27package jau.test.util.parallel.locks.impl;
29import java.util.ArrayList;
31import java.util.concurrent.locks.AbstractOwnableSynchronizer;
33import org.jau.lang.SourcedInterruptedException;
35import jau.test.util.parallel.locks.RecursiveLock;
45 private static class WaitingThread {
46 WaitingThread(
final Thread t) {
48 signaledByUnlock =
false;
51 boolean signaledByUnlock;
54 @SuppressWarnings(
"serial")
55 private static class Sync
extends AbstractOwnableSynchronizer {
60 return getExclusiveOwnerThread();
62 private final void setOwner(
final Thread t) {
63 setExclusiveOwnerThread(t);
65 private final void setLockedStack(
final Throwable s) {
68 ls.remove(lockedStack);
75 private int holdCount = 0;
77 final ArrayList<WaitingThread> queue =
new ArrayList<WaitingThread>();
79 private Throwable lockedStack =
null;
81 private final Sync sync =
new Sync();
93 return sync.lockedStack;
100 return sync.getOwner();
105 public final boolean isOwner(
final Thread thread) {
107 return sync.getOwner() == thread ;
114 return null != sync.getOwner();
121 final Thread o = sync.getOwner();
122 return null != o && Thread.currentThread() != o ;
129 return sync.holdCount;
136 if ( Thread.currentThread() != sync.getOwner() ) {
137 if (
null == sync.getOwner() ) {
138 throw new RuntimeException(threadName(Thread.currentThread())+
": Not locked: "+
toString());
140 if(
null!=sync.lockedStack) {
141 sync.lockedStack.printStackTrace();
143 throw new RuntimeException(Thread.currentThread()+
": Not owner: "+
toString());
153 if(
null!=sync.lockedStack) {
154 sync.lockedStack.printStackTrace();
156 throw new RuntimeException(
"Waited "+
TIMEOUT+
"ms for: "+
toString()+
" - "+threadName(Thread.currentThread()));
158 }
catch (
final InterruptedException e) {
159 throw new RuntimeException(
"Interrupted", e);
165 public final boolean tryLock(
long timeout)
throws InterruptedException {
167 final Thread cur = Thread.currentThread();
169 System.err.println(
"+++ LOCK 0 "+
toString()+
", cur "+threadName(cur));
171 if (sync.getOwner() == cur) {
174 System.err.println(
"+++ LOCK XR "+
toString()+
", cur "+threadName(cur));
179 if ( sync.getOwner() !=
null || ( 0<timeout && 0<sync.queue.size() ) ) {
181 if ( 0 >= timeout ) {
184 System.err.println(
"+++ LOCK XY "+
toString()+
", cur "+threadName(cur)+
", left "+timeout+
" ms");
190 final WaitingThread wCur =
new WaitingThread(cur);
191 sync.queue.add(0, wCur);
193 final long t0 = System.currentTimeMillis();
196 timeout -= System.currentTimeMillis() - t0;
197 }
catch (
final InterruptedException e) {
198 if( !wCur.signaledByUnlock ) {
199 sync.queue.remove(wCur);
200 throw SourcedInterruptedException.wrap(e);
201 }
else if( cur != sync.getOwner() ) {
204 timeout -= System.currentTimeMillis() - t0;
207 System.err.println(
"+++ LOCK 1 "+
toString()+
", cur "+threadName(cur)+
", left "+timeout+
" ms, signaled: "+wCur.signaledByUnlock);
212 wCur.signaledByUnlock =
false;
213 sync.queue.add(sync.queue.size(), wCur);
217 }
while ( cur != sync.getOwner() && 0 < timeout ) ;
218 Thread.interrupted();
220 if( 0 >= timeout && cur != sync.getOwner() ) {
222 if(!wCur.signaledByUnlock) {
223 sync.queue.remove(wCur);
226 System.err.println(
"+++ LOCK XX "+
toString()+
", cur "+threadName(cur)+
", left "+timeout+
" ms");
233 System.err.println(
"+++ LOCK X1 "+
toString()+
", cur "+threadName(cur)+
", left "+timeout+
" ms");
238 System.err.println(
"+++ LOCK X0 "+
toString()+
", cur "+threadName(cur));
244 sync.setLockedStack(
new Throwable(
"Previously locked by "+
toString()));
259 public final void unlock(
final Runnable taskAfterUnlockBeforeNotify) {
262 final Thread cur = Thread.currentThread();
266 if (sync.holdCount > 0) {
268 System.err.println(
"--- LOCK XR "+
toString()+
", cur "+threadName(cur));
274 sync.setLockedStack(
null);
276 if(
null!=taskAfterUnlockBeforeNotify) {
277 taskAfterUnlockBeforeNotify.run();
280 if(sync.queue.size() > 0) {
283 final WaitingThread oldest = sync.queue.remove(sync.queue.size()-1);
284 sync.setOwner(oldest.thread);
287 System.err.println(
"--- LOCK X1 "+
toString()+
", cur "+threadName(cur)+
", signal: "+threadName(oldest.thread));
290 oldest.signaledByUnlock =
true;
291 oldest.thread.interrupt();
295 System.err.println(
"--- LOCK X0 "+
toString()+
", cur "+threadName(cur)+
", signal any");
305 return sync.queue.size();
311 return syncName()+
"[count "+sync.holdCount+
312 ", qsz "+sync.queue.size()+
", owner "+threadName(sync.getOwner())+
"]";
315 private final String syncName() {
316 return "<"+Integer.toHexString(this.hashCode())+
", "+Integer.toHexString(sync.hashCode())+
">";
318 private final String threadName(
final Thread t) {
return null!=t ?
"<"+t.getName()+
">" :
"<NULL>" ; }
Functionality enabled if Lock#DEBUG is true.
static List< Throwable > getRecursiveLockTrace()
Reentrance locking toolkit, impl a complete fair FIFO scheduler.
final boolean isLockedByOtherThread()
Query whether the lock is hold by the a thread other than the current thread.
final void lock()
Blocking until the lock is acquired by this Thread or TIMEOUT is reached.
final int getHoldCount()
Return the number of locks issued to this lock by the same thread.
final void unlock()
Release the lock.
final void unlock(final Runnable taskAfterUnlockBeforeNotify)
Execute the Runnable taskAfterUnlockBeforeNotify while holding the exclusive lock.
final boolean isLocked()
Query if locked.
final Throwable getLockedStack()
Returns the Throwable instance generated when this lock was taken the 1st time and if jau....
final int getQueueLength()
final void validateLocked()
final boolean tryLock(long timeout)
Blocking until the lock is acquired by this Thread or maxwait in ms is reached.
final boolean isOwner(final Thread thread)
Query whether the lock is hold by the given thread.
RecursiveLockImpl01CompleteFair()
static final long TIMEOUT
The TIMEOUT for lock() in ms, defaults to DEFAULT_TIMEOUT.
static final boolean DEBUG
Enable via the property jogamp.debug.Lock
static final boolean TRACE_LOCK
Enable via the property jogamp.debug.Lock.TraceLock
Reentrance capable locking toolkit.