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
29 Changes: Christian Thalinger
32 $Id: threads.c 4903 2006-05-11 12:48:43Z edwin $
39 /* XXX cleanup these includes */
44 #include <sys/types.h>
52 #include <semaphore.h>
58 #ifndef USE_MD_THREAD_STUFF
59 #include "machine-instr.h"
61 #include "threads/native/generic-primitives.h"
65 #include "mm/memory.h"
66 #include "native/native.h"
67 #include "native/include/java_lang_Object.h"
68 #include "native/include/java_lang_Throwable.h"
69 #include "native/include/java_lang_Thread.h"
70 #include "native/include/java_lang_ThreadGroup.h"
71 #include "native/include/java_lang_VMThread.h"
72 #include "threads/native/threads.h"
73 #include "toolbox/avl.h"
74 #include "toolbox/logging.h"
75 #include "vm/builtin.h"
76 #include "vm/exceptions.h"
77 #include "vm/global.h"
78 #include "vm/loader.h"
79 #include "vm/options.h"
80 #include "vm/stringlocal.h"
82 #include "vm/jit/asmpart.h"
84 #if !defined(__DARWIN__)
85 #if defined(__LINUX__)
86 #define GC_LINUX_THREADS
87 #elif defined(__MIPS__)
88 #define GC_IRIX_THREADS
90 #include "boehm-gc/include/gc.h"
93 #ifdef USE_MD_THREAD_STUFF
94 pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
95 pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
96 pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
100 /******************************************************************************/
102 /******************************************************************************/
104 #define INITIALLOCKRECORDS 8
106 #define GRAB_LR(lr,t) \
107 if (lr->owner != t) { \
111 #define CHECK_MONITORSTATE(lr,t,mo,a) \
112 if (lr->o != mo || lr->owner != t) { \
113 *exceptionptr = new_illegalmonitorstateexception(); \
118 /******************************************************************************/
119 /* GLOBAL VARIABLES */
120 /******************************************************************************/
122 /* unlocked dummy record - avoids NULL checks */
123 static lock_record_t *dummyLR;
125 pthread_mutex_t lock_global_pool_lock;
126 lock_record_pool_t *lock_global_pool;
129 /* lock_init *******************************************************************
131 Initialize global data for locking.
133 *******************************************************************************/
137 pthread_mutex_init(&lock_global_pool_lock, NULL);
139 /* Every newly created object's monitorPtr points here so we save
140 a check against NULL */
142 dummyLR = NEW(lock_record_t);
144 dummyLR->owner = NULL;
145 dummyLR->waiting = NULL;
146 dummyLR->incharge = dummyLR;
150 /* lock_record_init ************************************************************
152 Initialize a lock record.
155 r............the lock record to initialize
156 t............will become the owner
158 *******************************************************************************/
160 static void lock_record_init(lock_record_t *r, threadobject *t)
167 r->incharge = (lock_record_t *) &dummyLR;
169 threads_sem_init(&r->queueSem, 0, 0);
170 pthread_mutex_init(&r->resolveLock, NULL);
171 pthread_cond_init(&r->resolveWait, NULL);
175 /* lock_init_thread_lock_record_pool *******************************************
177 Initialize the lock record pool(s) for a thread.
180 thread.......the thread
182 *******************************************************************************/
184 void lock_init_thread_lock_record_pool(threadobject *thread)
186 thread->ee.firstLR = NULL;
187 thread->ee.lrpool = NULL;
188 thread->ee.numlr = 0;
192 /* lock_record_alloc_new_pool **************************************************
194 Get a new lock record pool from the memory allocator.
197 thread.......the thread that will own the lock records
198 size.........number of lock records in the pool to allocate
201 the new lock record pool, with initialized lock records
203 *******************************************************************************/
205 static lock_record_pool_t *lock_record_alloc_new_pool(threadobject *thread, int size)
207 lock_record_pool_t *p = mem_alloc(sizeof(lock_record_pool_header_t)
208 + sizeof(lock_record_t) * size);
211 p->header.size = size;
212 for (i=0; i<size; i++) {
213 lock_record_init(&p->lr[i], thread);
214 p->lr[i].nextFree = &p->lr[i+1];
216 p->lr[i-1].nextFree = NULL;
221 /* lock_record_alloc_pool ******************************************************
223 Allocate a lock record pool. The pool is either taken from the global free
224 list or requested from the memory allocator.
227 thread.......the thread that will own the lock records
228 size.........number of lock records in the pool to allocate
231 the new lock record pool, with initialized lock records
233 *******************************************************************************/
235 static lock_record_pool_t *lock_record_alloc_pool(threadobject *t, int size)
237 pthread_mutex_lock(&lock_global_pool_lock);
238 if (lock_global_pool) {
240 lock_record_pool_t *pool = lock_global_pool;
241 lock_global_pool = pool->header.next;
242 pthread_mutex_unlock(&lock_global_pool_lock);
244 for (i=0; i < pool->header.size; i++) {
245 pool->lr[i].owner = t;
246 pool->lr[i].nextFree = &pool->lr[i+1];
248 pool->lr[i-1].nextFree = NULL;
252 pthread_mutex_unlock(&lock_global_pool_lock);
254 return lock_record_alloc_new_pool(t, size);
258 /* lock_record_free_pools ******************************************************
260 Free the lock record pools in the given linked list.
263 pool.........list header
265 *******************************************************************************/
267 void lock_record_free_pools(lock_record_pool_t *pool)
269 lock_record_pool_header_t *last;
270 pthread_mutex_lock(&lock_global_pool_lock);
271 last = &pool->header;
273 last = &last->next->header;
274 last->next = lock_global_pool;
275 lock_global_pool = pool;
276 pthread_mutex_unlock(&lock_global_pool_lock);
280 /* lock_record_alloc ***********************************************************
282 Allocate a lock record which is owned by the given thread.
285 t............the thread
287 *******************************************************************************/
289 static lock_record_t *lock_record_alloc(threadobject *t)
297 int poolsize = t->ee.numlr ? t->ee.numlr * 2 : INITIALLOCKRECORDS;
298 lock_record_pool_t *pool = lock_record_alloc_pool(t, poolsize);
299 pool->header.next = t->ee.lrpool;
302 t->ee.numlr += pool->header.size;
305 t->ee.firstLR = r->nextFree;
307 r->nextFree = NULL; /* in order to find invalid uses of nextFree */
313 /* lock_record_recycle *********************************************************
315 Recycle the given lock record. It will be inserted in the appropriate
319 t............the owner
320 r............lock record to recycle
322 *******************************************************************************/
324 static inline void lock_record_recycle(threadobject *t, lock_record_t *r)
328 assert(r->owner == t);
329 assert(r->nextFree == NULL);
331 r->nextFree = t->ee.firstLR;
336 /* lock_init_object_lock *******************************************************
338 Initialize the monitor pointer of the given object. The monitor gets
339 initialized to an unlocked state.
341 *******************************************************************************/
343 void lock_init_object_lock(java_objectheader *o)
347 o->monitorPtr = dummyLR;
351 /* lock_get_initial_lock_word **************************************************
353 Returns the global dummy monitor lock record. The pointer is
354 required in the code generator to set up a virtual
355 java_objectheader for code patch locking.
357 *******************************************************************************/
359 lock_record_t *lock_get_initial_lock_word(void)
365 /* lock_queue_on_lock_record ***************************************************
367 Suspend the current thread and queue it on the given lock record.
369 *******************************************************************************/
371 static void lock_queue_on_lock_record(lock_record_t *lr, java_objectheader *o)
373 atomic_add(&lr->queuers, 1);
374 MEMORY_BARRIER_AFTER_ATOMIC();
377 threads_sem_wait(&lr->queueSem);
379 atomic_add(&lr->queuers, -1);
383 /* lock_record_release *********************************************************
385 Release the lock held by the given lock record. Threads queueing on the
386 semaphore of the record will be woken up.
388 *******************************************************************************/
390 static void lock_record_release(lock_record_t *lr)
397 threads_sem_post(&lr->queueSem);
401 static inline void lock_handle_waiter(lock_record_t *newlr,
402 lock_record_t *curlr,
403 java_objectheader *o)
405 /* if the current lock record is used for waiting on the object */
406 /* `o`, then record it as a waiter in the new lock record */
408 if (curlr->waiting == o)
409 newlr->waiter = curlr;
413 /* lock_monitor_enter ****************************************************************
415 Acquire the monitor of the given object. If the current thread already
416 owns the monitor, the lock counter is simply increased.
418 This function blocks until it can acquire the monitor.
421 t............the current thread
422 o............the object of which to enter the monitor
425 the new lock record of the object when it has been entered
427 *******************************************************************************/
429 lock_record_t *lock_monitor_enter(threadobject *t, java_objectheader *o)
432 lock_record_t *lr = o->monitorPtr;
434 /* the lock record does not lock this object */
438 /* allocate a new lock record for this object */
439 mlr = lock_record_alloc(t);
442 /* check if it is the same record the object refered to earlier */
447 /* the object still refers to the same lock record */
449 lock_handle_waiter(mlr, lr, o);
454 /* no, it's another lock record */
455 /* if we don't own the old record, set incharge XXX */
459 /* if the object still refers to lr, replace it by the new mlr */
460 MEMORY_BARRIER_BEFORE_ATOMIC();
461 nlr = (lock_record_t *) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) mlr);
465 /* we swapped the new record in successfully */
466 if (mlr == lr || lr->o != o) {
467 /* the old lock record is the same as the new one, or */
468 /* it locks another object. */
470 lock_handle_waiter(mlr, lr, o);
473 /* lr locks the object, we have to wait */
475 lock_queue_on_lock_record(lr, o);
478 lock_handle_waiter(mlr, lr, o);
482 /* forget this mlr lock record, wait on nlr and try again */
483 lock_record_release(mlr);
484 lock_record_recycle(t, mlr);
485 lock_queue_on_lock_record(nlr, o);
488 /* the lock record is for the object we want */
490 if (lr->owner == t) {
491 /* we own it already, just recurse */
496 /* it's locked. we wait and then try again */
497 lock_queue_on_lock_record(lr, o);
503 /* lock_wake_waiters ********************************************************
505 For each lock record in the given waiter list, post the queueSem
506 once for each queuer of the lock record.
509 lr...........the head of the waiter list
511 *******************************************************************************/
513 static void lock_wake_waiters(lock_record_t *lr)
515 lock_record_t *tmplr;
518 /* move it to a local variable (Stefan commented this especially.
519 * Might be important somehow...) */
527 threads_sem_post(&tmplr->queueSem);
529 tmplr = tmplr->waiter;
530 } while (tmplr != NULL && tmplr != lr); /* this breaks cycles to lr */
534 /* lock_monitor_exit *****************************************************************
536 Decrement the counter of a (currently owned) monitor. If the counter
537 reaches zero, release the monitor.
539 If the current thread is not the owner of the monitor, an
540 IllegalMonitorState exception is thrown.
543 t............the current thread
544 o............the object of which to exit the monitor
547 true.........everything ok,
548 false........an exception has been thrown
550 *******************************************************************************/
552 bool lock_monitor_exit(threadobject *t, java_objectheader *o)
558 CHECK_MONITORSTATE(lr, t, o, return false);
560 /* { the current thread `t` owns the lock record `lr` on object `o` } */
562 if (lr->lockCount > 1) {
563 /* we had locked this one recursively. just decrement, it will */
564 /* still be locked. */
569 /* we are going to unlock and recycle this lock record */
572 lock_record_t *wlr = lr->waiter;
573 if (o->monitorPtr != lr ||
574 (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) wlr) != lr)
576 lock_record_t *nlr = o->monitorPtr;
577 assert(nlr->waiter == NULL);
578 nlr->waiter = wlr; /* XXX is it ok to overwrite the nlr->waiter field like that? */
579 STORE_ORDER_BARRIER();
582 lock_wake_waiters(wlr);
587 /* unlock and throw away this lock record */
588 lock_record_release(lr);
589 lock_record_recycle(t, lr);
594 /* lock_record_remove_waiter *******************************************************
596 Remove a waiter lock record from the waiter list of the given lock record
599 lr...........the lock record holding the waiter list
600 toremove.....the record to remove from the list
602 *******************************************************************************/
604 static void lock_record_remove_waiter(lock_record_t *lr,
605 lock_record_t *toremove)
608 if (lr->waiter == toremove) {
609 lr->waiter = toremove->waiter;
613 } while (lr); /* XXX need to break cycle? */
617 /* lock_monitor_wait *****************************************************************
619 Wait on an object for a given (maximum) amount of time.
622 t............the current thread
623 o............the object
624 millis.......milliseconds of timeout
625 nanos........nanoseconds of timeout
628 The current thread must be the owner of the object's monitor.
630 *******************************************************************************/
632 void lock_monitor_wait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
635 lock_record_t *newlr;
640 CHECK_MONITORSTATE(lr, t, o, return);
642 /* { the thread t owns the lock record lr on the object o } */
644 /* wake threads waiting on this record XXX why? */
647 lock_wake_waiters(lr->waiter);
649 /* mark the lock record as "waiting on object o" */
652 STORE_ORDER_BARRIER();
654 /* unlock this record */
656 lock_record_release(lr);
658 /* wait until notified/interrupted/timed out */
660 wasinterrupted = threads_wait_with_timeout_relative(t, millis, nanos);
662 /* re-enter the monitor */
664 newlr = lock_monitor_enter(t, o);
666 /* we are no longer waiting */
668 lock_record_remove_waiter(newlr, lr);
669 newlr->lockCount = lr->lockCount;
671 /* recylce the old lock record */
676 lock_record_recycle(t, lr);
678 /* if we have been interrupted, throw the appropriate exception */
681 *exceptionptr = new_exception(string_java_lang_InterruptedException);
685 /* lock_monitor_notify **************************************************************
687 Notify one thread or all threads waiting on the given object.
690 t............the current thread
691 o............the object
692 one..........if true, only notify one thread
695 The current thread must be the owner of the object's monitor.
697 *******************************************************************************/
699 static void lock_monitor_notify(threadobject *t, java_objectheader *o, bool one)
703 threadobject *wthread;
707 CHECK_MONITORSTATE(lr, t, o, return);
709 /* { the thread t owns the lock record lr on the object o } */
711 /* for each waiter: */
713 for (wlr = lr->waiter; wlr; wlr = wlr->waiter) {
715 /* signal the waiting thread */
717 wthread = wlr->owner;
718 pthread_mutex_lock(&wthread->waitLock);
719 if (wthread->isSleeping)
720 pthread_cond_signal(&wthread->waitCond);
721 wthread->signaled = true;
722 pthread_mutex_unlock(&wthread->waitLock);
724 /* if we should only wake one, we are done */
732 /* lock_does_thread_hold_lock **************************************************
734 Return true if the given thread owns the monitor of the given object.
737 t............the thread
738 o............the object
741 true, if the thread is locking the object
743 *******************************************************************************/
745 bool lock_does_thread_hold_lock(threadobject *t, java_objectheader *o)
752 return (lr->o == o) && (lr->owner == t);
756 /* lock_wait_for_object ********************************************************
758 Wait for the given object.
761 o............the object
762 millis.......milliseconds to wait
763 nanos........nanoseconds to wait
765 *******************************************************************************/
767 void lock_wait_for_object(java_objectheader *o, s8 millis, s4 nanos)
769 threadobject *t = (threadobject*) THREADOBJECT;
770 lock_monitor_wait(t, o, millis, nanos);
774 /* lock_notify_object **********************************************************
776 Notify one thread waiting on the given object.
779 o............the object
781 *******************************************************************************/
783 void lock_notify_object(java_objectheader *o)
785 threadobject *t = (threadobject*) THREADOBJECT;
786 lock_monitor_notify(t, o, true);
790 /* lock_notify_all_object ******************************************************
792 Notify all threads waiting on the given object.
795 o............the object
797 *******************************************************************************/
799 void lock_notify_all_object(java_objectheader *o)
801 threadobject *t = (threadobject*) THREADOBJECT;
802 lock_monitor_notify(t, o, false);
806 * These are local overrides for various environment variables in Emacs.
807 * Please do not remove this and leave it at the end of the file, where
808 * Emacs will automagically detect them.
809 * ---------------------------------------------------------------------
812 * indent-tabs-mode: t
816 * vim:noexpandtab:sw=4:ts=4: