/* * Copyright (C) 2012, 2016 higherfrequencytrading.com * Copyright (C) 2016 Roman Leventov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.chronicle.hash.impl.stage.entry; import net.openhft.chronicle.hash.impl.stage.hash.CheckOnEachPublicOperation; import net.openhft.chronicle.hash.locks.InterProcessDeadLockException; import net.openhft.chronicle.hash.locks.InterProcessLock; import net.openhft.sg.StageRef; import net.openhft.sg.Staged; import org.jetbrains.annotations.NotNull; import java.util.concurrent.TimeUnit; import static net.openhft.chronicle.hash.impl.LocalLockState.READ_LOCKED; import static net.openhft.chronicle.hash.impl.LocalLockState.UNLOCKED; @Staged public class ReadLock implements InterProcessLock { @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; @StageRef SegmentStages s; @StageRef HashEntryStages entry; @StageRef HashLookupPos hlp; @Override public boolean isHeldByCurrentThread() { checkOnEachPublicOperation.checkOnEachLockOperation(); return s.localLockState.read; } @Override public void lock() { checkOnEachPublicOperation.checkOnEachLockOperation(); if (s.localLockState == UNLOCKED) { if (s.readZero() && s.updateZero() && s.writeZero()) { try { s.segmentHeader.readLock(s.segmentHeaderAddress); } catch (InterProcessDeadLockException e) { throw s.debugContextsAndLocks(e); } } s.incrementRead(); s.setLocalLockState(READ_LOCKED); } } @Override public void lockInterruptibly() throws InterruptedException { checkOnEachPublicOperation.checkOnEachLockOperation(); if (Thread.interrupted()) throw new InterruptedException(); if (s.localLockState == UNLOCKED) { if (s.readZero() && s.updateZero() && s.writeZero()) { try { s.segmentHeader.readLockInterruptibly(s.segmentHeaderAddress); } catch (InterProcessDeadLockException e) { throw s.debugContextsAndLocks(e); } } s.incrementRead(); s.setLocalLockState(READ_LOCKED); } } @Override public boolean tryLock() { checkOnEachPublicOperation.checkOnEachLockOperation(); if (s.localLockState == UNLOCKED) { if (!s.readZero() || !s.updateZero() || !s.writeZero() || s.segmentHeader.tryReadLock(s.segmentHeaderAddress)) { s.incrementRead(); s.setLocalLockState(READ_LOCKED); return true; } else { return false; } } else { return true; } } @Override public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException { checkOnEachPublicOperation.checkOnEachLockOperation(); if (Thread.interrupted()) throw new InterruptedException(); if (s.localLockState == UNLOCKED) { if (!s.readZero() || !s.updateZero() || !s.writeZero() || s.segmentHeader.tryReadLock(s.segmentHeaderAddress, time, unit)) { s.incrementRead(); s.setLocalLockState(READ_LOCKED); return true; } else { return false; } } else { return true; } } @Override public void unlock() { checkOnEachPublicOperation.checkOnEachLockOperation(); if (s.localLockState != UNLOCKED) { // TODO what should close here? hlp.closeHashLookupPos(); entry.closeEntry(); } s.readUnlockAndDecrementCount(); s.setLocalLockState(UNLOCKED); } }