📄 monitor.java
字号:
/*
* $Id: Monitor.java,v 1.6 2004/02/02 18:42:10 epr Exp $
*/
package org.jnode.vm;
/**
* @author epr
*/
public final class Monitor implements Uninterruptible {
/** Number of locks on this monitor THIS FIELD MUST BE THE FIRST!! */
private int lockCount;
/** Lock counter of the monitor itself. THIS FIELD MUST BE THE SECOND!! */
private int monitorLock;
/** Thread that owns the monitor */
private VmThread owner;
/** Thread queue for monitorenter/exit */
private VmThreadQueue enterQueue;
/** Thread queue for wait/notify/notifyAll */
private VmThreadQueue notifyQueue;
/**
* Create a new instance
*/
public Monitor() {
this.lockCount = 0;
this.monitorLock = 0;
this.owner = null;
this.enterQueue = new VmThreadQueue("mon-enter", false);
this.notifyQueue = new VmThreadQueue("mon-notify", false);
}
/**
* Create a new instance that has already been locked.
*
* @param owner
* @param lockCount
*/
Monitor(VmThread owner, int lockCount) {
this.monitorLock = 0;
this.owner = owner;
this.lockCount = lockCount;
if (lockCount < 1) {
throw new IllegalArgumentException("LockCount must be >= 1");
}
this.enterQueue = null;
this.notifyQueue = null;
}
/**
* Enter the given monitor. This method will block until the monitor is locked by the current
* thread.
* @throws PragmaUninterruptible
*/
public final void enter() throws PragmaUninterruptible {
final VmProcessor proc = Unsafe.getCurrentProcessor();
final VmThread current = proc.getCurrentThread();
// Am I already owner of this lock?
if (this.owner == current) {
// Yes, already owner, just increment lock counter
lockCount++;
} else {
// No yet owner, try to obtain the lock
boolean loop = true;
final Address lcAddr = getLCAddress();
while (loop) {
// Try to claim this monitor
if (Unsafe.atomicCompareAndSwap(lcAddr, 0, 1)) {
loop = false;
owner = current;
} else {
// Claim the lock for this monitor
lock();
try {
enterQueue = prepareWait(current, enterQueue, "mon-enter");
proc.disableReschedule();
} finally {
unlock();
}
// Release the monitor lock
proc.suspend();
// When we return here, another thread has given up
// this monitor.
}
}
}
}
/**
* Giveup this monitor.
* @throws PragmaUninterruptible
*/
public final void exit() throws PragmaUninterruptible {
final VmProcessor proc = Unsafe.getCurrentProcessor();
final VmThread current = proc.getCurrentThread();
String exMsg = null;
if (owner != current) {
exMsg = "Current thread is not the owner of this monitor";
} else if (lockCount <= 0) {
lockCount = 0;
exMsg = "Monitor is not locked";
} else if (lockCount > 1) {
// Monitor is locked by current thread, decrement lockcount
lockCount--;
} else {
// Monitor is locked by current thread and will decrement to 0.
lock();
try {
wakeupWaitingThreads(enterQueue, true);
owner = null;
lockCount = 0;
} finally {
unlock();
}
}
if (exMsg != null) {
throw new IllegalMonitorStateException(exMsg);
}
}
/**
* Causes current thread to wait until another thread invokes the notify() method or the
* notifyAll() method for this monitor. In other words, this method behaves exactly as if it
* simply performs the call wait(0). The current thread must own this monitor. The thread
* releases ownership of this monitor and waits until another thread notifies threads waiting
* on this object's monitor to wake up either through a call to the notify method or the
* notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and
* resumes execution. This method should only be called by a thread that is the owner of this
* monitor. See the notify method for a description of the ways in which a thread can become
* the owner of a monitor.
*
* @param timeout
* @throws PragmaUninterruptible
* @throws InterruptedException
*/
public final void Wait(long timeout) throws PragmaUninterruptible, InterruptedException {
final VmProcessor proc = Unsafe.getCurrentProcessor();
final VmThread current = proc.getCurrentThread();
//final int id = current.getId();
String exMsg = null;
if (owner != current) {
exMsg = "Current thread is not the owner of this monitor";
} else if (lockCount == 0) {
exMsg = "Monitor is not locked";
} else {
final int oldLockCount = lockCount;
lock();
try {
notifyQueue = prepareWait(current, notifyQueue, "mon-notify");
proc.disableReschedule();
} finally {
unlock();
}
// If there is a timeout, also add the current thread to the
// sleep queue.
if (timeout > 0) {
current.wakeupTime = VmSystem.currentKernelMillis() + timeout;
proc.addToSleepQueue(current);
}
owner = null;
lockCount = 0;
proc.suspend();
// When we return here, we have been notified or there
// was a timeout.
if (!current.isRunning()) {
Unsafe.debug("Back from wait, but state != running");
Unsafe.debug("state=");
Unsafe.debug(current.getThreadState());
Unsafe.die("Wait");
}
if (timeout > 0) {
//Screen.debug("<backfromwait-"); Screen.debug(id); Screen.debug("/>");
// Remove the current thread from the notifyQueue.
// There is no need to remove myself from the sleep queue,
// because this is done either by the scheduler or
// indirect by wakeupWaitingThreads.
lock();
try {
notifyQueue.remove(current);
} finally {
unlock();
}
}
enter();
this.lockCount = oldLockCount;
}
if (exMsg != null) {
throw new IllegalMonitorStateException(exMsg);
}
// Check for InterruptedException
current.testAndClearInterruptStatus();
}
/**
* Notify threads waiting on this monitor.
* @throws PragmaUninterruptible
*/
public final void NotifyAll() throws PragmaUninterruptible {
Notify(true);
}
/**
* Notify the first or all waiting threads on this monitor.
*
* @param all
* @throws PragmaUninterruptible
*/
final void Notify(boolean all) throws PragmaUninterruptible {
final VmProcessor proc = Unsafe.getCurrentProcessor();
final VmThread current = proc.getCurrentThread();
String exMsg = null;
if (owner != current) {
exMsg = "Current thread is not the owner of this monitor";
} else if (lockCount == 0) {
exMsg = "Monitor is not locked";
} else {
lock();
try {
wakeupWaitingThreads(notifyQueue, all);
} finally {
unlock();
}
}
if (exMsg != null) {
throw new IllegalMonitorStateException(exMsg);
}
}
/**
* Is the given thread owner of this monitor?
*
* @param thread
* @return boolean
* @throws PragmaUninterruptible
*/
final boolean isOwner(VmThread thread) throws PragmaUninterruptible {
return (owner == thread);
}
/**
* Is this monitor locked?
*
* @return boolean
* @throws PragmaUninterruptible
*/
final boolean isLocked() throws PragmaUninterruptible {
return (lockCount > 0);
}
/**
* Prepare the given thread for a waiting state.
*
* @param thread
* @param queue
* @param queueName
* @return The queue
* @throws PragmaUninterruptible
*/
private final VmThreadQueue prepareWait(VmThread thread, VmThreadQueue queue, String queueName) throws PragmaUninterruptible {
if (monitorLock != 1) {
Unsafe.debug("MonitorLock not claimed");
Unsafe.die("prepareWait");
}
if (queue == null) {
queue = new VmThreadQueue(queueName, false);
}
thread.prepareWait(this);
queue.add(thread, false, "mon.prepareWait");
return queue;
}
/**
* Notify a single thread. The thread is remove from the notifyQueue and its <code>wakeupAfterMonitor</code>
* method is called.
*
* @param thread
* @throws PragmaUninterruptible
*/
private final void notifyThread(VmThread thread) throws PragmaUninterruptible {
final VmThreadQueue eq = this.enterQueue;
if (eq != null) {
eq.remove(thread);
}
final VmThreadQueue nq = this.notifyQueue;
if (nq != null) {
nq.remove(thread);
}
thread.wakeupAfterMonitor(this);
}
/**
* The given thread is removed from the notifyQueue.
*
* @param thread
* @throws PragmaUninterruptible
*/
final void removeThreadFromQueues(VmThread thread) throws PragmaUninterruptible {
final VmThreadQueue eq = this.enterQueue;
if (eq != null) {
eq.remove(thread);
}
final VmThreadQueue nq = this.notifyQueue;
if (nq != null) {
nq.remove(thread);
}
}
/**
* Wakeup all waiting threads.
* @param queue
* @param all
* @throws PragmaUninterruptible
*/
private final void wakeupWaitingThreads(VmThreadQueue queue, boolean all) throws PragmaUninterruptible {
if (queue != null) {
while (!queue.isEmpty()) {
final VmThread thread = queue.first();
notifyThread(thread);
if (!all) {
break;
}
}
}
}
/**
* Gets the address of the lockCount variable. It is assumed that this variable is at offset 0
* within this object!
* @return The address of lockCount
*/
private final Address getLCAddress() {
return Unsafe.addressOf(this);
}
/**
* Claim access to this monitor. A monitor may only be locked for a small amount of time, since
* this method uses a spinlock.
*
* @see #unlock()
* @see #monitorLock
*/
private final void lock() {
final VmProcessor proc = Unsafe.getCurrentProcessor();
final Address mlAddr = Unsafe.add(Unsafe.addressOf(this), 4);
while (!Unsafe.atomicCompareAndSwap(mlAddr, 0, 1)) {
proc.yield(true);
}
}
/**
* Release access to this monitor. A monitor may only be locked for a small amount of time,
* since this method uses a spinlock.
*
* @see #lock()
* @see #monitorLock
*/
private final void unlock() {
monitorLock = 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -