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 + -
显示快捷键?