1 /* src/threads/native/lock.c - lock implementation
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
30 Changes: Christian Thalinger
32 $Id: threads.c 4903 2006-05-11 12:48:43Z edwin $
45 #include "mm/memory.h"
47 #include "vm/global.h"
48 #include "vm/exceptions.h"
49 #include "vm/stringlocal.h"
51 /* arch.h must be here because it defines USE_FAKE_ATOMIC_INSTRUCTIONS */
55 /* includes for atomic instructions: */
57 #if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
58 #include "threads/native/generic-primitives.h"
60 #include "machine-instr.h"
64 /******************************************************************************/
66 /******************************************************************************/
68 /* number of lock records in the first pool allocated for a thread */
69 #define INITIALLOCKRECORDS 8
72 /* CAUTION: oldvalue is evaluated twice! */
73 #define COMPARE_AND_SWAP_SUCCEEDS(address, oldvalue, newvalue) \
74 (compare_and_swap((long *)(address), (long)(oldvalue), (long)(newvalue)) == (long)(oldvalue))
77 /******************************************************************************/
78 /* GLOBAL VARIABLES */
79 /******************************************************************************/
81 /* global lock record pool list header */
82 lock_record_pool_t *lock_global_pool;
84 /* mutex for synchronizing access to the global pool */
85 pthread_mutex_t lock_global_pool_lock;
89 /*============================================================================*/
90 /* INITIALIZATION OF DATA STRUCTURES */
91 /*============================================================================*/
94 /* lock_init *******************************************************************
96 Initialize global data for locking.
98 *******************************************************************************/
102 pthread_mutex_init(&lock_global_pool_lock, NULL);
106 /* lock_record_init ************************************************************
108 Initialize a lock record.
111 r............the lock record to initialize
112 t............will become the owner
114 *******************************************************************************/
116 static void lock_record_init(lock_record_t *r, threadobject *t)
126 pthread_mutex_init(&(r->mutex), NULL);
130 /* lock_init_execution_env *****************************************************
132 Initialize the execution environment for a thread.
135 thread.......the thread
137 *******************************************************************************/
139 void lock_init_execution_env(threadobject *thread)
141 thread->ee.firstfree = NULL;
142 thread->ee.lockrecordpools = NULL;
143 thread->ee.lockrecordcount = 0;
148 /*============================================================================*/
149 /* LOCK RECORD MANAGEMENT */
150 /*============================================================================*/
153 /* lock_record_alloc_new_pool **************************************************
155 Get a new lock record pool from the memory allocator.
158 thread.......the thread that will own the lock records
159 size.........number of lock records in the pool to allocate
162 the new lock record pool, with initialized lock records
164 *******************************************************************************/
166 static lock_record_pool_t *lock_record_alloc_new_pool(threadobject *thread, int size)
169 lock_record_pool_t *pool;
171 /* get the pool from the memory allocator */
173 pool = mem_alloc(sizeof(lock_record_pool_header_t)
174 + sizeof(lock_record_t) * size);
176 /* initialize the pool header */
178 pool->header.size = size;
180 /* initialize the individual lock records */
182 for (i=0; i<size; i++) {
183 lock_record_init(&pool->lr[i], thread);
185 pool->lr[i].nextfree = &pool->lr[i+1];
188 /* terminate free list */
190 pool->lr[i-1].nextfree = NULL;
196 /* lock_record_alloc_pool ******************************************************
198 Allocate a lock record pool. The pool is either taken from the global free
199 list or requested from the memory allocator.
202 thread.......the thread that will own the lock records
203 size.........number of lock records in the pool to allocate
206 the new lock record pool, with initialized lock records
208 *******************************************************************************/
210 static lock_record_pool_t *lock_record_alloc_pool(threadobject *t, int size)
212 pthread_mutex_lock(&lock_global_pool_lock);
214 if (lock_global_pool) {
216 lock_record_pool_t *pool;
218 /* pop a pool from the global freelist */
220 pool = lock_global_pool;
221 lock_global_pool = pool->header.next;
223 pthread_mutex_unlock(&lock_global_pool_lock);
225 /* re-initialize owner and freelist chaining */
227 for (i=0; i < pool->header.size; i++) {
228 pool->lr[i].owner = NULL;
229 pool->lr[i].nextfree = &pool->lr[i+1];
231 pool->lr[i-1].nextfree = NULL;
236 pthread_mutex_unlock(&lock_global_pool_lock);
238 /* we have to get a new pool from the allocator */
240 return lock_record_alloc_new_pool(t, size);
244 /* lock_record_free_pools ******************************************************
246 Free the lock record pools in the given linked list. The pools are inserted
247 into the global freelist.
250 pool.........list header
252 *******************************************************************************/
254 void lock_record_free_pools(lock_record_pool_t *pool)
256 lock_record_pool_header_t *last;
261 pthread_mutex_lock(&lock_global_pool_lock);
263 /* find the last pool in the list */
265 last = &pool->header;
267 last = &last->next->header;
269 /* chain it to the lock_global_pool freelist */
271 last->next = lock_global_pool;
273 /* insert the freed pools into the freelist */
275 lock_global_pool = pool;
277 pthread_mutex_unlock(&lock_global_pool_lock);
281 /* lock_record_alloc ***********************************************************
283 Allocate a lock record which is owned by the given thread.
286 t............the thread
288 *******************************************************************************/
290 static lock_record_t *lock_record_alloc(threadobject *t)
299 lock_record_pool_t *pool;
303 poolsize = t->ee.lockrecordcount ? t->ee.lockrecordcount * 2 : INITIALLOCKRECORDS;
304 pool = lock_record_alloc_pool(t, poolsize);
306 /* add it to our per-thread pool list */
308 pool->header.next = t->ee.lockrecordpools;
309 t->ee.lockrecordpools = pool;
310 t->ee.lockrecordcount += pool->header.size;
312 /* take the first record from the pool */
316 /* pop the record from the freelist */
318 t->ee.firstfree = r->nextfree;
320 r->nextfree = NULL; /* in order to find invalid uses of nextfree */
326 /* lock_record_recycle *********************************************************
328 Recycle the given lock record. It will be inserted in the appropriate
332 t............the owner
333 r............lock record to recycle
335 *******************************************************************************/
337 static inline void lock_record_recycle(threadobject *t, lock_record_t *r)
341 assert(r->owner == NULL);
342 assert(r->nextfree == NULL);
344 r->nextfree = t->ee.firstfree;
350 /*============================================================================*/
351 /* OBJECT LOCK INITIALIZATION */
352 /*============================================================================*/
355 /* lock_init_object_lock *******************************************************
357 Initialize the monitor pointer of the given object. The monitor gets
358 initialized to an unlocked state.
360 *******************************************************************************/
362 void lock_init_object_lock(java_objectheader *o)
366 o->monitorPtr = NULL;
370 /* lock_get_initial_lock_word **************************************************
372 Returns the initial (unlocked) lock word. The pointer is
373 required in the code generator to set up a virtual
374 java_objectheader for code patch locking.
376 *******************************************************************************/
378 lock_record_t *lock_get_initial_lock_word(void)
385 /*============================================================================*/
386 /* LOCKING ALGORITHM */
387 /*============================================================================*/
390 /* lock_inflate ****************************************************************
392 Inflate the lock of the given object.
395 t............the current thread
396 o............the object of which to inflate the lock
399 the new lock record of the object
401 *******************************************************************************/
403 static lock_record_t *lock_inflate(threadobject *t, java_objectheader *o)
407 /* allocate a fat lock */
409 lr = lock_record_alloc(t);
411 /* We try to install this fat lock... */
413 if (COMPARE_AND_SWAP_SUCCEEDS(&(o->monitorPtr), NULL, lr))
416 /* The CAS failed. That means another thread inflated the lock. */
417 /* It won't change anymore, so we can read it in a relaxed way. */
419 lock_record_recycle(t, lr);
420 return o->monitorPtr;
424 /* lock_monitor_enter **********************************************************
426 Acquire the monitor of the given object. If the current thread already
427 owns the monitor, the lock counter is simply increased.
429 This function blocks until it can acquire the monitor.
432 t............the current thread
433 o............the object of which to enter the monitor
436 the new lock record of the object when it has been entered
438 *******************************************************************************/
440 lock_record_t *lock_monitor_enter(threadobject *t, java_objectheader *o)
444 /* get the lock record for this object */
445 /* inflate the lock if it is not already fat */
446 if ((lr = o->monitorPtr) == NULL) {
447 lr = lock_inflate(t, o);
450 /* check for recursive entering */
451 /* We don't have to worry about stale values here, as any stale value */
452 /* will be != t and thus fail this check. */
453 if (lr->owner == t) {
458 /* acquire the mutex of the lock record */
459 pthread_mutex_lock(&(lr->mutex));
461 /* enter us as the owner */
464 assert(lr->count == 0);
470 /* lock_monitor_exit *****************************************************************
472 Decrement the counter of a (currently owned) monitor. If the counter
473 reaches zero, release the monitor.
475 If the current thread is not the owner of the monitor, an
476 IllegalMonitorState exception is thrown.
479 t............the current thread
480 o............the object of which to exit the monitor
483 true.........everything ok,
484 false........an exception has been thrown
486 *******************************************************************************/
488 bool lock_monitor_exit(threadobject *t, java_objectheader *o)
494 /* check if we own this monitor */
495 /* We don't have to worry about stale values here, as any stale value */
496 /* will be != t and thus fail this check. */
498 if (!lr || lr->owner != t) {
499 *exceptionptr = new_illegalmonitorstateexception();
503 /* { the current thread `t` owns the lock record `lr` on object `o` } */
505 if (lr->count != 0) {
506 /* we had locked this one recursively. just decrement, it will */
507 /* still be locked. */
512 /* unlock this lock record */
515 pthread_mutex_unlock(&(lr->mutex));
521 /* lock_record_remove_waiter *********************************************************
523 Remove a thread from the list of waiting threads of a lock record.
526 lr...........the lock record
527 t............the current thread
530 The current thread must be the owner of the lock record.
532 *******************************************************************************/
534 void lock_record_remove_waiter(lock_record_t *lr, threadobject *t)
536 lock_waiter_t **link;
539 link = &(lr->waiters);
540 while ((w = *link)) {
541 if (w->waiter == t) {
549 /* this should never happen */
550 fprintf(stderr,"error: waiting thread not found in list of waiters\n");
556 /* lock_monitor_wait *****************************************************************
558 Wait on an object for a given (maximum) amount of time.
561 t............the current thread
562 o............the object
563 millis.......milliseconds of timeout
564 nanos........nanoseconds of timeout
567 The current thread must be the owner of the object's monitor.
569 *******************************************************************************/
571 void lock_monitor_wait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
574 lock_waiter_t *waiter;
580 /* check if we own this monitor */
581 /* We don't have to worry about stale values here, as any stale value */
582 /* will be != t and thus fail this check. */
584 if (!lr || lr->owner != t) {
585 *exceptionptr = new_illegalmonitorstateexception();
589 /* { the thread t owns the lock record lr on the object o } */
591 /* register us as waiter for this object */
593 waiter = NEW(lock_waiter_t);
595 waiter->next = lr->waiters;
596 lr->waiters = waiter;
598 /* remember the old lock count */
600 lockcount = lr->count;
602 /* unlock this record */
606 pthread_mutex_unlock(&(lr->mutex));
608 /* wait until notified/interrupted/timed out */
610 wasinterrupted = threads_wait_with_timeout_relative(t, millis, nanos);
612 /* re-enter the monitor */
614 lr = lock_monitor_enter(t, o);
616 /* remove us from the list of waiting threads */
618 lock_record_remove_waiter(lr, t);
620 /* restore the old lock count */
622 lr->count = lockcount;
624 /* if we have been interrupted, throw the appropriate exception */
627 *exceptionptr = new_exception(string_java_lang_InterruptedException);
631 /* lock_monitor_notify **************************************************************
633 Notify one thread or all threads waiting on the given object.
636 t............the current thread
637 o............the object
638 one..........if true, only notify one thread
641 The current thread must be the owner of the object's monitor.
643 *******************************************************************************/
645 static void lock_monitor_notify(threadobject *t, java_objectheader *o, bool one)
648 lock_waiter_t *waiter;
649 threadobject *waitingthread;
653 /* check if we own this monitor */
654 /* We don't have to worry about stale values here, as any stale value */
655 /* will be != t and thus fail this check. */
657 if (!lr || lr->owner != t) {
658 *exceptionptr = new_illegalmonitorstateexception();
662 /* { the thread t owns the lock record lr on the object o } */
664 /* for each waiter: */
666 for (waiter = lr->waiters; waiter; waiter = waiter->next) {
668 /* signal the waiting thread */
670 waitingthread = waiter->waiter;
672 pthread_mutex_lock(&waitingthread->waitmutex);
673 if (waitingthread->sleeping)
674 pthread_cond_signal(&waitingthread->waitcond);
675 waitingthread->signaled = true;
676 pthread_mutex_unlock(&waitingthread->waitmutex);
678 /* if we should only wake one, we are done */
687 /*============================================================================*/
688 /* INQUIRY FUNCIONS */
689 /*============================================================================*/
692 /* lock_does_thread_hold_lock **************************************************
694 Return true if the given thread owns the monitor of the given object.
697 t............the thread
698 o............the object
701 true, if the thread is locking the object
703 *******************************************************************************/
705 bool lock_does_thread_hold_lock(threadobject *t, java_objectheader *o)
711 return (lr && lr->owner == t);
716 /*============================================================================*/
717 /* WRAPPERS FOR OPERATIONS ON THE CURRENT THREAD */
718 /*============================================================================*/
721 /* lock_wait_for_object ********************************************************
723 Wait for the given object.
726 o............the object
727 millis.......milliseconds to wait
728 nanos........nanoseconds to wait
730 *******************************************************************************/
732 void lock_wait_for_object(java_objectheader *o, s8 millis, s4 nanos)
734 threadobject *t = (threadobject*) THREADOBJECT;
735 lock_monitor_wait(t, o, millis, nanos);
739 /* lock_notify_object **********************************************************
741 Notify one thread waiting on the given object.
744 o............the object
746 *******************************************************************************/
748 void lock_notify_object(java_objectheader *o)
750 threadobject *t = (threadobject*) THREADOBJECT;
751 lock_monitor_notify(t, o, true);
755 /* lock_notify_all_object ******************************************************
757 Notify all threads waiting on the given object.
760 o............the object
762 *******************************************************************************/
764 void lock_notify_all_object(java_objectheader *o)
766 threadobject *t = (threadobject*) THREADOBJECT;
767 lock_monitor_notify(t, o, false);
771 * These are local overrides for various environment variables in Emacs.
772 * Please do not remove this and leave it at the end of the file, where
773 * Emacs will automagically detect them.
774 * ---------------------------------------------------------------------
777 * indent-tabs-mode: t
781 * vim:noexpandtab:sw=4:ts=4: