monitormanager.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 268 行

JAVA
268
字号
/*
 * $Id: MonitorManager.java,v 1.2 2003/12/14 16:47:28 epr Exp $
 */
package org.jnode.vm;

import org.jnode.util.NumberUtils;
import org.jnode.vm.classmgr.ObjectFlags;
import org.jnode.vm.classmgr.ObjectLayout;

/**
 * @author epr
 */
public class MonitorManager {
	
	/**
	 * A fast implementation of the monitorEnter opcode.
	 * This implementation is based on a thin-lock, present
	 * if the status word of the header of each object.
	 * @param object
	 */
	public static void monitorEnter(Object object) {
		if (object == null) {
			throw new NullPointerException();
		}

		final VmProcessor proc = Unsafe.getCurrentProcessor();
		final VmThread t = proc.getCurrentThread();
		final int slotSize = proc.getArchitecture().getReferenceSize();
		final int tid = t.getId();
		
		if (((tid & ~ObjectFlags.THREAD_ID_MASK) != 0) || (tid == 0)) {
			throw new VirtualMachineError("Invalid thread id " + tid);
		}
		
		// attempt fast path: object is not locked.
		final Address status_address = Unsafe.add(Unsafe.addressOf(object), ObjectLayout.FLAGS_SLOT * slotSize);
		final int oldlockword = Unsafe.getInt(status_address);
		final int status_flags = oldlockword & ObjectFlags.STATUS_FLAGS_MASK;
		int newlockword = status_flags | tid;
		if (Unsafe.atomicCompareAndSwap(status_address, status_flags, newlockword)) {			
			// fast path succeeded, the object was not locked and 
			// has been locked by the current thread.
			return;
		}

		// object is locked or has an inflated lock.
		// if tid's are equal, this extracts the counter.
		final int counter = oldlockword ^ newlockword; 
		if ((oldlockword & ObjectFlags.LOCK_EXPANDED) != 0) {
			// slow path 2: high bit of lock word is set --> inflated lock
			final Monitor m = getMonitor(oldlockword);
			m.enter();
		} else if (counter >= ObjectFlags.LOCK_COUNT_MASK) {
			// slow path: other thread owns thin lock, or entry counter == max
			if (counter == ObjectFlags.LOCK_COUNT_MASK) {
				// thin lock entry counter == max, so we need to inflate ourselves.
				final int entrycount = (ObjectFlags.LOCK_COUNT_MASK >> ObjectFlags.LOCK_COUNT_SHIFT)+1;
				//Screen.debug("entrycount=" + entrycount);
				//Unsafe.die();
				final Monitor m = new Monitor(t, entrycount+1);
				newlockword = Unsafe.addressToInt(Unsafe.addressOf(m)) | ObjectFlags.LOCK_EXPANDED | status_flags;
				// we own the lock, so a simple write is sufficient.
				Unsafe.setInt(status_address, newlockword);
			} else {
				// thin lock owned by another thread.
				final Monitor m = new Monitor(t, 1);
				// install an inflated lock.
				installInflatedLock(object, m, slotSize);
			}
		} else {
			// not-quite-so-fast path: locked by current thread.  increment counter.
			// we own the lock, so a simple write is sufficient.
			Unsafe.setInt(status_address, oldlockword+ObjectFlags.LOCK_COUNT_INC);
		}
	}
	
	/** Monitorexit runtime routine.
	 *  Checks for thin lock usage, otherwise falls back to inflated locks.
	 * @param object
	 */
	public static void monitorExit(Object object) {
		if (object == null) {
			throw new NullPointerException();
		}

		final VmProcessor proc = Unsafe.getCurrentProcessor();
		final VmThread t = proc.getCurrentThread();
		final int slotSize = proc.getArchitecture().getReferenceSize();
		final int tid = t.getId();

		if ((tid & ~ObjectFlags.THREAD_ID_MASK) != 0) {
			throw new VirtualMachineError("Invalid thread id " + tid);
		}

		final Address status_address = Unsafe.add(Unsafe.addressOf(object), ObjectLayout.FLAGS_SLOT * slotSize);
		final int oldlockword = Unsafe.getInt(status_address);
		// if not inflated and tid matches, this contains status flags and counter
		final int counter = oldlockword ^ tid;
		if ((oldlockword & ObjectFlags.LOCK_EXPANDED) != 0) {
			// inflated lock
			final Monitor m = getMonitor(oldlockword);
			m.exit();
		} else if (counter <= ObjectFlags.STATUS_FLAGS_MASK) {
			// owned by us and count is zero.  clear tid field.
			Unsafe.atomicAnd(status_address, ObjectFlags.STATUS_FLAGS_MASK);
		} else if (counter <= (ObjectFlags.LOCK_COUNT_MASK | ObjectFlags.STATUS_FLAGS_MASK)) {
			// owned by us but count is non-zero.  decrement count.
			Unsafe.atomicSub(status_address, ObjectFlags.LOCK_COUNT_INC);
		} else {
			// lock not owned by us!
			throw new IllegalMonitorStateException();
		}
	}
    
	public static void wait(Object object, long timeout)
	throws InterruptedException {
		getOwnedInflatedMonitor(object).Wait(timeout);
	}

	public static void notify(Object object) {
		getOwnedInflatedMonitor(object).Notify(false);
	}

	public static void notifyAll(Object object) {
		getOwnedInflatedMonitor(object).Notify(true);
	}

	/**
	 * Initialize this manager
	 */
	protected static void initialize() {
	}

	/**
	 * Gets the inflated monitor of the given object.
	 * The object must have been locked by the current thread,
	 * otherwise an IllegalMonitorStateException is thrown.
	 * @param object
	 * @return The monitor
	 * @throw IllegalMonitorStateException
	 * @throws IllegalMonitorStateException
	 */
	private static Monitor getOwnedInflatedMonitor(Object object) 
	throws IllegalMonitorStateException {
		final VmProcessor proc = Unsafe.getCurrentProcessor();
		final VmArchitecture arch = proc.getArchitecture();
		final VmThread t = proc.getCurrentThread();
		final int tid = t.getId();

		if ((tid & ~ObjectFlags.THREAD_ID_MASK) != 0) {
			throw new VirtualMachineError("Invalid thread id " + tid);
		}

		final int slotSize = arch.getReferenceSize();
		final Address status_address = Unsafe.add(Unsafe.addressOf(object), ObjectLayout.FLAGS_SLOT * slotSize);
		final int oldlockword = Unsafe.getInt(status_address);
		// if not inflated and tid matches, this contains status flags and counter
		final int counter = oldlockword ^ tid;
		if (counter < 0) {
			// inflated lock
			return getMonitor(oldlockword);
		} else if (counter <= (ObjectFlags.LOCK_COUNT_MASK | ObjectFlags.STATUS_FLAGS_MASK)) {
			// owned by us, not inflated
			final int status_flags = oldlockword & ObjectFlags.STATUS_FLAGS_MASK;
			final int entrycount = ((oldlockword & ObjectFlags.LOCK_COUNT_MASK) >> ObjectFlags.LOCK_COUNT_SHIFT);
			final Monitor m = new Monitor(t, entrycount+1);
			final Address monAddr = Unsafe.addressOf(m);
			final int monAddr32 = Unsafe.addressToInt(monAddr);
			if ((monAddr32 & (ObjectFlags.STATUS_FLAGS_MASK | ObjectFlags.LOCK_EXPANDED)) != 0) {
				throw new VirtualMachineError("Monitor object has address that conflicts with header flags 0x" + NumberUtils.hex(monAddr32));
			}

			final int newlockword = monAddr32 | ObjectFlags.LOCK_EXPANDED | status_flags;
			// we own the lock, so a simple write is sufficient.
			//Assert._assert(HeapAddress.addressOf(k).offset(ObjectLayout.STATUS_WORD_OFFSET).peek4() == oldlockword);
			Unsafe.setInt(status_address, newlockword);
			return m;
		} else {
			// lock not owned by us!
			throw new IllegalMonitorStateException("Object not locked by current thread");
		}
	}

	/**
	 * Make sure that object K has an inflated monitor.
	 * 
	 * @param k
	 */
	final static void setupInflatedLock(Object k) {
		final VmProcessor proc = Unsafe.getCurrentProcessor();
		final Monitor m = new Monitor(proc.getCurrentThread(), 1);
		installInflatedLock(k, m, proc.getArchitecture().getReferenceSize());
		m.exit();
	}
	
	/** 
	 * Installs an inflated lock on the given object.
	 * Uses a spin-loop to wait until the object is unlocked or inflated.
	 * @param k
	 * @param m
	 * @param slotSize
	 */
	private static void installInflatedLock(Object k, Monitor m, int slotSize) {
		final Address monAddr = Unsafe.addressOf(m);
		final int monAddr32 = Unsafe.addressToInt(monAddr);
		if ((monAddr32 & (ObjectFlags.STATUS_FLAGS_MASK | ObjectFlags.LOCK_EXPANDED)) != 0) {
			throw new VirtualMachineError("Monitor object has address that conflicts with header flags 0x" + NumberUtils.hex(monAddr32));
		}
		final Address status_address = Unsafe.add(Unsafe.addressOf(k), ObjectLayout.FLAGS_SLOT * slotSize);
		
		for (;;) {
			final int oldlockword = Unsafe.getInt(status_address);
			if ((oldlockword & ObjectFlags.LOCK_EXPANDED) != 0) {
				// inflated by another thread, use that one.
				final Monitor m2 = getMonitor(oldlockword);
				m2.enter();
				return;
			} 
			final int status_flags = oldlockword & ObjectFlags.STATUS_FLAGS_MASK;
			final int newlockword = monAddr32 | ObjectFlags.LOCK_EXPANDED | status_flags;
			if (Unsafe.atomicCompareAndSwap(status_address, status_flags, newlockword)) {
				// successfully obtained inflated lock.
				return;
			} else {
				// another thread has a thin lock on this object.  yield to scheduler.
				/*Screen.debug("<waitForLockInstall old=0x" + NumberUtils.hex(oldlockword) + " tid=0x" + NumberUtils.hex(tid) + " thread=" + t.asThread().getName() + 
                             " object.class=" + Unsafe.getVmClass(k).getName() +
		                     " inReschedule=" + VmScheduler.inReschedule + 
						     "/>");*/
				final VmProcessor proc = Unsafe.getCurrentProcessor();
				proc.yield(true);
			}
		}
	}
	
	/** 
	 * Get the Monitor object associated with this lockword.
	 * @param lockword
	 * @return The monitor
	 */
	private static Monitor getMonitor(int lockword) {
		final int word = lockword & ~(ObjectFlags.LOCK_EXPANDED | ObjectFlags.STATUS_FLAGS_MASK);
		final Address address = Unsafe.intToAddress(word);
		if (address == null) {
			throw new IllegalMonitorStateException("Inflated monitor is null????");
		}
		return (Monitor)Unsafe.objectAt(address);
	}
    
    /**
     * Gets the inflated monitor of an object (if any).
     * @param object
     * @param arch
     * @return The inflated monitor of the given object, or null if the given object has no inflated monitor.
     */
    static Monitor getInflatedMonitor(Object object, VmArchitecture arch) {
    	final int slotSize = arch.getReferenceSize();
		final Address status_address = Unsafe.add(Unsafe.addressOf(object), ObjectLayout.FLAGS_SLOT * slotSize);
		final int oldlockword = Unsafe.getInt(status_address);
		
		if ((oldlockword & ObjectFlags.LOCK_EXPANDED) != 0) {
			return getMonitor(oldlockword);
		} else {
			return null;
		}
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?