⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 monitor.java

📁 纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统
💻 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 + -