locks.c
来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 521 行
C
521 行
/* * locks.c * Manage locking system * * Copyright (c) 1996-1999 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "config.h"#include "config-std.h"#include "object.h"#include "classMethod.h"#include "baseClasses.h"#include "thread.h"#include "locks.h"#include "ksem.h"#include "errors.h"#include "exception.h"#include "md.h"#include "jthread.h"#include "debug.h"#include "gc.h"#include "jvmpi_kaffe.h"/* * If we don't have an atomic compare and exchange defined then make * one out of a simple atomic exchange (using the LOCKINPROGRESS value * as the place holder). If we don't have ATOMIC_EXCHANGE, we'll just * fake it. */#if !defined(COMPARE_AND_EXCHANGE)#if defined(ATOMIC_EXCHANGE)#define COMPARE_AND_EXCHANGE(A,O,N) \ ({ \ iLock* val = LOCKINPROGRESS; \ ATOMIC_EXCHANGE((A), val); \ if (val == (O)) { \ *(A) = (N); \ } \ else { \ *(A) = (O); \ } \ (val == (O) ? 1 : 0); \ })#else#error Please define COMPARE_AND_EXCHANGE or ATOMIC_EXCHANGE #endif#endif/* Count number of backoffs. XXX move into the STAT infrastructure. */int backoffcount = 0;/* * Initialise the locking system. */voidinitLocking(void){}#if defined(KAFFE_VMDEBUG)voiddumpObjectLocks(void){}#endif/* * Get a heavy lock for the object and hold it. If the object doesn't * have a heavy lock then we create one. */staticiLock*getHeavyLock(iLock** lkp, iLock *heavyLock){ iLock* old; iLock* lk; jlong timeout;DBG(SLOWLOCKS, dprintf(" getHeavyLock(**lkp=%p, *lk=%p, th=%p)\n", lkp, *lkp, jthread_current());) lk = heavyLock; timeout = 1; for (;;) { /* Get the current lock and replace it with LOCKINPROGRESS to indicate * changes are in progress. */ old = *lkp; if (old == LOCKINPROGRESS || !COMPARE_AND_EXCHANGE(lkp, old, LOCKINPROGRESS)) { /* Someone else put the lock in LOCKINPROGRESS state */ backoffcount++; ksemGet(&THREAD_DATA()->sem, timeout); /* Back off */ timeout = (timeout << 1)|timeout; continue; } /* If bottom bit is set, strip off and use pointer as pointer to heavy lock */ if ((((uintp)old) & 1) == 1) {DBG(SLOWLOCKS, dprintf(" got cached lock\n");) if (lk != heavyLock) { gc_free (lk); } lk = (iLock*)(((uintp)old) & (uintp)-2); } else { if (lk == 0) { /* Release the lock before we go into malloc. * We have to reclaim the lock afterwards (at beginning * of loop) */ *lkp = old; lk = (iLock*)gc_malloc(sizeof(iLock), GC_ALLOC_LOCK); /* if that fails we're in trouble!! */ assert(lk != 0); continue; }DBG(SLOWLOCKS, dprintf(" got %s lock\n", (lk != heavyLock) ? "new" : "special");) lk->holder = (void*)old; lk->mux = 0; lk->cv = 0; } return (lk); }}/* * Release the lock - only the one who has claimed it can do this * so there's no need for locked instructions. */staticvoidputHeavyLock(iLock** lkp, iLock* lk){ assert(*lkp == LOCKINPROGRESS);DBG(SLOWLOCKS, dprintf(" putHeavyLock(**lkp=%p, *lk=%p, th=%p)\n", lkp, lk, jthread_current());) if (lk == LOCKFREE) { *lkp = LOCKFREE; } else { *lkp = (iLock*)(1|(uintp)lk); }}/* * Slowly lock a mutex. We get the heavy lock and lock that instead. * If we can't lock it we suspend until we can. */static voidslowLockMutex(iLock** lkp, void* where, iLock *heavyLock){ iLock* lk; jthread_t cur = jthread_current ();DBG(SLOWLOCKS, dprintf("slowLockMutex(**lkp=%p, where=%p, th=%p)\n", lkp, where, jthread_current());) jthread_disable_stop(); /* protect the heavy lock, and its queues */ for (;;) { lk = getHeavyLock(lkp, heavyLock); /* If I hold the heavy lock then just keep on going */ if (jthread_on_current_stack(lk->holder)) { putHeavyLock(lkp, lk); jthread_enable_stop(); return; } /* If no one holds the heavy lock then claim it */ if (lk->holder == 0) { lk->holder = where; putHeavyLock(lkp, lk); jthread_enable_stop(); return; } /* Otherwise wait for holder to release it */ jthread_get_data(cur)->nextlk = lk->mux; lk->mux = cur; putHeavyLock(lkp, lk); ksemGet(&jthread_get_data(cur)->sem, 0); }}/* * Slowly unlock a mutex. If there's someone waiting then we wake them up * so they can claim the lock. If no one is waiting we revert the lock to * a fast thin lock. */static voidslowUnlockMutex(iLock** lkp, void* where, iLock *heavyLock){ iLock* lk; jthread_t tid;DBG(SLOWLOCKS, dprintf("slowUnlockMutex(**lkp=%p, where=%p, th=%p)\n", lkp, where, jthread_current());) jthread_disable_stop(); /* protect the heavy lock, and its queues */ lk = getHeavyLock(lkp, heavyLock); /* Only the lock holder can be doing an unlock */ if (!jthread_on_current_stack(lk->holder)) { putHeavyLock(lkp, lk); jthread_enable_stop(); throwException(IllegalMonitorStateException); } /* If holder isn't where we are now then this isn't the final unlock */#if defined(STACK_GROWS_UP) if (lk->holder < where) {#else if (lk->holder > where) {#endif putHeavyLock(lkp, lk); jthread_enable_stop(); return; } /* Final unlock - if someone is waiting for it now would be a good * time to tell them. */ if (lk->mux != 0) { tid = lk->mux; lk->mux = jthread_get_data(tid)->nextlk; jthread_get_data(tid)->nextlk = 0; lk->holder = 0; putHeavyLock(lkp, lk); ksemPut(&jthread_get_data(tid)->sem); } /* If someone's waiting to be signaled keep the heavy in place */ else if (lk->cv != 0) { lk->holder = 0; putHeavyLock(lkp, lk); } else { if (lk != heavyLock) { gc_free(lk); } putHeavyLock(lkp, LOCKFREE); } jthread_enable_stop();}voidlocks_internal_slowUnlockMutexIfHeld(iLock** lkp, void* where, iLock *heavyLock){ iLock* lk; void* holder;DBG(SLOWLOCKS, dprintf("slowUnlockMutexIfHeld(**lkp=%p, where=%p, th=%p)\n", lkp, where, jthread_current());) holder = *lkp; /* nothing to do if the lock is free */ if (holder == LOCKFREE) { return; } /* if it's a thin lock and this thread owns it, * try to free it the easy way */ if (jthread_on_current_stack(holder) && COMPARE_AND_EXCHANGE(lkp, holder, LOCKFREE)) { return; } /* ok, it is a heavy lock */ lk = getHeavyLock(lkp, heavyLock); holder = lk->holder; putHeavyLock(lkp, lk); if (jthread_on_current_stack(holder)) { slowUnlockMutex(lkp, where, heavyLock); }}jbooleanlocks_internal_waitCond(iLock** lkp, jlong timeout, iLock *heavyLock){ iLock* lk; void* holder; jthread_t cur = jthread_current(); jthread_t *ptr; jboolean r;DBG(SLOWLOCKS, dprintf("_waitCond(**lkp=%p, timeout=%ld, th=%p)\n", lkp, (long)timeout, jthread_current());) lk = getHeavyLock(lkp, heavyLock); holder = lk->holder; /* I must be holding the damn thing */ if (!jthread_on_current_stack(holder)) { putHeavyLock(lkp, holder); throwException(IllegalMonitorStateException); } jthread_get_data(cur)->nextlk = lk->cv; lk->cv = cur; putHeavyLock(lkp, lk); slowUnlockMutex(lkp, holder, heavyLock); r = ksemGet(&jthread_get_data(cur)->sem, timeout); /* Timeout */ if (r == false) { lk = getHeavyLock(lkp, heavyLock); /* Remove myself from CV or MUX queue - if I'm * not on either * then I should wait on myself to remove any pending signal. */ for (ptr = &lk->cv; *ptr != 0; ptr = &jthread_get_data(*ptr)->nextlk) { if ((*ptr) == cur) { *ptr = jthread_get_data(cur)->nextlk; goto found; } } for (ptr = &lk->mux; *ptr != 0; ptr = &jthread_get_data(*ptr)->nextlk) { if ((*ptr) == cur) { *ptr = jthread_get_data(cur)->nextlk; goto found; } } /* Not on list - so must have been signalled after all - * decrease the semaphore to avoid problems. */ ksemGet(&jthread_get_data(cur)->sem, 0); found:; putHeavyLock(lkp, lk); } slowLockMutex(lkp, holder, heavyLock); return (r);}voidlocks_internal_signalCond(iLock** lkp, iLock *heavyLock){ iLock* lk; jthread_t tid;DBG(SLOWLOCKS, dprintf("_signalCond(**lkp=%p, th=%p)\n", lkp, jthread_current());) lk = getHeavyLock(lkp, heavyLock); if (!jthread_on_current_stack(lk->holder)) { putHeavyLock(lkp, lk); throwException(IllegalMonitorStateException); } /* Move one CV's onto the MUX */ tid = lk->cv; if (tid != 0) { lk->cv = jthread_get_data(tid)->nextlk; jthread_get_data(tid)->nextlk = lk->mux; lk->mux = tid; } putHeavyLock(lkp, lk);}voidlocks_internal_broadcastCond(iLock** lkp, iLock *heavyLock){ iLock* lk; jthread_t tid;DBG(SLOWLOCKS, dprintf("_broadcastCond(**lkp=%p, th=%p)\n", lkp, jthread_current());) lk = getHeavyLock(lkp, heavyLock); if (!jthread_on_current_stack(lk->holder)) { putHeavyLock(lkp, lk); throwException(IllegalMonitorStateException); } /* Move all the CV's onto the MUX */ while (lk->cv != 0) { tid = lk->cv; lk->cv = jthread_get_data(tid)->nextlk; jthread_get_data(tid)->nextlk = lk->mux; lk->mux = tid; } putHeavyLock(lkp, lk);}/* * Lock a mutex - try to do this quickly but if we failed because * we can't determine if this is a multiple entry lock or we've got * contention then fall back on a slow lock. */voidlocks_internal_lockMutex(iLock** lkp, void* where, iLock *heavyLock){ uintp val; val = (uintp)*lkp; if (val == 0) { if (!COMPARE_AND_EXCHANGE(lkp, 0, (iLock*)where)) { slowLockMutex(lkp, where, heavyLock); } } else if (!jthread_on_current_stack((void *)val)) { /* XXX count this in the stats area */ slowLockMutex(lkp, where, heavyLock); }}/* * Unlock a mutex - try to do this quickly but if we failed then * we've got contention so fall back on a slow lock. */voidlocks_internal_unlockMutex(iLock** lkp, void* where, iLock *heavyLock){ uintp val; val = (uintp)*lkp; if ((val & 1) != 0) { slowUnlockMutex(lkp, where, heavyLock); } else if ((val == (uintp)where) /* XXX squirrely bit */ && !COMPARE_AND_EXCHANGE(lkp, (iLock*)where, LOCKFREE)) { slowUnlockMutex(lkp, where, heavyLock); }}voidlockObject(Hjava_lang_Object* obj){ locks_internal_lockMutex(&obj->lock, &obj, 0);}voidunlockObject(Hjava_lang_Object* obj){ locks_internal_unlockMutex(&obj->lock, &obj, 0);}voidslowLockObject(Hjava_lang_Object* obj, void* where){#if defined(ENABLE_JVMPI) if( JVMPI_EVENT_ISENABLED(JVMPI_EVENT_MONITOR_CONTENDED_ENTER) ) { JVMPI_Event ev; ev.event_type = JVMPI_EVENT_MONITOR_CONTENDED_ENTER; ev.u.monitor.object = obj; jvmpiPostEvent(&ev); }#endif slowLockMutex(&obj->lock, where, 0);#if defined(ENABLE_JVMPI) if( JVMPI_EVENT_ISENABLED(JVMPI_EVENT_MONITOR_CONTENDED_ENTERED) ) { JVMPI_Event ev; ev.event_type = JVMPI_EVENT_MONITOR_CONTENDED_ENTERED; ev.u.monitor.object = obj; jvmpiPostEvent(&ev); }#endif}voidslowUnlockObject(Hjava_lang_Object* obj, void* where){#if defined(ENABLE_JVMPI) if( JVMPI_EVENT_ISENABLED(JVMPI_EVENT_MONITOR_CONTENDED_EXIT) ) { JVMPI_Event ev; ev.event_type = JVMPI_EVENT_MONITOR_CONTENDED_EXIT; ev.u.monitor.object = obj; jvmpiPostEvent(&ev); }#endif slowUnlockMutex(&obj->lock, where, 0);}voiddumpLocks(void){}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?