package org.rosuda.JRI;
/** This class implements a (not so) simple mutex. The initial state of the mutex is unlocked. */
public class Mutex {
public static boolean verbose=false;
/** defines the current mutex state */
private boolean locked=false;
/** thread that locked this mutex (used for simple deadlock-detection) */
private Thread lockedBy=null;
/** locks the mutex. If the mutex is already locked, waits until the mutex becomes free. Make sure the same thread doesn't issue two locks, because that will cause a deadlock. Use {@link #safeLock()} instead if you wish to detect such deadlocks. */
public synchronized void lock()
{
while (locked) {
if (lockedBy==Thread.currentThread())
System.err.println("FATAL ERROR: org.rosuda.JRI.Mutex detected a deadlock! The application is likely to hang indefinitely!");
if (verbose)
System.out.println("INFO: "+toString()+" is locked by "+lockedBy+", but "+Thread.currentThread()+" waits for release (no timeout)");
try {
wait();
} catch (InterruptedException e) {
if (verbose)
System.out.println("INFO: "+toString()+" caught InterruptedException");
}
}
locked=true;
lockedBy=Thread.currentThread();
if (verbose) System.out.println("INFO: "+toString()+" locked by "+lockedBy);
}
/** locks the mutex. If the mutex is already locked, waits until the mutex becomes free. Make sure the same thread doesn't issue two locks, because that will cause a deadlock.
@param to timeout in milliseconds, see {@link #wait()}.
@return true
if the lock was successful, false
if not
*/
public synchronized boolean lockWithTimeout(long to)
{
if (locked) {
if (lockedBy==Thread.currentThread())
System.err.println("FATAL ERROR: org.rosuda.JRI.Mutex detected a deadlock! The application is likely to hang indefinitely!");
if (verbose)
System.out.println("INFO: "+toString()+" is locked by "+lockedBy+", but "+Thread.currentThread()+" waits for release (timeout "+to+" ms)");
try {
wait(to);
} catch (InterruptedException e) {
if (verbose)
System.out.println("INFO: "+toString()+" caught InterruptedException");
}
}
if (!locked) {
locked=true;
lockedBy=Thread.currentThread();
if (verbose) System.out.println("INFO: "+toString()+" locked by "+lockedBy);
return true;
}
if (verbose) System.out.println("INFO: "+toString()+" timeout, failed to obtain lock for "+Thread.currentThread());
return false;
}
/** attempts to lock the mutex and returns information about its success.
@return 0 if the mutex was locked sucessfully
1 if the mutex is already locked by another thread
-1 is the mutex is already locked by the same thread (hence a call to {@link #lock()} would cause a deadlock). */
public synchronized int tryLock()
{
if (verbose) System.out.println("INFO: "+toString()+" tryLock by "+Thread.currentThread());
if (locked) return (lockedBy==Thread.currentThread())?-1:1;
locked=true;
lockedBy=Thread.currentThread();
if (verbose) System.out.println("INFO: "+toString()+" locked by "+lockedBy);
return 0;
}
/** Locks the mutex. It works like {@link #lock()} except that it returns immediately if the same thread already owns the lock. It is safer to use this function rather than {@link #lock()}, because lock can possibly cause a deadlock which won't be resolved.
@return true
is the mutex was successfully locked, false
if deadlock was detected (i.e. the same thread has already the lock). */
public synchronized boolean safeLock()
{
if (locked && lockedBy==Thread.currentThread()) {
if (verbose) System.out.println("INFO: "+toString()+" unable to provide safe lock for "+Thread.currentThread());
return false;
}
lock();
return true;
}
/** Locks the mutex. It works like {@link #lockWithTimeout(long)} except that it returns immediately if the same thread already owns the lock. It is safer to use this function rather than {@link #lockWithTimeout(long)}, because lock can possibly cause a deadlock which won't be resolved.
@return true
is the mutex was successfully locked, false
if deadlock was detected or timeout elapsed. */
public synchronized boolean safeLockWithTimeout(long to)
{
if (locked && lockedBy==Thread.currentThread()) {
if (verbose) System.out.println("INFO: "+toString()+" unable to provide safe lock (deadlock detected) for "+Thread.currentThread());
return false;
}
return lockWithTimeout(to);
}
/** unlocks the mutex. It is possible to unlock an unlocked mutex, but a warning may be issued. */
public synchronized void unlock()
{
if (locked && lockedBy!=Thread.currentThread())
System.err.println("WARNING: org.rosuda.JRI.Mutex was unlocked by other thread than locked! This may soon lead to a crash...");
locked=false;
if (verbose) System.out.println("INFO: "+toString()+" unlocked by "+Thread.currentThread());
// notify just 1 in case more of them are waiting
notify();
}
public String toString()
{
return super.toString()+"["+((locked)?"":"un")+"locked"+((!locked)?"":(", by "+((lockedBy==Thread.currentThread())?"current":"another")+" thread"))+"]";
}
}