org.jikesrvm.scheduler
Class SpinLock

java.lang.Object
  extended by org.jikesrvm.scheduler.SpinLock
All Implemented Interfaces:
Constants, HeapLayoutConstants, ThinLockConstants, TIBLayoutConstants, SizeConstants

public final class SpinLock
extends Object
implements Constants

Alternative (to Java monitors) light-weight synchronization mechanism to implement Java monitors Lock. These locks should not be used where Java monitors would suffice, or where an adaptive mutex is required. They are intended to be held only briefly!

Normally, contending RVMThreads will spin on this processor lock's latestContender field. If MCS_Locking is set, the processors spin on processor local data. This is loosely based on an idea in Mellor-Crummey and Scott's paper in ASPLOS-IV (1991). 1. Possible project: determine those conditions under which MCS locking performs better than spinning on a global address.

Acquiring or releasing a lock involves atomically reading and setting the lock's latestContender field. If this field is null, the lock is unowned. Otherwise, the field points to the virtual processor that owns the lock, or, if MCS locking is being used, to the last vp on a circular queue of virtual processors spinning until they get the lock, or, if MCS locking is being used and the circular spin queue is being updated, to IN_FLUX.

Contention is best handled by doing something else. To support this, tryLock obtains the lock (and returns true) if the lock is unowned (and there is no spurious microcontention). Otherwise, it returns false.

Only when "doing something else" is not an attractive option (locking global thread queues, unlocking a thick lock with threads waiting, avoiding starvation on a thread that has issued several tryLocks, etc.) should lock() be called. Here, any remaining contention is handled by spinning on a local flag.

To add itself to the circular waiting queue, a processor must succeed in setting the latestContender field to IN_FLUX. A backoff strategy is used to reduce contention for this field. This strategy has both a pseudo-random (to prevent two or more virtual processors from backing off in lock step) and an exponential component (to deal with really high contention).

Releasing a lock entails either atomically setting the latestContender field to null (if this processor is the latestContender), or releasing the first virtual processor on the circular spin queue. In the latter case, the latestContender field must be set to IN_FLUX. To give unlock() priority over lock(), the backoff strategy is not used for unlocking: if a vp fails to set set the field to IN_FLUX, it tries again immediately.

Usage: system locks should only be used when synchronized methods cannot. Do not do anything, (such as trigger a type cast, allocate an object, or call any method of a class that does not implement Uninterruptible) that might allow a thread switch or trigger a garbage collection between lock and unlock.

See Also:
RVMThread, Monitor, Lock

Field Summary
private static int delayBase
           
private static int[] delayCount
           
private static int delayIndex
           
private static int delayMultiplier
           
private static Address IN_FLUX
          For MCS locking, indicates that another processor is changing the state of the circular waiting queue.
(package private)  RVMThread latestContender
          The state of the processor lock.
private static boolean MCS_Locking
          Should contending RVMThreads spin on thread local addresses (true) or on a globally shared address (false).
 
Fields inherited from interface org.jikesrvm.Constants
NOT_REACHED, REFLECTION_FPRS_BITS, REFLECTION_FPRS_MASK, REFLECTION_GPRS_BITS, REFLECTION_GPRS_MASK
 
Fields inherited from interface org.jikesrvm.objectmodel.ThinLockConstants
TL_DEDICATED_U16_OFFSET, TL_DEDICATED_U16_SHIFT, TL_LOCK_COUNT_MASK, TL_LOCK_COUNT_SHIFT, TL_LOCK_COUNT_UNIT, TL_LOCK_ID_MASK, TL_LOCK_ID_SHIFT, TL_NUM_BITS_RC, TL_NUM_BITS_STAT, TL_NUM_BITS_TID, TL_STAT_BIASABLE, TL_STAT_FAT, TL_STAT_MASK, TL_STAT_SHIFT, TL_STAT_THIN, TL_THREAD_ID_MASK, TL_THREAD_ID_SHIFT, TL_UNLOCK_MASK
 
Fields inherited from interface org.jikesrvm.SizeConstants
BITS_IN_ADDRESS, BITS_IN_BOOLEAN, BITS_IN_BYTE, BITS_IN_CHAR, BITS_IN_DOUBLE, BITS_IN_EXTENT, BITS_IN_FLOAT, BITS_IN_INT, BITS_IN_LONG, BITS_IN_OFFSET, BITS_IN_PAGE, BITS_IN_SHORT, BITS_IN_WORD, BYTES_IN_ADDRESS, BYTES_IN_BOOLEAN, BYTES_IN_BYTE, BYTES_IN_CHAR, BYTES_IN_DOUBLE, BYTES_IN_EXTENT, BYTES_IN_FLOAT, BYTES_IN_INT, BYTES_IN_LONG, BYTES_IN_OFFSET, BYTES_IN_PAGE, BYTES_IN_SHORT, BYTES_IN_WORD, LOG_BITS_IN_ADDRESS, LOG_BITS_IN_BOOLEAN, LOG_BITS_IN_BYTE, LOG_BITS_IN_CHAR, LOG_BITS_IN_DOUBLE, LOG_BITS_IN_EXTENT, LOG_BITS_IN_FLOAT, LOG_BITS_IN_INT, LOG_BITS_IN_LONG, LOG_BITS_IN_OFFSET, LOG_BITS_IN_PAGE, LOG_BITS_IN_SHORT, LOG_BITS_IN_WORD, LOG_BYTES_IN_ADDRESS, LOG_BYTES_IN_BOOLEAN, LOG_BYTES_IN_BYTE, LOG_BYTES_IN_CHAR, LOG_BYTES_IN_DOUBLE, LOG_BYTES_IN_EXTENT, LOG_BYTES_IN_FLOAT, LOG_BYTES_IN_INT, LOG_BYTES_IN_LONG, LOG_BYTES_IN_OFFSET, LOG_BYTES_IN_PAGE, LOG_BYTES_IN_SHORT, LOG_BYTES_IN_WORD
 
Fields inherited from interface org.jikesrvm.objectmodel.TIBLayoutConstants
IMT_METHOD_SLOTS, NEEDS_DYNAMIC_LINK, TIB_ARRAY_ELEMENT_TIB_INDEX, TIB_DOES_IMPLEMENT_INDEX, TIB_FIRST_SPECIALIZED_METHOD_INDEX, TIB_FIRST_VIRTUAL_METHOD_INDEX, TIB_INTERFACE_DISPATCH_TABLE_INDEX, TIB_SUPERCLASS_IDS_INDEX, TIB_TYPE_INDEX
 
Fields inherited from interface org.jikesrvm.HeapLayoutConstants
BAD_MAP_COMPRESSION, BOOT_IMAGE_CODE_END, BOOT_IMAGE_CODE_SIZE, BOOT_IMAGE_CODE_START, BOOT_IMAGE_DATA_END, BOOT_IMAGE_DATA_SIZE, BOOT_IMAGE_DATA_START, BOOT_IMAGE_END, BOOT_IMAGE_RMAP_END, BOOT_IMAGE_RMAP_START, MAX_BOOT_IMAGE_RMAP_SIZE, MAXIMUM_MAPPABLE
 
Constructor Summary
SpinLock()
           
 
Method Summary
private  void handleMicrocontention(int n)
          An attempt to lock or unlock a processor lock has failed, presumably due to contention with another processor.
 void lock()
          Acquire a processor lock.
 void lock(String s)
           
 boolean lockHeld()
           
 boolean tryLock()
          Conditionally acquire a processor lock.
 void unlock()
          Release a processor lock.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

MCS_Locking

private static final boolean MCS_Locking
Should contending RVMThreads spin on thread local addresses (true) or on a globally shared address (false).

See Also:
Constant Field Values

latestContender

RVMThread latestContender
The state of the processor lock. Only the first two states are possible unless MCS locking is implemented.


delayMultiplier

private static final int delayMultiplier
See Also:
Constant Field Values

delayBase

private static final int delayBase
See Also:
Constant Field Values

delayIndex

private static int delayIndex

delayCount

private static final int[] delayCount

IN_FLUX

private static final Address IN_FLUX
For MCS locking, indicates that another processor is changing the state of the circular waiting queue.

Constructor Detail

SpinLock

public SpinLock()
Method Detail

lockHeld

public boolean lockHeld()

lock

public void lock(String s)

lock

public void lock()
Acquire a processor lock.


tryLock

public boolean tryLock()
Conditionally acquire a processor lock.

Returns:
whether acquisition succeeded

unlock

public void unlock()
Release a processor lock.


handleMicrocontention

private void handleMicrocontention(int n)
An attempt to lock or unlock a processor lock has failed, presumably due to contention with another processor. Backoff a little to increase the likelihood that a subsequent retry will succeed.