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