Patch [ecj]: Central Parking

Mohan Embar gnustuff@thisiscool.com
Fri Dec 8 06:11:00 GMT 2006


Hi Andrew,

Sorry for the multiple posts. This supersedes my previous email and
includes Win32 support. Like I said, if you're okay with the approach
in principle, I'll write up a ChangeLog. If anyone else who's listerning
wants to look this over, I'd appreciate it.

-- Mohan
http://www.thisiscool.com/
http://www.animalsong.org/

Index: include/win32-threads.h
===================================================================
--- include/win32-threads.h	(revision 119567)
+++ include/win32-threads.h	(working copy)
@@ -193,6 +193,20 @@
 // See java/lang/natWin32Process.cc (waitFor) for an example.
 HANDLE _Jv_Win32GetInterruptEvent (void);
 
+// park() / unpark() support
+
+struct ParkHelper
+{
+  volatile bool dead;
+  HANDLE park_semaphore;
+  
+  void init ();
+  void deactivate ();
+  void destroy ();
+  void park (jboolean isAbsolute, jlong time);
+  void unpark ();
+};
+
 // Remove defines from <windows.h> that conflict with various things in libgcj code
 
 #undef TRUE
Index: include/posix-threads.h
===================================================================
--- include/posix-threads.h	(revision 119567)
+++ include/posix-threads.h	(working copy)
@@ -19,6 +19,7 @@
 
 #include <pthread.h>
 #include <sched.h>
+#include <sysdep/locks.h>
 
 //
 // Typedefs.
@@ -350,7 +351,33 @@
 
 void _Jv_ThreadInterrupt (_Jv_Thread_t *data);
 
-void _Jv_ThreadUnpark (::java::lang::Thread *thread);
-void _Jv_ThreadPark (jboolean isAbsolute, jlong time);
+// park() / unpark() support
 
+struct ParkHelper
+{
+  volatile obj_addr_t park_permit;
+  pthread_mutex_t park_mutex;
+  pthread_cond_t park_cond;
+  
+  void init ();
+  void deactivate ();
+  void destroy ();
+  void park (jboolean isAbsolute, jlong time);
+  void unpark ();
+};
+
+inline void
+ParkHelper::init ()
+{
+  pthread_mutex_init (&park_mutex, NULL);
+  pthread_cond_init (&park_cond, NULL);
+}
+
+inline void
+ParkHelper::destroy ()
+{
+  pthread_mutex_destroy (&park_mutex);
+  pthread_cond_destroy (&park_cond);
+}
+
 #endif /* __JV_POSIX_THREADS__ */
Index: include/jvm.h
===================================================================
--- include/jvm.h	(revision 119567)
+++ include/jvm.h	(working copy)
@@ -774,9 +774,7 @@
   _Jv_ConditionVariable_t join_cond;
 
   // These are used by Unsafe.park() and Unsafe.unpark().
-  volatile obj_addr_t park_permit;
-  pthread_mutex_t park_mutex;
-  pthread_cond_t park_cond;
+  ParkHelper park_helper;
 
   // This is private data for the thread system layer.
   _Jv_Thread_t *thread;
Index: sun/misc/natUnsafe.cc
===================================================================
--- sun/misc/natUnsafe.cc	(revision 119567)
+++ sun/misc/natUnsafe.cc	(working copy)
@@ -238,11 +238,15 @@
 void
 sun::misc::Unsafe::unpark (::java::lang::Thread *thread)
 {
-  _Jv_ThreadUnpark (thread);
+  natThread *nt = (natThread *) thread->data;
+  nt->park_helper.unpark ();
 }
 
 void
 sun::misc::Unsafe::park (jboolean isAbsolute, jlong time)
 {
-  _Jv_ThreadPark (isAbsolute, time);
+  using namespace ::java::lang;
+  Thread *thread = Thread::currentThread();
+  natThread *nt = (natThread *) thread->data;
+  nt->park_helper.park (isAbsolute, time);
 }
Index: posix-threads.cc
===================================================================
--- posix-threads.cc	(revision 119567)
+++ posix-threads.cc	(working copy)
@@ -347,13 +347,11 @@
  *
  * @param thread the thread to unblock.
  */
-
 void
-_Jv_ThreadUnpark (::java::lang::Thread *thread)
+ParkHelper::unpark ()
 {
   using namespace ::java::lang;
-  natThread *nt = (natThread *) thread->data;
-  volatile obj_addr_t *ptr = &nt->park_permit;
+  volatile obj_addr_t *ptr = &park_permit;
 
   /* If this thread is in state RUNNING, give it a permit and return
      immediately.  */
@@ -366,13 +364,22 @@
   if (compare_and_swap 
       (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING))
     {
-      pthread_mutex_lock (&nt->park_mutex);
-      pthread_cond_signal (&nt->park_cond);
-      pthread_mutex_unlock (&nt->park_mutex);
+      pthread_mutex_lock (&park_mutex);
+      pthread_cond_signal (&park_cond);
+      pthread_mutex_unlock (&park_mutex);
     }
 }
 
 /**
+ * Sets our state to dead.
+ */
+void
+ParkHelper::deactivate ()
+{
+  park_permit = ::java::lang::Thread::THREAD_PARK_DEAD;
+}
+
+/**
  * Blocks the thread until a matching _Jv_ThreadUnpark() occurs, the
  * thread is interrupted or the optional timeout expires.  If an
  * unpark call has already occurred, this also counts.  A timeout
@@ -387,14 +394,11 @@
  * @param time either the number of nanoseconds to wait, or a time in
  *             milliseconds from the epoch to wait for.
  */
-
 void
-_Jv_ThreadPark (jboolean isAbsolute, jlong time)
+ParkHelper::park (jboolean isAbsolute, jlong time)
 {
   using namespace ::java::lang;
-  Thread *thread = Thread::currentThread();
-  natThread *nt = (natThread *) thread->data;
-  volatile obj_addr_t *ptr = &nt->park_permit;
+  volatile obj_addr_t *ptr = &park_permit;
 
   /* If we have a permit, return immediately.  */
   if (compare_and_swap 
@@ -444,22 +448,21 @@
 	}
     }
       
-  pthread_mutex_lock (&nt->park_mutex);
+  pthread_mutex_lock (&park_mutex);
   if (compare_and_swap 
       (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PARKED))
     {
       if (millis == 0 && nanos == 0)
-	pthread_cond_wait (&nt->park_cond, &nt->park_mutex);
+	pthread_cond_wait (&park_cond, &park_mutex);
       else
-	pthread_cond_timedwait (&nt->park_cond, &nt->park_mutex, 
-					&ts);
+	pthread_cond_timedwait (&park_cond, &park_mutex, &ts);
       /* If we were unparked by some other thread, this will already
 	 be in state THREAD_PARK_RUNNING.  If we timed out, we have to
 	 do it ourself.  */
       compare_and_swap 
 	(ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING);
     }
-  pthread_mutex_unlock (&nt->park_mutex);
+  pthread_mutex_unlock (&park_mutex);
 }
 
 static void
Index: java/lang/natThread.cc
===================================================================
--- java/lang/natThread.cc	(revision 119567)
+++ java/lang/natThread.cc	(working copy)
@@ -26,6 +26,8 @@
 #include <java/lang/InterruptedException.h>
 #include <java/lang/NullPointerException.h>
 
+#include <sun/misc/Unsafe.h>
+
 #include <jni.h>
 
 #ifdef ENABLE_JVMPI
@@ -54,8 +56,7 @@
   _Jv_MutexInit (&nt->join_mutex);
   _Jv_CondInit (&nt->join_cond);
 
-  pthread_mutex_init (&nt->park_mutex, NULL);
-  pthread_cond_init (&nt->park_cond, NULL);
+  nt->park_helper.init();
 
   nt->thread = _Jv_ThreadInitData (this);
   // FIXME: if JNI_ENV is set we will want to free it.  It is
@@ -75,9 +76,8 @@
   _Jv_MutexDestroy (&nt->join_mutex);
 #endif
   _Jv_FreeJNIEnv((JNIEnv*)nt->jni_env);
-
-  pthread_mutex_destroy (&nt->park_mutex);
-  pthread_cond_destroy (&nt->park_cond);
+  
+  nt->park_helper.destroy();
 }
 
 jint
@@ -131,7 +131,7 @@
 
       // Even though we've interrupted this thread, it might still be
       // parked.
-      _Jv_ThreadUnpark (this);
+      ::sun::misc::Unsafe::getUnsafe ()->unpark (this);
     }
 }
 
@@ -214,7 +214,7 @@
   __sync_synchronize();
   natThread *nt = (natThread *) data;
   
-  nt->park_permit = THREAD_PARK_DEAD;
+  nt->park_helper.deactivate ();
   group->removeThread (this);
 
 #ifdef ENABLE_JVMPI  
Index: win32-threads.cc
===================================================================
--- win32-threads.cc	(revision 119567)
+++ win32-threads.cc	(working copy)
@@ -26,6 +26,7 @@
 #include <jvm.h>
 #include <java/lang/Thread.h>
 #include <java/lang/System.h>
+#include <sysdep/locks.h>
 
 #include <errno.h>
 
@@ -420,6 +421,31 @@
   LeaveCriticalSection (&data->interrupt_mutex);
 }
 
+// park() / unpark() support
+
+void
+ParkHelper::init ()
+{
+  dead = false;
+
+  // Create a semaphore with a maximum count of 1. When
+  // the count is 0, we're equivalent to POSIX THREAD_PARK_RUNNING.
+  // When the count is 1, we're equivalent to POSIX THREAD_PARK_PERMIT.
+  park_semaphore = CreateSemaphore (NULL, 0, 1, NULL);
+}
+
+void
+ParkHelper::deactivate ()
+{
+  dead = true;
+}
+
+void
+ParkHelper::destroy()
+{
+  CloseHandle (park_semaphore);
+}
+
 /**
  * Releases the block on a thread created by _Jv_ThreadPark().  This
  * method can also be used to terminate a blockage caused by a prior
@@ -428,11 +454,17 @@
  *
  * @param thread the thread to unblock.
  */
-
 void
-_Jv_ThreadUnpark (::java::lang::Thread *thread)
+ParkHelper::unpark ()
 {
-  // WRITEME:
+  // Leave if we're dead.
+  if (dead) return;
+  
+  // Increment our semaphore count by 1, waking up any thread that's
+  // sleeping on it, or else giving ourselves a permit for later if
+  // there's currently no sleeping thread. If we've already got a
+  // permit, this call has no effect.
+  ReleaseSemaphore (park_semaphore, 1, NULL);
 }
 
 /**
@@ -450,9 +482,42 @@
  * @param time either the number of nanoseconds to wait, or a time in
  *             milliseconds from the epoch to wait for.
  */
-
 void
-_Jv_ThreadPark (jboolean isAbsolute, jlong time)
+ParkHelper::park (jboolean isAbsolute, jlong time)
 {
-  // WRITEME:
+  // Leave if we're dead.
+  if (dead) return;
+  
+  // Determine the number of milliseconds to wait.
+  jlong millis = 0, nanos = 0;
+  
+  if (time)
+    {
+      if (isAbsolute)
+	{
+	  millis = time - ::java::lang::System::currentTimeMillis();
+	  nanos = 0;
+	}
+      else
+	{
+	  millis = 0;
+	  nanos = time;
+	}
+	
+      if (nanos)
+        {
+          millis += nanos / 1000000;
+          if (millis == 0)
+            millis = 1;
+            // ...otherwise, we'll block indefinitely.
+        }
+    }
+    
+  if (millis < 0) return;
+      // Can this ever happen?
+      
+  // Wait. If our semaphore count is 1, it means we have a permit
+  // and the call returns immediately.
+  DWORD timeout = millis==0 ? INFINITE : (DWORD) millis;
+  WaitForSingleObject (park_semaphore, timeout);
 }






More information about the Java-patches mailing list