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 + -
显示快捷键?