objsync.c

来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,810 行 · 第 1/5 页

C
1,810
字号
/* * @(#)objsync.c	1.100 06/10/10 *  * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER *  * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation.  *  * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt).  *  * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA  *  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions.  */#include "javavm/include/defs.h"#include "javavm/include/sync.h"#include "javavm/include/indirectmem.h"#include "javavm/include/localroots.h"#include "javavm/include/common_exceptions.h"#include "javavm/include/clib.h"#ifdef CVM_JVMTI#include "javavm/include/jvmtiExport.h"#endif/* NOTES: About CVM object monitors and their life-cycles   ======================================================   The Fast Locking mechanism:   ==========================   CVM implements a fast locking mechanism which attempts to speed up monitor   locking/unlocking operations for the monitors which meet the following   criteria:     1. The object monitor is locked and unlocked only by one thread at a time        (i.e. no thread contention occurs while trying to lock or unlock the        monitor).     2. The object monitor isn't used for the Object.wait(), Object.notify(),        Object.notifyAll().   If the above criteria is met, then the lock is implemented by simply   setting the low 2 bits of a header bit flag word in each object using some   form of atomic operation.  The fast lock mechanism basically provides some   speed optimization benefits due to:     1. Not having to actually invoke OS system calls to allocate and        lock/unlock a monitor.     2. Reduce the amount of memory/resource allocations necessary to implement        the monitor.  Monitors are allocated per thread as well as globally and        are reclaimed for reuse through various scavenging mechanism.  This        reuse speeds up monitor operations if a previously reclaimed monitor is        available for reuse.   At any time that the criteria for fast locking/unlocking are not met, the   monitor implementation will inflate itself into a heavy weight monitor which   relies on the platform-specific mutex and condvar implementations defined by   the porting layer to do its locking/unlocking.   Data Structures & Ownership of the data structures:   ==================================================   CVM object monitors are implemented using 2 data structures:     1. The CVMOwnedMonitor record.     2. The CVMObjMonitor monitor implementation.     The CVMOwnedMonitor record is used to track locking information with or     without an actual monitor.  CVMOwnedMonitors are allocated, freed, and     modified exclusively by its owner thread.  This avoids contention between     threads over the manipulation of CVMOwnedMonitors.     The CVMObjMonitor is the actual monitor that is attached to the object     when a heavy-weight lock needs to employed.  CVMObjMonitors, unlike     CVMOwnedMonitors, are shared between threads and held in the global list.     Contention is minimized by having each thread cache one instance of the     CVMObjMonitor for its own use during the inflation process.  Otherwise,     CVMObjMonitors in the global lists are protected from contention between     threads by the CVMglobals.syncLock.   In CVMglobals, there are:     1. CVMglobals.objLocksBound: This is the list of bound monitors i.e.            CVMObjMonitors which are attached to an object.     2. CVMglobals.objLocksUnbound: This is the list of unbound monitors i.e.            CVMObjMonitors which used to be attached to objects which have now            been GC'ed.  This means that the monitor's object pointer is NULL.     3. CVMglobals.objLocksFree: This is the list of free monitors i.e            CVMObjMonitors which are not attached to any objects yet.     4. CVMglobals.syncLock: This is the global lock used for protecting the            above 3 monitor lists and for synchronizing threads which wish to:            inflate a monitor, set an object hash code, or do an unlock            operation on a fast lock.   Each thread's CVMExecEnv has:     1. ee->objLockCurrent: This is a per-thread reference to a CVMObjMonitor            that is in the midst of being processed and has not yet been            attached to an object yet.  This is necessary to prevent the            referenced CVMObjMonitor from being scavenged prematurely.     2. ee->objLocksFreeUnlocked: This is supply of CVMObjMonitors for use by            the the thread in the event that it needs to do a monitor            inflation.  The inflation process will replenish            ee->objLocksFreeUnlocked at the end of the inflation process.            The current implementation only keeps one CVMObjMonitor available            in ee->objLocksFreeUnlocked.     3. ee->objLocksOwned: This is a list of all the CVMOwnedMonitors which are            locked by the thread.  These CVMOwnedMonitors may or may not be            attached to an actual CVMObjMonitor.     4. ee->objLocksFreeOwned: This is a list of free CVMOwnedMonitors            available for the thread's use.        Write access to these fields of the CVMExecEnv is exclusively owned by        owner thread.  This avoids any contention between threads, and, hence,        no synchronization mechanism is needed to synchronize accesses to these        fields.   The Monitor Life-Cycles & Processes:   ===================================    Inflation:        . This is the process by which an object gets attached to a          CVMObjMonitor.  This process is protected by the CVMglobals.syncLock.    Initial state:        . The object header bits indicate CVM_LOCKSTATE_UNLOCKED.    Locked without contention (fast lock):        . The object header bits indicate CVM_LOCKSTATE_LOCKED and holds a          pointer to a CVMOwnedMonitor instance.        . The thread who owns the lock on that object also holds a pointer to          the same CVMOwnedMonitor in its owned list.        . If the object header bits already indicate CVM_LOCKSTATE_LOCKED upon          attempting to lock the monitor, then the CVMOwnedMonitor's reentry          count is incremented.    Locked with contention (heavy weight lock):        . The object header bits indicate CVM_LOCKSTATE_MONITOR and holds a          pointer to a CVMObjMonitor instance.        . The CVMObjMonitor is marked as CVM_OBJMON_OWNED and put on the          global bound list.        . The thread who owns the lock still have a pointer to the          CVMOwnedMonitor record.  The CVMOwnedMonitor record has a pointer to          the CVMObjMonitor for the lock.    Unlocked while holding a fast lock:        . The CVMOwnedMonitor's reentry count is decremented.  If this count          has not reached 0 yet, then the unlock operation is done.  Otherwise,          the following steps are executed as well.        . The object header bits are changed back to CVM_LOCKSTATE_UNLOCKED.        . The CVMOwnedMonitor is moved from the owner thread's ee's owned list          to its free list.    Unlocked while holding a heavy weight lock:        . The object header bits remains CVM_LOCKSTATE_MONITOR and the object          retains its pointer to the CVMObjMonitor instance.        . The CVMObjMonitor is marked as CVM_OBJMON_BOUND and remains on the          global bound list.    Each thread always keep one free CVMObjMonitor around to accelerate    impending monitor inflation operations.  After a monitor has been inflated,    the thread will attempt to replenish its spare free CVMObjMonitor.  It does    this by either:        1. Getting one from the global free list.        2. Scavenging for bound monitors which are not locked.        3. Allocating new ones.    During CVMObjMonitor scavenging:        . CVMObjMonitors which are bound (on the global bound list) but not          locked are released into the global free list.        . CVMObjMonitors which are on the global unbound list (see notes on          monitor GC below) are unlocked and released into the global free          list.    CVMOwnedMonitor scavenging:        . CVMOwnedMonitor needed by most monitor operations and attained before          the operation commences (at the top of the functions).        . Usually, it is attained from the thread's free list.  If the free          list is empty, then the thread will attempt to replenish the free          CVMOwnedMonitor supply by one of the following ways:            1. Allocate a new one.            2. Run the scavenger which searches the thread's owned list for               monitors which have fast locks but are no longer associated               with a live object (see notes on monitor GC below).  These               monitor records are unlocked and released back into the thread's               free list.  Since this case does not naturally happen with Java               code, it is unlikely to occur.  Hence a scavenging operation is               unlikely to yield a free CVMOwnedMonitor.  This is why we opt to               allocate a new one first before attempting a scavenging               operation.    During a monitor GC (invoked by the GC):        . CVMObjMonitors which are locked but no longer associated with a live          object (because the object has been GC'ed but the lock hasn't been          released prior) are moved from the global bound list to the global          unbound list.  See notes on monitor scavenging above to see how these          monitors get released back into the free lists for reuse.          The CVMObjMonitors do not get moved directly from the bound list to          the free list because bound CVMObjMonitors are attached to          CVMOwnedMonitors.  Hence, the best that the GC thread can do is to          tag the monitor by putting it on the unbound list and relying on the          owner thread to release the attached CVMOwnedMonitor as well as put          the CVMObjMonitor back on the free list.    During thread destruction:        . When a thread shuts down, it will unlock all monitors whose lock it          owns if those monitors are still associated with live objects.        . While attempting to unlock monitors, if the thread encounters any          monitors which are no longer associated with any live objects, it          will invoke the appropriate scavengers to reclaim the monitors into          the free lists.        . After reclaiming or unlocking all the monitors on its owned list, the          thread will release/free up all the free monitors on its free list          before exiting.    Deflation of heavy weight monitors:    ==================================    Heavy weight monitors are deflated in the scavenging process.  Since a    scavenging process is invoked immediately after each monitor inflation    process, unlocked inflated monitors don't stay around for long.    Synchronization between various Monitor Methods:    ===============================================    The following methods must be protected from themselves and each other by    sync'ing on the same lock.  The lock currently used for this purpose is    CVMglobals.syncLock.  The methods are as follows:        1. CVMobjectInflate()        2. CVMobjectSetHashBitsIfNeeded()        3. CVMfastUnlock()    Assumptions:    ===========    1. It is assumed that we won't ever enter a monitor recursively up to an       reentry count of CVM_MAX_REENTRY_COUNT.  This allows       CVM_INVALID_REENTRY_COUNT to be above CVM_MAX_REENTRY_COUNT.       Debug builds will check that count never reaches CVM_MAX_REENTRY_COUNT.*/#ifndef CVM_INITIAL_NUMBER_OF_OBJ_MONITORS#define CVM_INITIAL_NUMBER_OF_OBJ_MONITORS      10#endifstatic void CVMmonitorAttachObjMonitor2OwnedMonitor(CVMExecEnv *ee,                                                    CVMObjMonitor *mon);#if CVM_FASTLOCK_TYPE != CVM_FASTLOCK_NONEstatic CVMBool CVMfastReentryTryLock(CVMExecEnv *ee, CVMObject *obj);#endifstatic void CVMsyncMonitorScavenge(CVMExecEnv *ee, CVMBool releaseOwnedRecs);static void CVMsyncGCSafeAllMonitorScavengeInternal(CVMExecEnv *ee,                                                    CVMBool releaseOwnedRecs);static void CVMmonitorScavengeFast(CVMExecEnv *ee);static void CVMownedMonitorInit(CVMOwnedMonitor *m, CVMExecEnv *owner);static void CVMownedMonitorDestroy(CVMOwnedMonitor *m);#ifdef CVM_THREAD_BOOSTstatic void CVMboost(CVMExecEnv *ee, CVMObjMonitor *mon, CVMExecEnv *owner);static void CVMunboost(CVMExecEnv *ee, CVMObjMonitor *mon);#endifstatic CVMTryLockFunc   CVMdetTryUnlock, CVMdetTryLock;static CVMLockFunc      CVMfastLock, CVMdetLock;static CVMLockFunc      CVMfastUnlock, CVMdetUnlock;static CVMNotifyFunc    CVMfastNotify, CVMdetNotify;static CVMNotifyAllFunc CVMfastNotifyAll, CVMdetNotifyAll;static CVMWaitFunc      CVMfastWait, CVMdetWait;/* * The locking vector. */const CVMSyncVector CVMsyncKinds[2] = {    {CVMfastTryLock, CVMfastLock, CVMfastTryUnlock, CVMfastUnlock,     CVMfastWait, CVMfastNotify, CVMfastNotifyAll, NULL},    {CVMdetTryLock,  CVMdetLock,  CVMdetTryUnlock, CVMdetUnlock,     CVMdetWait,  CVMdetNotify,  CVMdetNotifyAll, NULL}};#if CVM_FASTLOCK_TYPE == CVM_FASTLOCK_MICROLOCK/* NOTE: The rendezvousOwnedRec below is used as a fake CVMOwnedMonitor that   is not owned by any thread (hence, the owner is NULL).  It is used to   replace the various words field in the object header when we want to   inflate the monitor into a CVMObjMonitor.  This replacement ensures that   no fast locking and unlocking activity occurs on this object without having   to hold onto the object microlock the whole time we're doing the inflation.   This also avoids any complications due to any side effects of holding onto   the object microlock while waiting for various HPI functions (e.g.   CVMmutexSetOwner()) to complete.*/static const CVMOwnedMonitor rendezvousOwnedRec = {    /* owner    */ NULL,    /* type     */ CVM_OWNEDMON_FAST,    /* object   */ NULL,    /* u        */ {{0}},    /* next     */ NULL,#ifdef CVM_DEBUG    /* magic    */ CVM_OWNEDMON_MAGIC,    /* state    */ CVM_OWNEDMON_OWNED,#endif    /* count    */ 1};#endifstatic voidCVMmonEnter(CVMExecEnv *ee, CVMObjMonitor *mon){    /* This is like a reference count, needed if count==0 */    ee->objLockCurrent = mon;#ifdef CVM_THREAD_BOOST    if (mon->boost) {        /* If we get here, then the ownership of the monitor has not actually	   been claimed the owner thread yet though it has been marked as so.	   The following ensures that ownership is claimed by the owner thread	   before we enter the monitor. */	CVMExecEnv *owner = CVMprofiledMonitorGetOwner(&mon->mon);	if (owner == ee) {            /* mon->boost being true and this thread being the owner implies	       that another thread had inflated this monitor for us.  We'll	       need to claim ownership of the monitor and unboost our thread	       priority.  Only after that we'll we re-enter the the monitor.	    */	    CVMunboost(ee, mon);	    CVMassert(!mon->boost);	    CVMprofiledMonitorEnterUnsafe(&mon->mon, ee, CVM_TRUE);	} else {	    /* This is the case where we discovered a contended enter and	       inflated the monitor.  We therefore need to boost the thread	       priority of the owner and wait for it to claim ownership of	       the monitor before we try to acquire it ourselves. */	    CVMprofiledMonitorPreContendedEnterUnsafe(&mon->mon, ee);	    CVMboost(ee, mon, owner);	    CVMprofiledMonitorContendedEnterUnsafe(&mon->mon, ee);	}    } else {	CVMprofiledMonitorEnterUnsafe(&mon->mon, ee, CVM_TRUE);    }    CVMassert(!mon->boost);#else    CVMprofiledMonitorEnterUnsafe(&mon->mon, ee, CVM_TRUE);#endif    ee->objLockCurrent = NULL;    CVMassert(CVMprofiledMonitorGetOwner(&mon->mon) == ee);}static CVMBoolCVMmonTryEnter(CVMExecEnv *ee, CVMObjMonitor *mon){#ifdef CVM_THREAD_BOOST    if (mon->boost) {	return CVM_FALSE;    }#endif    if (!CVMprofiledMonitorTryEnter(&mon->mon, ee)) {	return CVM_FALSE;

⌨️ 快捷键说明

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