* src/threads/threads-common.c (threads_start_javathread): Changed
[cacao.git] / src / threads / native / lock.c
index cf917aedb0ba1ecb04abcc327ca1a138dc4daff5..a6078339f7da4834877cb3b7ffd3688ea54d4375 100644 (file)
@@ -1,6 +1,6 @@
 /* src/threads/native/lock.c - lock implementation
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
    J. Wenninger, Institut f. Computersprachen - TU Wien
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Stefan Ring
-                       Edwin Steiner
-
-   Changes: Christian Thalinger
-
    $Id: threads.c 4903 2006-05-11 12:48:43Z edwin $
 
 */
 #include <sys/time.h>
 #include <pthread.h>
 
-#include "mm/memory.h"
 #include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "threads/native/lock.h"
+#include "threads/native/threads.h"
+
 #include "vm/global.h"
 #include "vm/exceptions.h"
 #include "vm/stringlocal.h"
+#include "vm/vm.h"
+
+#include "vmcore/options.h"
+
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
+
+#if defined(ENABLE_VMLOG)
+#include <vmlog_cacao.h>
+#endif
 
 /* arch.h must be here because it defines USE_FAKE_ATOMIC_INSTRUCTIONS */
 
 /* MACROS FOR THE FLAT LOCK CONTENTION BIT                                    */
 /******************************************************************************/
 
-#define LOCK_SET_FLC_BIT(obj)    ((obj)->flcword = 1)
-#define LOCK_CLEAR_FLC_BIT(obj)  ((obj)->flcword = 0)
-#define LOCK_TEST_FLC_BIT(obj)   ((obj)->flcword != 0)
+#define LOCK_SET_FLC_BIT(obj)    ((obj)->hdrflags |= HDRFLAG_FLC)
+#define LOCK_CLEAR_FLC_BIT(obj)  ((obj)->hdrflags &= ~ HDRFLAG_FLC)
+#define LOCK_TEST_FLC_BIT(obj)   ((obj)->hdrflags & HDRFLAG_FLC)
 
 
 /******************************************************************************/
@@ -217,6 +226,10 @@ void lock_init(void)
        pthread_mutex_init(&lock_global_pool_lock, NULL);
 
        lock_hashtable_init();
+
+#if defined(ENABLE_VMLOG)
+       vmlog_cacao_init_lock();
+#endif
 }
 
 
@@ -301,29 +314,35 @@ ptrint lock_pre_compute_thinlock(s4 index)
 
 static lock_record_pool_t *lock_record_alloc_new_pool(threadobject *thread, int size)
 {
-       int i;
        lock_record_pool_t *pool;
+       s4                  i;
 
        /* get the pool from the memory allocator */
 
        pool = mem_alloc(sizeof(lock_record_pool_header_t)
                                   + sizeof(lock_record_t) * size);
 
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_lock_record_pool += sizeof(lock_record_pool_header_t) +
+                       sizeof(lock_record_t) * size;
+#endif
+
        /* initialize the pool header */
 
        pool->header.size = size;
 
        /* initialize the individual lock records */
 
-       for (i=0; i<size; i++) {
+       for (i = 0; i < size; i++) {
                lock_record_init(&pool->lr[i], thread);
 
-               pool->lr[i].nextfree = &pool->lr[i+1];
+               pool->lr[i].nextfree = &pool->lr[i + 1];
        }
 
        /* terminate free list */
 
-       pool->lr[i-1].nextfree = NULL;
+       pool->lr[i - 1].nextfree = NULL;
 
        return pool;
 }
@@ -347,24 +366,24 @@ static lock_record_pool_t *lock_record_alloc_pool(threadobject *t, int size)
 {
        pthread_mutex_lock(&lock_global_pool_lock);
 
-       if (lock_global_pool) {
+       if (lock_global_pool != NULL) {
                int i;
                lock_record_pool_t *pool;
 
                /* pop a pool from the global freelist */
 
-               pool = lock_global_pool;
+               pool             = lock_global_pool;
                lock_global_pool = pool->header.next;
 
                pthread_mutex_unlock(&lock_global_pool_lock);
 
                /* re-initialize owner and freelist chaining */
 
-               for (i=0; i < pool->header.size; i++) {
-                       pool->lr[i].owner = NULL;
-                       pool->lr[i].nextfree = &pool->lr[i+1];
+               for (i = 0; i < pool->header.size; i++) {
+                       pool->lr[i].owner    = NULL;
+                       pool->lr[i].nextfree = &pool->lr[i + 1];
                }
-               pool->lr[i-1].nextfree = NULL;
+               pool->lr[i - 1].nextfree = NULL;
 
                return pool;
        }
@@ -395,7 +414,7 @@ void lock_record_free_pools(lock_record_pool_t *pool)
                       /*     algorithm. We must find another way to free  */
                       /*     unused lock records.                         */
 
-       if (!pool)
+       if (pool == NULL)
                return;
 
        pthread_mutex_lock(&lock_global_pool_lock);
@@ -403,6 +422,7 @@ void lock_record_free_pools(lock_record_pool_t *pool)
        /* find the last pool in the list */
 
        last = &pool->header;
+
        while (last->next)
                last = &last->next->header;
 
@@ -504,9 +524,15 @@ static void lock_hashtable_init(void)
 {
        pthread_mutex_init(&(lock_hashtable.mutex), NULL);
 
-       lock_hashtable.size = LOCK_INITIAL_HASHTABLE_SIZE;
+       lock_hashtable.size    = LOCK_INITIAL_HASHTABLE_SIZE;
        lock_hashtable.entries = 0;
-       lock_hashtable.ptr = MNEW(lock_record_t *, lock_hashtable.size);
+       lock_hashtable.ptr     = MNEW(lock_record_t *, lock_hashtable.size);
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_lock_hashtable += sizeof(lock_record_t *) * lock_hashtable.size;
+#endif
+
        MZERO(lock_hashtable.ptr, lock_record_t *, lock_hashtable.size);
 }
 
@@ -540,11 +566,17 @@ static void lock_hashtable_grow(void)
 
        oldtable = lock_hashtable.ptr;
        newtable = MNEW(lock_record_t *, newsize);
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_lock_hashtable += sizeof(lock_record_t *) * newsize;
+#endif
+
        MZERO(newtable, lock_record_t *, newsize);
 
        /* rehash the entries */
 
-       for (i=0; i<oldsize; ++i) {
+       for (i = 0; i < oldsize; i++) {
                lr = oldtable[i];
                while (lr) {
                        next = lr->hashlink;
@@ -561,10 +593,15 @@ static void lock_hashtable_grow(void)
 
        /* replace the old table */
 
-       lock_hashtable.ptr = newtable;
+       lock_hashtable.ptr  = newtable;
        lock_hashtable.size = newsize;
 
        MFREE(oldtable, lock_record_t *, oldsize);
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_lock_hashtable -= sizeof(lock_record_t *) * oldsize;
+#endif
 }
 
 
@@ -657,7 +694,7 @@ void lock_init_object_lock(java_objectheader *o)
        assert(o);
 
        o->monitorPtr = (lock_record_t *) THIN_UNLOCKED;
-       o->flcword = 0;
+       LOCK_CLEAR_FLC_BIT(o);
 }
 
 
@@ -783,15 +820,24 @@ static void lock_inflate(threadobject *t, java_objectheader *o, lock_record_t *l
       t............the current thread
          o............the object of which to enter the monitor
 
+   RETURN VALUE:
+      true.........the lock has been successfully acquired
+         false........an exception has been thrown
+
 *******************************************************************************/
 
-void lock_monitor_enter(java_objectheader *o)
+bool lock_monitor_enter(java_objectheader *o)
 {
        threadobject *t;
        /* CAUTION: This code assumes that ptrint is unsigned! */
        ptrint        lockword;
        ptrint        thinlock;
 
+       if (o == NULL) {
+               exceptions_throw_nullpointerexception();
+               return false;
+       }
+
        t = THREADOBJECT;
 
        thinlock = t->thinlock;
@@ -802,7 +848,7 @@ void lock_monitor_enter(java_objectheader *o)
                /* success. we locked it */
                /* The Java Memory Model requires a memory barrier here: */
                MEMORY_BARRIER();
-               return;
+               return true;
        }
 
        /* next common case: recursive lock with small recursion count */
@@ -820,7 +866,7 @@ void lock_monitor_enter(java_objectheader *o)
                        o->monitorPtr = (lock_record_t *) (lockword + THIN_LOCK_COUNT_INCR);
 
                        /* success. we locked it */
-                       return;
+                       return true;
                }
                else {
                        lock_record_t *lr;
@@ -832,7 +878,7 @@ void lock_monitor_enter(java_objectheader *o)
                        lock_inflate(t, o, lr);
                        lr->count++;
 
-                       return;
+                       return true;
                }
        }
 
@@ -848,7 +894,7 @@ void lock_monitor_enter(java_objectheader *o)
                        /* check for recursive entering */
                        if (lr->owner == t) {
                                lr->count++;
-                               return;
+                               return true;
                        }
 
                        /* acquire the mutex of the lock record */
@@ -857,7 +903,7 @@ void lock_monitor_enter(java_objectheader *o)
 
                        assert(lr->count == 0);
 
-                       return;
+                       return true;
                }
 
                /****** inflation path ******/
@@ -909,7 +955,7 @@ void lock_monitor_enter(java_objectheader *o)
 
                /* we own the inflated lock now */
 
-               return;
+               return true;
        }
 }
 
@@ -938,6 +984,11 @@ bool lock_monitor_exit(java_objectheader *o)
        ptrint        lockword;
        ptrint        thinlock;
 
+       if (o == NULL) {
+               exceptions_throw_nullpointerexception();
+               return false;
+       }
+
        t = THREADOBJECT;
 
        /* We don't have to worry about stale values here, as any stale value */
@@ -1033,6 +1084,36 @@ bool lock_monitor_exit(java_objectheader *o)
 }
 
 
+/* lock_record_add_waiter ******************************************************
+
+   Add a thread to the list of waiting threads of a lock record.
+
+   IN:
+      lr...........the lock record
+      thread.......the thread to add
+
+*******************************************************************************/
+
+static void lock_record_add_waiter(lock_record_t *lr, threadobject *thread)
+{
+       lock_waiter_t *waiter;
+
+       /* allocate a waiter data structure */
+
+       waiter = NEW(lock_waiter_t);
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_lock_waiter += sizeof(lock_waiter_t);
+#endif
+
+       waiter->waiter = thread;
+       waiter->next   = lr->waiters;
+
+       lr->waiters = waiter;
+}
+
+
 /* lock_record_remove_waiter ***************************************************
 
    Remove a thread from the list of waiting threads of a lock record.
@@ -1046,15 +1127,26 @@ bool lock_monitor_exit(java_objectheader *o)
    
 *******************************************************************************/
 
-static void lock_record_remove_waiter(lock_record_t *lr, threadobject *t)
+static void lock_record_remove_waiter(lock_record_t *lr, threadobject *thread)
 {
        lock_waiter_t **link;
-       lock_waiter_t *w;
+       lock_waiter_t  *w;
 
        link = &(lr->waiters);
+
        while ((w = *link)) {
-               if (w->waiter == t) {
+               if (w->waiter == thread) {
                        *link = w->next;
+
+                       /* free the waiter data structure */
+
+                       FREE(w, lock_waiter_t);
+
+#if defined(ENABLE_STATISTICS)
+                       if (opt_stat)
+                               size_lock_waiter -= sizeof(lock_waiter_t);
+#endif
+
                        return;
                }
 
@@ -1062,9 +1154,8 @@ static void lock_record_remove_waiter(lock_record_t *lr, threadobject *t)
        }
 
        /* this should never happen */
-       fprintf(stderr,"error: waiting thread not found in list of waiters\n");
-       fflush(stderr);
-       abort();
+
+       vm_abort("lock_record_remove_waiter: waiting thread not found in list of waiters\n");
 }
 
 
@@ -1084,20 +1175,16 @@ static void lock_record_remove_waiter(lock_record_t *lr, threadobject *t)
    
 *******************************************************************************/
 
-static void lock_record_wait(threadobject *t, lock_record_t *lr, s8 millis, s4 nanos)
+static void lock_record_wait(threadobject *thread, lock_record_t *lr, s8 millis, s4 nanos)
 {
-       lock_waiter_t *waiter;
-       s4             lockcount;
-       bool           wasinterrupted;
+       s4   lockcount;
+       bool wasinterrupted;
 
        /* { the thread t owns the fat lock record lr on the object o } */
 
        /* register us as waiter for this object */
 
-       waiter = NEW(lock_waiter_t);
-       waiter->waiter = t;
-       waiter->next = lr->waiters;
-       lr->waiters = waiter;
+       lock_record_add_waiter(lr, thread);
 
        /* remember the old lock count */
 
@@ -1106,19 +1193,19 @@ static void lock_record_wait(threadobject *t, lock_record_t *lr, s8 millis, s4 n
        /* unlock this record */
 
        lr->count = 0;
-       lock_record_exit(t, lr);
+       lock_record_exit(thread, lr);
 
        /* wait until notified/interrupted/timed out */
 
-       wasinterrupted = threads_wait_with_timeout_relative(t, millis, nanos);
+       wasinterrupted = threads_wait_with_timeout_relative(thread, millis, nanos);
 
        /* re-enter the monitor */
 
-       lock_record_enter(t, lr);
+       lock_record_enter(thread, lr);
 
        /* remove us from the list of waiting threads */
 
-       lock_record_remove_waiter(lr, t);
+       lock_record_remove_waiter(lr, thread);
 
        /* restore the old lock count */
 
@@ -1127,7 +1214,7 @@ static void lock_record_wait(threadobject *t, lock_record_t *lr, s8 millis, s4 n
        /* if we have been interrupted, throw the appropriate exception */
 
        if (wasinterrupted)
-               *exceptionptr = new_exception(string_java_lang_InterruptedException);
+               exceptions_throw_interruptedexception();
 }
 
 
@@ -1349,8 +1436,11 @@ bool lock_is_held_by_current_thread(java_objectheader *o)
 
 void lock_wait_for_object(java_objectheader *o, s8 millis, s4 nanos)
 {
-       threadobject *t = (threadobject*) THREADOBJECT;
-       lock_monitor_wait(t, o, millis, nanos);
+       threadobject *thread;
+
+       thread = THREADOBJECT;
+
+       lock_monitor_wait(thread, o, millis, nanos);
 }
 
 
@@ -1365,8 +1455,11 @@ void lock_wait_for_object(java_objectheader *o, s8 millis, s4 nanos)
 
 void lock_notify_object(java_objectheader *o)
 {
-       threadobject *t = (threadobject*) THREADOBJECT;
-       lock_monitor_notify(t, o, true);
+       threadobject *thread;
+
+       thread = THREADOBJECT;
+
+       lock_monitor_notify(thread, o, true);
 }
 
 
@@ -1381,10 +1474,14 @@ void lock_notify_object(java_objectheader *o)
 
 void lock_notify_all_object(java_objectheader *o)
 {
-       threadobject *t = (threadobject*) THREADOBJECT;
-       lock_monitor_notify(t, o, false);
+       threadobject *thread;
+
+       thread = THREADOBJECT;
+
+       lock_monitor_notify(thread, o, false);
 }
 
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where