blob: 3bb39702ce8bfd2228ccd12af4185a9158959710 [file] [log] [blame]
//===----------- ObjectLocks.h - Object based locks -----------------------===//
//
// The VMKit project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef VMKIT_OBJECT_LOCKS_H
#define VMKIT_OBJECT_LOCKS_H
#include "vmkit/Allocator.h"
#include "vmkit/GC.h"
#include "vmkit/Cond.h"
#include "vmkit/Locks.h"
#include "vmkit/Thread.h"
namespace vmkit {
class FatLock;
class LockSystem;
class LockingThread {
public:
/// varcond - Condition variable when the thread needs to be awaken from
/// a wait.
///
vmkit::Cond varcond;
/// interruptFlag - Has this thread been interrupted?
///
uint32 interruptFlag;
/// nextWaiting - Next thread waiting on the same monitor.
///
LockingThread* nextWaiting;
/// prevWaiting - Previous thread waiting on the same monitor.
///
LockingThread* prevWaiting;
/// waitsOn - The lock on which the thread is waiting on.
///
FatLock* waitsOn;
/* Java thread states **************************************************************/
static const unsigned int StateNew = 0;
static const unsigned int StateRunning = 1;
static const unsigned int StateBlocked = 2;
static const unsigned int StateWaiting = 3;
static const unsigned int StateTimeWaiting = 4;
static const unsigned int StateTerminated = 5;
static const unsigned int StateParked = 6;
static const unsigned int StateTimeParked = 7;
static const unsigned int StateInterrupted = 40;
/// state - The current state of this thread: Running, Waiting or Interrupted.
uint32 state;
LockingThread() {
interruptFlag = 0;
nextWaiting = NULL;
prevWaiting = NULL;
waitsOn = NULL;
state = StateRunning;
}
bool wait(gc* object, LockSystem& table, struct timeval* info, bool timed);
void notify(gc* object, LockSystem& table, vmkit::Thread* ownerThread = NULL);
void notifyAll(gc* object, LockSystem& table, vmkit::Thread* ownerThread = NULL);
};
class FatLock : public vmkit::PermanentObject {
private:
vmkit::LockRecursive internalLock;
vmkit::SpinLock spinLock;
uint32_t waitingThreads;
uint32_t lockingThreads;
LockingThread* firstThread;
gc* associatedObject;
uint32_t index;
FatLock* nextFreeLock;
bool associatedObjectDead;
public:
FatLock(uint32_t index, gc* object);
word_t getID();
int tryAcquire() { return internalLock.tryLock(); }
bool acquire(gc* object, LockSystem& table);
void acquireAll(gc* object, word_t count);
void release(gc* object, LockSystem& table, vmkit::Thread* ownerThread = NULL);
vmkit::Thread* getOwner();
bool owner();
void setAssociatedObject(gc* obj);
gc* getAssociatedObject() { return associatedObject; }
gc** getAssociatedObjectPtr() { return &associatedObject; }
bool associatedObjectIsDead() const {return associatedObjectDead;}
void markAssociatedObjectAsDead() {associatedObjectDead = true;}
friend class LockSystem;
friend class LockingThread;
friend class ThinLock;
};
/// LockSystem - This class manages all Java locks used by the applications.
/// Each JVM must own an instance of this class and allocate Java locks
/// with it.
///
class LockSystem {
friend class FatLock;
public:
// Fixed values. With these values, an index is on 18 bits.
static const uint32_t GlobalSize = 128;
static const uint32_t BitIndex = 11;
static const uint32_t IndexSize = 1 << BitIndex;
static const uint32_t BitMask = IndexSize - 1;
static const uint32_t MaxLocks = GlobalSize * IndexSize;
vmkit::BumpPtrAllocator& allocator;
/// LockTable - The global table that will hold the locks. The table is
/// a two-dimensional array, and only one entry is created, so that
/// the lock system does not eat up all memory on startup.
///
FatLock* ** LockTable;
/// currentIndex - The current index in the tables. Always incremented,
/// never decremented.
///
uint32_t currentIndex;
/// freeLock - The list of locks that are allocated and available.
///
FatLock* freeLock;
/// threadLock - Spin lock to protect the currentIndex field.
///
vmkit::SpinLock threadLock;
/// allocate - Allocate a FatLock.
///
FatLock* allocate(gc* obj);
/// deallocate - Put a lock in the free list lock.
///
void deallocate(FatLock* lock);
/// LockSystem - Default constructor. Initialize the table.
///
LockSystem(vmkit::BumpPtrAllocator& allocator);
/// getLock - Get a lock from an index in the table.
///
FatLock* getLock(uint32_t index) {
return LockTable[index >> BitIndex][index & BitMask];
}
FatLock* getFatLockFromID(word_t ID);
};
class ThinLock {
public:
// The header of an object that has a thin lock implementation is like the
// following:
//
// x xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
// ^ ^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
// 1 11 12 8
// fat lock thread id thin lock count + hash GC bits
static const uint64_t FatMask = 1LL << (kThreadStart > 0xFFFFFFFFLL ? 61LL : 31LL);
static const uint64_t NonLockBits = HashBits + GCBits;
static const uint64_t NonLockBitsMask = ((1LL << NonLockBits) - 1LL);
static const uint64_t ThinCountMask = 0xFFFFFFFFLL & ~(FatMask | kThreadIDMask | NonLockBitsMask);
static const uint64_t ThinCountShift = NonLockBits;
static const uint64_t ThinCountAdd = 1LL << NonLockBits;
/// initialise - Initialise the value of the lock.
///
static void removeFatLock(FatLock* fatLock, LockSystem& table);
/// overflowThinlock - Change the lock of this object to a fat lock because
/// we have reached the maximum number of locks.
static void overflowThinLock(gc* object, LockSystem& table);
/// changeToFatlock - Change the lock of this object to a fat lock. The lock
/// may be in a thin lock or fat lock state.
static FatLock* changeToFatlock(gc* object, LockSystem& table);
/// acquire - Acquire the lock.
static void acquire(gc* object, LockSystem& table);
/// release - Release the lock.
static void release(gc* object, LockSystem& table, vmkit::Thread* ownerThread = NULL);
/// owner - Returns true if the current thread is the owner of this object's
/// lock.
static bool owner(gc* object, LockSystem& table);
static vmkit::Thread* getOwner(gc* object, LockSystem& table);
/// getFatLock - Get the fat lock is the lock is a fat lock, 0 otherwise.
static FatLock* getFatLock(gc* object, LockSystem& table);
};
} // end namespace vmkit
#endif // VMKIT_OBJECT_LOCKS_H