diff options
Diffstat (limited to 'src/java/jogamp/common/util/locks/RecursiveLockImpl01Unfairish.java')
-rw-r--r-- | src/java/jogamp/common/util/locks/RecursiveLockImpl01Unfairish.java | 262 |
1 files changed, 140 insertions, 122 deletions
diff --git a/src/java/jogamp/common/util/locks/RecursiveLockImpl01Unfairish.java b/src/java/jogamp/common/util/locks/RecursiveLockImpl01Unfairish.java index ad29f78..23e2c90 100644 --- a/src/java/jogamp/common/util/locks/RecursiveLockImpl01Unfairish.java +++ b/src/java/jogamp/common/util/locks/RecursiveLockImpl01Unfairish.java @@ -26,35 +26,54 @@ * or implied, of JogAmp Community. */ -package com.jogamp.common.util.locks; +package jogamp.common.util.locks; -import jogamp.common.Debug; -import java.security.AccessController; +import java.util.List; +import java.util.concurrent.locks.AbstractOwnableSynchronizer; -import java.util.LinkedList; +import com.jogamp.common.util.locks.RecursiveLock; /** - * Reentrance locking toolkit, impl a complete fair FIFO scheduler + * Reentrance locking toolkit, impl a non-complete fair FIFO scheduler. + * <p> + * Fair scheduling is not guaranteed due to the usage of {@link Object#notify()}, + * however new lock-applicants will wait if queue is not empty for {@link #lock()} + * and {@link #tryLock(long) tryLock}(timeout>0).</p> + * + * <p> + * Sync object extends {@link AbstractOwnableSynchronizer}, hence monitoring is possible.</p> */ -public class RecursiveLock implements LockExt { +public class RecursiveLockImpl01Unfairish implements RecursiveLock { - static class SyncData { - // owner of the lock - Thread owner = null; - // lock recursion - int recursionCount = 0; + @SuppressWarnings("serial") + private static class Sync extends AbstractOwnableSynchronizer { + private Sync() { + super(); + } + private final Thread getOwner() { + return getExclusiveOwnerThread(); + } + private final void setOwner(Thread t) { + setExclusiveOwnerThread(t); + } + private final void setLockedStack(Throwable s) { + List<Throwable> ls = LockDebugUtil.getRecursiveLockTrace(); + if(s==null) { + ls.remove(lockedStack); + } else { + ls.add(s); + } + lockedStack = s; + } + // lock count by same thread + private int holdCount = 0; // stack trace of the lock, only used if DEBUG - Throwable lockedStack = null; - // waiting thread queue - LinkedList threadQueue = new LinkedList(); - // flag signaling unlock has woken up a waiting thread - boolean signaled = false; + private Throwable lockedStack = null; + private int qsz = 0; } - private final SyncData sdata = new SyncData(); // synchronized (flow/mem) mutable access - - private static final boolean TRACE_LOCK = Debug.isPropertyDefined("jogamp.debug.Lock.TraceLock", true, AccessController.getContext()); - - public RecursiveLock() { + private Sync sync = new Sync(); + + public RecursiveLockImpl01Unfairish() { } /** @@ -63,131 +82,127 @@ public class RecursiveLock implements LockExt { * @see com.jogamp.common.util.locks.Lock#DEBUG */ public final Throwable getLockedStack() { - synchronized(sdata) { - return sdata.lockedStack; + synchronized(sync) { + return sync.lockedStack; } } public final Thread getOwner() { - synchronized(sdata) { - return sdata.owner; + synchronized(sync) { + return sync.getOwner(); } } public final boolean isOwner() { - return isOwner(Thread.currentThread()); + synchronized(sync) { + return isOwner(Thread.currentThread()); + } } public final boolean isOwner(Thread thread) { - synchronized(sdata) { - return sdata.owner == thread ; + synchronized(sync) { + return sync.getOwner() == thread ; } } public final boolean isLocked() { - synchronized(sdata) { - return null != sdata.owner; + synchronized(sync) { + return null != sync.getOwner(); } } public final boolean isLockedByOtherThread() { - synchronized(sdata) { - return null != sdata.owner && Thread.currentThread() != sdata.owner ; + synchronized(sync) { + return null != sync.getOwner() && Thread.currentThread() != sync.getOwner() ; } } - public final int getRecursionCount() { - synchronized(sdata) { - return sdata.recursionCount; + public final int getHoldCount() { + synchronized(sync) { + return sync.holdCount; } } public final void validateLocked() { - synchronized(sdata) { - if ( null == sdata.owner ) { - throw new RuntimeException(Thread.currentThread()+": Not locked"); - } - if ( Thread.currentThread() != sdata.owner ) { - if(null!=sdata.lockedStack) { - sdata.lockedStack.printStackTrace(); + synchronized(sync) { + if ( Thread.currentThread() != sync.getOwner() ) { + if ( null == sync.getOwner() ) { + throw new RuntimeException(threadName(Thread.currentThread())+": Not locked: "+toString()); } - throw new RuntimeException(Thread.currentThread()+": Not owner, owner is "+sdata.owner); + if(null!=sync.lockedStack) { + sync.lockedStack.printStackTrace(); + } + throw new RuntimeException(Thread.currentThread()+": Not owner: "+toString()); } } } public final void lock() { - synchronized(sdata) { - if(!tryLock(TIMEOUT)) { - if(null!=sdata.lockedStack) { - sdata.lockedStack.printStackTrace(); + synchronized(sync) { + try { + if(!tryLock(TIMEOUT)) { + if(null!=sync.lockedStack) { + sync.lockedStack.printStackTrace(); + } + throw new RuntimeException("Waited "+TIMEOUT+"ms for: "+toString()+" - "+threadName(Thread.currentThread())); } - throw new RuntimeException("Waited "+TIMEOUT+"ms for: "+sdata.owner+" - "+Thread.currentThread()+", with recursionCount "+sdata.recursionCount+", lock: "+this+", qsz "+sdata.threadQueue.size()); + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted", e); } } } - public boolean tryLock(long maxwait) { - synchronized(sdata) { - Thread cur = Thread.currentThread(); + public final boolean tryLock(long timeout) throws InterruptedException { + synchronized(sync) { + final Thread cur = Thread.currentThread(); if(TRACE_LOCK) { - String msg = "LOCK 0 ["+this+"], recursions "+sdata.recursionCount+", cur "+cur+", owner "+sdata.owner; - System.err.println(msg); - //Throwable tt = new Throwable(msg); - //tt.printStackTrace(); + System.err.println("+++ LOCK 0 "+toString()+", cur "+threadName(cur)); } - if (sdata.owner == cur) { - ++sdata.recursionCount; + if (sync.getOwner() == cur) { + ++sync.holdCount; if(TRACE_LOCK) { - System.err.println("+++ LOCK 2 ["+this+"], recursions "+sdata.recursionCount+", "+cur); + System.err.println("+++ LOCK XR "+toString()+", cur "+threadName(cur)); } return true; } - - if ( sdata.owner != null || - 0 < maxwait && ( sdata.signaled || sdata.threadQueue.size() > 0 ) ) { - - if ( 0 >= maxwait ) { - // implies 'sdata.owner != null': locked by other thread - // no waiting requested, bail out right away + + if ( sync.getOwner() != null || ( 0<timeout && 0<sync.qsz ) ) { + + if ( 0 >= timeout ) { + // locked by other thread and no waiting requested return false; } - - boolean timedOut = false; + + ++sync.qsz; do { - sdata.threadQueue.addFirst(cur); // should only happen once - try { - sdata.wait(maxwait); - timedOut = sdata.threadQueue.remove(cur); // TIMEOUT if not already removed by unlock - } catch (InterruptedException e) { - if(!sdata.signaled) { - // theoretically we could stay in the loop, - // in case the interrupt wasn't issued by unlock, - // hence the re-enqueue - sdata.threadQueue.remove(cur); - if(TRACE_LOCK) { - System.err.println("XXX LOCK - ["+this+"], recursions "+sdata.recursionCount+", "+cur); - } - } + final long t0 = System.currentTimeMillis(); + sync.wait(timeout); + timeout -= System.currentTimeMillis() - t0; + } while (null != sync.getOwner() && 0 < timeout) ; + --sync.qsz; + + if( 0 >= timeout ) { + // timed out + if(TRACE_LOCK || DEBUG) { + System.err.println("+++ LOCK XX "+toString()+", cur "+threadName(cur)+", left "+timeout+" ms"); } - } while (null != sdata.owner && !timedOut) ; - - sdata.signaled = false; - - if(timedOut || null != sdata.owner) { return false; } - + + ++sync.holdCount; + if(TRACE_LOCK) { + System.err.println("+++ LOCK X1 "+toString()+", cur "+threadName(cur)+", left "+timeout+" ms"); + } + } else { + ++sync.holdCount; if(TRACE_LOCK) { - System.err.println("+++ LOCK 3 ["+this+"], recursions "+sdata.recursionCount+", qsz "+sdata.threadQueue.size()+", "+cur); + System.err.println("+++ LOCK X0 "+toString()+", cur "+threadName(cur)); } - } else if(TRACE_LOCK) { - System.err.println("+++ LOCK 1 ["+this+"], recursions "+sdata.recursionCount+", qsz "+sdata.threadQueue.size()+", "+cur); } - - sdata.owner = cur; + + sync.setOwner(cur); if(DEBUG) { - sdata.lockedStack = new Throwable("Previously locked by "+sdata.owner+", lock: "+this); + sync.setLockedStack(new Throwable("Previously locked by "+toString())); } return true; } @@ -195,51 +210,54 @@ public class RecursiveLock implements LockExt { public final void unlock() { - unlock(null); + synchronized(sync) { + unlock(null); + } } public final void unlock(Runnable taskAfterUnlockBeforeNotify) { - synchronized(sdata) { + synchronized(sync) { validateLocked(); - - if (sdata.recursionCount > 0) { - --sdata.recursionCount; + final Thread cur = Thread.currentThread(); + + --sync.holdCount; + + if (sync.holdCount > 0) { if(TRACE_LOCK) { - System.err.println("--- LOCK 1 ["+this+"], recursions "+sdata.recursionCount+", "+Thread.currentThread()); + System.err.println("--- LOCK XR "+toString()+", cur "+threadName(cur)); } return; } - sdata.owner = null; - sdata.lockedStack = null; + + sync.setOwner(null); + if(DEBUG) { + sync.setLockedStack(null); + } if(null!=taskAfterUnlockBeforeNotify) { taskAfterUnlockBeforeNotify.run(); } - - int qsz = sdata.threadQueue.size(); - if(qsz > 0) { - Thread parkedThread = (Thread) sdata.threadQueue.removeLast(); - if(TRACE_LOCK) { - System.err.println("--- LOCK X ["+this+"], recursions "+sdata.recursionCount+ - ", "+Thread.currentThread()+", irq "+(qsz-1)+": "+parkedThread); - } - sdata.signaled = true; - if(qsz==1) { - // fast path, just one waiting thread - sdata.notify(); - } else { - // signal the oldest one .. - parkedThread.interrupt(); // Propagate SecurityException if it happens - } - } else if(TRACE_LOCK) { - System.err.println("--- LOCK X ["+this+"], recursions "+sdata.recursionCount+", "+Thread.currentThread()); + + if(TRACE_LOCK) { + System.err.println("--- LOCK X0 "+toString()+", cur "+threadName(cur)+", signal any"); } + sync.notify(); } } - public int getWaitingThreadQueueSize() { - synchronized(sdata) { - return sdata.threadQueue.size(); + public final int getQueueLength() { + synchronized(sync) { + return sync.qsz; } } + + public String toString() { + return syncName()+"[count "+sync.holdCount+ + ", qsz "+sync.qsz+", owner "+threadName(sync.getOwner())+"]"; + } + + private final String syncName() { + return "<"+Integer.toHexString(this.hashCode())+", "+Integer.toHexString(sync.hashCode())+">"; + } + private final String threadName(Thread t) { return null!=t ? "<"+t.getName()+">" : "<NULL>" ; } } |