/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.scheduler.greenthreads; import org.jikesrvm.VM; import org.jikesrvm.runtime.VM_Magic; import org.jikesrvm.scheduler.VM_Lock; import org.jikesrvm.scheduler.VM_Processor; import org.jikesrvm.scheduler.VM_Scheduler; import org.jikesrvm.scheduler.VM_ThinLock; import org.jikesrvm.scheduler.VM_Thread; import org.vmmagic.pragma.LogicallyUninterruptible; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Offset; @Uninterruptible public class VM_GreenLock extends VM_Lock { /** * A queue of threads contending for this lock (guarded by <code>mutex</code>). * For example, on the current thread if "synchronized(lockObject)" were * performed and the lock wasn't available, the thread would be queued here. */ public final VM_ThreadQueue entering; /** A queue of (proxies for) threads awaiting notification on this object (guarded by <code>mutex</code>). */ public final VM_ThreadProxyWaitingQueue waiting; /** * Should we give up or persist in the attempt to get a heavy-weight lock, * if its <code>mutex</code> microlock is held by another procesor. */ private static final boolean tentativeMicrolocking = false; /** * A heavy weight lock to handle extreme contention and wait/notify * synchronization. */ public VM_GreenLock() { entering = new VM_ThreadQueue(); waiting = new VM_ThreadProxyWaitingQueue(); } /** * Acquires this heavy-weight lock on the indicated object. * * @param o the object to be locked * @return true, if the lock succeeds; false, otherwise */ @Override public final boolean lockHeavy(Object o) { if (tentativeMicrolocking) { if (!mutex.tryLock()) { return false; } } else { mutex.lock("lock heavy mutex"); // Note: thread switching is not allowed while mutex is held. } if (lockedObject != o) { // lock disappeared before we got here mutex.unlock(); // thread switching benign return false; } if (STATS) lockOperations++; VM_GreenProcessor mine = VM_GreenProcessor.getCurrentProcessor(); int threadId = mine.threadId; if (ownerId == threadId) { recursionCount++; } else if (ownerId == 0) { ownerId = threadId; recursionCount = 1; } else if (mine.threadSwitchingEnabled()) { VM_GreenScheduler.getCurrentThread().block(entering, mutex); // when this thread next gets scheduled, it will be entitled to the lock, // but another thread might grab it first. return false; // caller will try again } else { // can't yield - must spin and let caller retry // potential deadlock if user thread is contending for a lock with thread switching disabled if (VM.VerifyAssertions) VM._assert(VM_Scheduler.getCurrentThread().isGCThread()); mutex.unlock(); // thread-switching benign return false; // caller will try again } mutex.unlock(); // thread-switching benign return true; } /** * Releases this heavy-weight lock on the indicated object. * * @param o the object to be unlocked */ @Override public final void unlockHeavy(Object o) { boolean deflated = false; mutex.lock("unlock heavy"); // Note: thread switching is not allowed while mutex is held. VM_Processor mine = VM_Processor.getCurrentProcessor(); if (ownerId != mine.threadId) { mutex.unlock(); // thread-switching benign raiseIllegalMonitorStateException("heavy unlocking", o); } recursionCount--; if (0 < recursionCount) { mutex.unlock(); // thread-switching benign return; } if (STATS) unlockOperations++; ownerId = 0; VM_GreenThread t = entering.dequeue(); if (t != null) { t.unblock(); } else if (entering.isEmpty() && waiting.isEmpty()) { // heavy lock can be deflated // Possible project: decide on a heuristic to control when lock should be deflated Offset lockOffset = VM_Magic.getObjectType(o).getThinLockOffset(); if (!lockOffset.isMax()) { // deflate heavy lock deflate(o, lockOffset); deflated = true; } } mutex.unlock(); // does a VM_Magic.sync(); (thread-switching benign) if (deflated && ((LOCK_ALLOCATION_UNIT_SIZE << 1) <= mine.freeLocks) && BALANCE_FREE_LOCKS) { globalizeFreeLocks(mine); } } /** * Disassociates this heavy-weight lock from the indicated object. * This lock is not held, nor are any threads on its queues. Note: * the mutex for this lock is held when deflate is called. * * @param o the object from which this lock is to be disassociated */ private void deflate(Object o, Offset lockOffset) { if (VM.VerifyAssertions) { VM._assert(lockedObject == o); VM._assert(recursionCount == 0); VM._assert(entering.isEmpty()); VM._assert(waiting.isEmpty()); } if (STATS) deflations++; VM_ThinLock.deflate(o, lockOffset, this); lockedObject = null; free(this); } @LogicallyUninterruptible private static void raiseIllegalMonitorStateException(String msg, Object o) { throw new IllegalMonitorStateException(msg + o); } /** * Is this lock blocking thread t? */ @Override protected final boolean isBlocked(VM_Thread t) { return entering.contains(t); } /** * Is this thread t waiting on this lock? */ @Override protected final boolean isWaiting(VM_Thread t) { return waiting.contains(t); } /** * Dump threads blocked trying to get this lock */ @Override protected void dumpBlockedThreads() { VM.sysWrite(" entering: "); entering.dump(); } /** * Dump threads waiting to be notified on this lock */ @Override protected void dumpWaitingThreads() { VM.sysWrite(" waiting: "); waiting.dump(); } }