Fixes PR131.
[cacao.git] / src / threads / lock.cpp
index 5bcee690db131362a170ab9dbd3d3132e8afce3b..ae7bb874036d858dd59c9b74cd7f2f43786356ce 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "vm/types.h"
 
-#include "mm/memory.h"
+#include "mm/memory.hpp"
 
 #include "native/llni.h"
 
@@ -46,7 +46,7 @@
 #include "toolbox/list.hpp"
 
 #include "vm/exceptions.hpp"
-#include "vm/finalizer.h"
+#include "vm/finalizer.hpp"
 #include "vm/global.h"
 #include "vm/options.h"
 #include "vm/string.hpp"
@@ -459,7 +459,14 @@ static lock_record_t *lock_hashtable_get(java_handle_t* o)
 #if defined(ENABLE_GC_BOEHM)
                /* register new finalizer to clean up the lock record */
 
-               GC_REGISTER_FINALIZER(LLNI_DIRECT(o), lock_record_finalizer, 0, 0, 0);
+               GC_finalization_proc ofinal = 0;
+               GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(o), lock_record_finalizer, 0, &ofinal, 0);
+
+               /* There was a finalizer -- reinstall it. We do not want to disrupt the
+                  normal finalizer operation. We hold the monitor on this object, so
+                  this is thread-safe. */
+               if (ofinal)
+                       GC_REGISTER_FINALIZER(LLNI_DIRECT(o), ofinal, 0, 0, 0);
 #endif
 
                /* enter it in the hashtable */
@@ -483,6 +490,29 @@ static lock_record_t *lock_hashtable_get(java_handle_t* o)
        return lr;
 }
 
+/* lock_schedule_lockrecord_removal ********************************************
+
+   Gives the locking system a chance to schedule the removal of an unused lock
+   record. This function is called after an object's finalizer has run.
+
+   IN:
+         o....the object which has been finalized
+
+*******************************************************************************/
+
+#if defined(ENABLE_GC_BOEHM)
+void lock_schedule_lockrecord_removal(java_handle_t *o)
+{
+       Lockword* lockword = lock_lockword_get(o);
+       if (!lockword->is_fat_lock())
+               /* there is no lock record */
+               return;
+
+       /* register new finalizer to clean up the lock record */
+       GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(o), lock_record_finalizer, 0, 0, 0);
+}
+#endif
+
 
 /* lock_hashtable_remove *******************************************************
 
@@ -578,11 +608,6 @@ static void lock_record_finalizer(void *object, void *p)
        }
 #endif
 
-       /* check for a finalizer function */
-
-       if (c->finalizer != NULL)
-               finalizer_run(object, p);
-
        /* remove the lock-record entry from the hashtable and free it */
 
        lock_hashtable_remove(THREADOBJECT, o);
@@ -675,6 +700,22 @@ static void lock_inflate(java_handle_t *o, lock_record_t *lr)
 }
 
 
+/* sable_flc_waiting ***********************************************************
+
+   Enqueue the current thread on another thread's FLC list. The function
+   blocks until the lock has been inflated by the owning thread.
+
+   The algorithm used to be an almost literal copy from SableVM. The
+   superfluous list traversal in the waiting loop has been removed since,
+   though.
+
+   IN:
+         lockword.....the object's lockword as seen at the first locking attempt
+         t............the current thread
+         o............the object of which to enter the monitor
+
+*******************************************************************************/
+
 static void sable_flc_waiting(Lockword *lockword, threadobject *t, java_handle_t *o)
 {
        int32_t index;
@@ -714,30 +755,18 @@ static void sable_flc_waiting(Lockword *lockword, threadobject *t, java_handle_t
                        t_other->flc_tail = t;
                f = t_other->flc_tail;
 
-               for (;;)
+               // The other thread will clear flc_object.
+               while (t->flc_object)
                {
-                       threadobject *current;
+                       // We are not cleared yet -- the other thread cannot have seen
+                       // the FLC bit yet.
+                       assert(t_other->flc_bit);
 
                        // Wait until another thread sees the flc bit and notifies
                        // us of unlocking.
                        t->flc_cond->wait(t_other->flc_lock);
-
-                       if (t_other->flc_tail != f)
-                               break;
-                       /* Traverse FLC list looking if we're still there */
-                       current = t_other->flc_list;
-                       while (current && current != t)
-                               current = current->flc_next;
-                       if (!current)
-                               /* not in list anymore, can stop waiting */
-                               break;
-
-                       /* We are still in the list -- the other thread cannot have seen
-                          the FLC bit yet */
-                       assert(t_other->flc_bit);
                }
 
-               t->flc_object = NULL;   /* for garbage collector? */
                t->flc_next = NULL;
        }
        else
@@ -746,6 +775,17 @@ static void sable_flc_waiting(Lockword *lockword, threadobject *t, java_handle_t
        t_other->flc_lock->unlock();
 }
 
+/* notify_flc_waiters **********************************************************
+
+   Traverse the thread's FLC list and inflate all corresponding locks. Notify
+   the associated threads as well.
+
+   IN:
+         t............the current thread
+         o............the object currently being unlocked
+
+*******************************************************************************/
+
 static void notify_flc_waiters(threadobject *t, java_handle_t *o)
 {
        threadobject *current;
@@ -775,6 +815,7 @@ static void notify_flc_waiters(threadobject *t, java_handle_t *o)
 
                // Wake the waiting threads.
                current->flc_cond->broadcast();
+               current->flc_object = NULL;
 
                current = current->flc_next;
        }