objsync.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,810 行 · 第 1/5 页
C
1,810 行
static voidCVMreplenishFreeListsBlocking(CVMExecEnv *ee){ /* NOTE: We need to attempt scavenging first before allocating a new ObjMon because scavenging is the only mechanism by which these monitors get reused. Otherwise, we will end up allocating as many monitors as memory will allow, and unused monitors that could have been reused will remain unused because the scavenger won't be called until we run out of memory. */ if (ee->objLocksFreeUnlocked == NULL) { /* NOTE: ee->objLocksOwned, and ee->objLocksFreeOwned may be changed by CVMsyncMonitorScavenge(). Do not cache these values. */ CVMsyncMonitorScavenge(ee, CVM_FALSE); if (CVMglobals.objLocksFree != NULL) { /* It appears that after scavenging, we have replenished the global free list. So try to replenish the thread specific free list for CVMObjMonitors by tapping into the global free list. NOTE: This is not guaranteed to succeed because some other thread might come along and consume the monitor our scavenger has just freed. */ CVMsysMutexLock(ee, &CVMglobals.syncLock); CVMreplenishFreeListsNonBlocking(ee); CVMsysMutexUnlock(ee, &CVMglobals.syncLock); } /* If after scavenging, we still aren't able to fill the need, then it's time to allocate a new one: */ if (ee->objLocksFreeUnlocked == NULL) { CVMObjMonitor *mon; mon = (CVMObjMonitor *)calloc(1, sizeof (CVMObjMonitor)); if (mon != NULL) { if (CVMobjMonitorInit(ee, mon, NULL, 0)) { ee->objLocksFreeUnlocked = mon; CVMassert(CVMobjMonitorOwner(mon) == NULL); } else { free(mon); } } } }}/* Purpose: Replenish the thread specific CVMOwnedMonitor free list either by scavenging for it or creating a new one. */static voidCVMreplenishLockRecordUnsafe(CVMExecEnv *ee){ CVMassert(CVMD_isgcUnsafe(ee)); /* We attempt to create a new CVMOwnedMonitor first because it is unlikely that scavenging will turn up any unused CVMOwnedMonitors. See full comments at the top of the file for details. */ { CVMOwnedMonitor *o; CVMD_gcSafeExec(ee, { o = (CVMOwnedMonitor *)calloc(1, sizeof (CVMOwnedMonitor)); if (o != NULL) { CVMownedMonitorInit(o, ee); } }); if (o != NULL) { o->next = ee->objLocksFreeOwned; ee->objLocksFreeOwned = o; } } /* Scavenge for unused CVMOwnedMonitors if necessary: */ if (ee->objLocksFreeOwned == NULL) { /* We call CVMmonitorScavengeFast() here instead of CVMsyncMonitorScavenge() because we only need to replenish our supply of CVMOwnedMonitors and not CVMObjMonitors. Since CVMsyncMonitorScavenge() is significantly more costly to run and does not get us any additional benefit to help satisfy our needs, calling CVMmonitorScavengeFast() instead is a preferred choice. NOTE: ee->objLocksOwned, and ee->objLocksFreeOwned may be changed by CVMmonitorScavengeFast(). Do not cache these values. */ CVMmonitorScavengeFast(ee); } if (ee->objLocksFreeOwned == NULL && ee->threadExiting) { CVMOwnedMonitor *o = ee->objLocksReservedOwned; /* If this fails, increase CVM_RESERVED_OWNMON_COUNT below */ CVMassert(o != NULL); ee->objLocksReservedOwned = o->next; ee->objLocksFreeOwned = o; o->next = NULL; }}/* Pin an (inflated) object monitor. It will remain inflated until *//* it is unpinned. */static voidCVMobjMonitorPin(CVMExecEnv *ee, CVMObjMonitor *mon){ CVMassert(ee->objLocksPinnedCount < CVM_PINNED_OBJMON_COUNT); ee->objLocksPinned[ee->objLocksPinnedCount++] = mon;}/* Unpin all monitors that were pinned by this thread. */static voidCVMobjMonitorUnpinAll(CVMExecEnv *ee){#ifdef CVM_DEBUG_ASSERTS int i; int n = ee->objLocksPinnedCount; for (i = 0; i < n; ++i) { ee->objLocksPinned[i] = NULL; }#endif CVMtraceExec(CVM_DEBUGFLAG(TRACE_MISC), { CVMconsolePrintf("Unpinned %d monitors\n", ee->objLocksPinnedCount); }); ee->objLocksPinnedCount = 0;}/* Mark pinned monitors as busy */static voidCVMobjMonitorMarkPinnedAsBusy(CVMExecEnv *ee){ int i; for (i = 0; i < ee->objLocksPinnedCount; ++i) { CVMassert(ee->objLocksPinned[i]->obj != NULL);#ifdef CVM_DEBUG_ASSERTS { int state = ee->objLocksPinned[i]->state & ~CVM_OBJMON_BUSY; CVMassert(state == CVM_OBJMON_BOUND || state == CVM_OBJMON_OWNED); }#endif ee->objLocksPinned[i]->state |= CVM_OBJMON_BUSY; }}/* Clear the busy flag from pinned monitors. Undoes what *//* CVMobjMonitorMarkPinnedAsBusy() did. */static voidCVMobjMonitorMarkPinnedAsUnbusy(CVMExecEnv *ee){ int i; for (i = 0; i < ee->objLocksPinnedCount; ++i) { ee->objLocksPinned[i]->state &= ~CVM_OBJMON_BUSY; }}/* Unpin any unreferenced monitors. They can never be *//* inflated or synchronized on again. */static voidCVMobjMonitorUnpinUnreferenced(CVMExecEnv *ee){ int i = 0; while (i < ee->objLocksPinnedCount) { if (ee->objLocksPinned[i]->obj == NULL) {#if 0 /* There should be a way to determine if the monitor is on */ /* the unbound list. */ CVMassert(ee->objLocksPinned[i]->state == CVM_OBJMON_UNBOUND);#endif ee->objLocksPinned[i] = ee->objLocksPinned[--ee->objLocksPinnedCount]; CVMtraceMisc(("Unpinned unreferenced monitor\n")); continue; } ++i; }}static CVMObjMonitor *CVMobjectInflate(CVMExecEnv *ee, CVMObjectICell* indirectObj){ CVMObjMonitor *mon, *omon; CVMObjMonitor **fromListPtr; /* * bits can hold a native pointer (see CVMobjectVariousWord()) * therefore the type has to be CVMAddr which is 4 byte on * 32 bit platforms and 8 byte on 64 bit platforms */ CVMAddr bits; /* See if another thread already beat us to inflating the monitor: */ { CVMObject *obj = CVMID_icellDirect(ee, indirectObj); if (CVMobjMonitorState(obj) == CVM_LOCKSTATE_MONITOR) { CVMObjMonitor *mon = CVMobjMonitor(obj); CVMassert(mon->obj == obj);#ifdef CVM_THREAD_BOOST if (mon->boost) { /* Another thread beat us to inflating this monitor. If we own it, then we'll need to claim actual ownership of the monitor and unboost our thread priority because we didn't inflate it ourselves. CVMunboost() will check for monitor ownership before unboosting. If we don't own it, then CVMunboost() will do nothing. */ CVMunboost(ee, mon); }#endif return mon; } } /* %comment l008 */ /* See notes above on "Synchronization between various Monitor Methods": */ CVMD_gcSafeExec(ee, { CVMsysMutexLock(ee, &CVMglobals.syncLock); }); { CVMObject *obj = CVMID_icellDirect(ee, indirectObj); bits = obj->hdr.various32; } /* While acquiring the syncLock above, another thread could have beaten us to inflating the monitor. Check if this is the case: */ if (CVMhdrBitsSync(bits) == CVM_LOCKSTATE_MONITOR) { /* If we're here, the another thread did beat us to it: */ CVMObjMonitor *mon = (CVMObjMonitor *)CVMhdrBitsPtr(bits); CVMassert(mon->state != CVM_OBJMON_FREE);#ifdef CVM_DEBUG CVMassert(mon->magic == CVM_OBJMON_MAGIC);#endif CVMassert(mon->obj == CVMID_icellDirect(ee, indirectObj));#ifdef CVM_THREAD_BOOST /* Another thread beat us to inflating this monitor. If we own it, then we'll need to claim actual ownership of the monitor and unboost our thread priority because we didn't inflate it ourselves. CVMunboost() will check for monitor ownership before unboosting. If we don't own it, then CVMunboost() will do nothing. */ if (mon->boost) { CVMunboost(ee, mon); }#endif#ifdef CVM_AGGRESSIVE_REPLENISH /* replenish free lists */ goto done;#else CVMsysMutexUnlock(ee, &CVMglobals.syncLock); return mon;#endif } /* If we get here, then we know for sure that no other thread has inflated the monitor yet. And only we have the right to inflate it because we hold the syncLock. */ /* In the following, we'll be doing one of the these change of states: 1. unlocked --> monitor (heavy/deterministic), or 2. locked (fast) --> monitor (heavy/deterministic) */ /* Get a heavy CVMObjMonitor from the free list: */ { fromListPtr = &ee->objLocksFreeUnlocked; mon = *fromListPtr; if (mon == NULL) { /* Failed because no CVMObjMonitor was available: */ CVMsysMutexUnlock(ee, &CVMglobals.syncLock); return NULL; } CVMassert(CVMprofiledMonitorGetOwner(&mon->mon) == NULL); } omon = mon; CVMassert(mon->state == CVM_OBJMON_FREE); mon->state = CVM_OBJMON_BOUND; { CVMObject *obj = CVMID_icellDirect(ee, indirectObj);#if CVM_FASTLOCK_TYPE != CVM_FASTLOCK_NONE CVMUint32 reentryCount = 1; /* * obits can hold a native pointer * therefore the type has to be CVMAddr which is 4 byte on * 32 bit platforms and 8 byte on 64 bit platforms */ CVMAddr obits;#if CVM_FASTLOCK_TYPE == CVM_FASTLOCK_ATOMICOPS /* Write CVM_LOCKSTATE_LOCKED to the obj's header bits to lock out any fast lock or monitor inflation attempts by any other threads: */ obits = CVMatomicSwap(&(obj)->hdr.various32, CVM_LOCKSTATE_LOCKED); if (CVMhdrBitsSync(obits) == CVM_LOCKSTATE_LOCKED) { CVMOwnedMonitor *o = (CVMOwnedMonitor *)CVMhdrBitsPtr(obits); /* We need to use a CVMatomicSwap() here because the owner thread may already have attained its CVMOwnedMonitor corrently. Hence, the above atomic swap of obj->hdr.various32 doesn't prevent a fastReentryTryLock() that's already in progress. However, by doing an atomic swap on the reentry count, we can guarantee that we get the last reentryCount of the owner thread before we prevent it from doing anymore re-entries by swapping a CVM_INVALID_REENTRY_COUNT value into the reentryCount. */ reentryCount = CVMatomicSwap(&o->count, CVM_INVALID_REENTRY_COUNT); }#elif CVM_FASTLOCK_TYPE == CVM_FASTLOCK_MICROLOCK /* Acquire the microlock to lock out any fast lock or monitor inflation attempts by any other threads: */ CVMobjectMicroLock(ee, obj); obits = CVMobjectVariousWord(obj); if (CVMhdrBitsSync(obits) == CVM_LOCKSTATE_LOCKED) { CVMOwnedMonitor *o = (CVMOwnedMonitor *)CVMhdrBitsPtr(obits); reentryCount = o->count;#ifdef CVM_DEBUG o->count = CVM_INVALID_REENTRY_COUNT;#endif } /* Set the object's various word to a fake CVMOwnedMonitor record that is not owned by any thread (i.e. the owner field is NULL) to prevent any fast lock or unlock operations on this object while we're inflating. After that, we can unlock the microlock. */ CVMobjectVariousWord(obj) = (CVMAddr)(&rendezvousOwnedRec) | CVM_LOCKSTATE_LOCKED; CVMobjectMicroUnlock(ee, obj);#endif /* If there is already a fast lock on the object, ... */ if (CVMhdrBitsSync(obits) == CVM_LOCKSTATE_LOCKED) { CVMOwnedMonitor *o = (CVMOwnedMonitor *)CVMhdrBitsPtr(obits); CVMExecEnv *owner = o->owner;#ifdef CVM_DEBUG CVMassert(o->magic == CVM_OWNEDMON_MAGIC);#endif CVMassert(o->type == CVM_OWNEDMON_FAST); if (owner != ee) { /* set mutex ownership */ CVMprofiledMonitorGetCount(&mon->mon) = reentryCount; CVMprofiledMonitorGetOwner(&mon->mon) = owner;#ifdef CVM_THREAD_BOOST#ifdef CVM_DEBUG mon->boostThread = owner;#endif /* Request priority boosting on owner thread so that it can claim actual ownership of this monitor: */ CVMassert(!mon->boost); mon->boost = CVM_TRUE;#else /* !CVM_THREAD_BOOST */ CVMprofiledMonitorSetMutexOwner(&mon->mon, ee, owner);#ifdef CVM_DEBUG_ASSERTS { CVMBool success = CVMprofiledMonitorTryEnter(&mon->mon, ee); CVMassert(!success); }#endif /* CVM_DEBUG */#endif /* !CVM_THREAD_BOOST */ } else { CVMBool success = CVMprofiledMonitorTryEnter(&mon->mon, ee); CVMassert(success); (void) success; CVMassert(CVMprofiledMonitorGetCount(&mon->mon) == 1); CVMprofiledMonitorGetCount(&mon->mon) = reentryCount; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?