This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch [ecj]: Central Parking
- From: Mohan Embar <gnustuff at thisiscool dot com>
- To: java-patches at gcc dot gnu dot org
- Cc: Adam Megacz <adam at megacz dot com>
- Date: Tue, 05 Dec 2006 23:24:16 -0600
- Subject: Patch [ecj]: Central Parking
- Reply-to: gnustuff at thisiscool dot com
Hi All,
This does away with _Jv_ThreadPark and _Jv_ThreadUnpark and
keeps park() and unpark() in natUnsafe.cc, thereby allowing
a shared implementation using the cross-platform synchronization
functions and objects in posix-threads.h and win32-threads.h.
Since the park() implementation uses _Jv_CondNotify, we also get
thread interrupt support for free and can do away with the _Jv_ThreadUnpark
call in Thread.interrupt(). I hope I did this right and understood
everything correctly.
I built this on a native i686-pc-linux-gnu compiler as
well as a (i686-pc-linux-gnu,i686-pc-mingw32) cross, but didn't
see any tests in the libjava testsuite for this, so it's
untested. I figure that since it compiled without any
errors, it must work flawlessly, but it would be nice to
have a second set of eyes here.
-- Mohan
http://www.thisiscool.com/
http://www.animalsong.org/
2006-12-05 Mohan Embar <gnustuff@thisiscool.com>
* include/posix-threads.h (_Jv_ThreadUnpark, _Jv_ThreadPark): Removed.
* include/jvm.h (struct natThread): Replaced POSIX mutex and condition
variables with cross-platform equivalents.
* sun/misc/natUnsafe.cc (unpark): Ported implementation from
posix-threads.cc; made cross-platform.
(park): Likewise.
* posix-threads.cc (_Jv_ThreadUnpark, _Jv_ThreadPark): Removed.
* java/lang/natThread.cc (initialize_native): Replaced POSIX mutex
and condition variable initialization with cross-platform equivalents.
(finalize_native): Replaced POSIX mutex and condition variable
destruction with cross-platform equivalents; conditionalized.
(interrupt): Removed call to _Jv_ThreadUnpark().
* win32-threads.cc (_Jv_ThreadUnpark, _Jv_ThreadPark): Removed.
Index: include/posix-threads.h
===================================================================
--- include/posix-threads.h (revision 119567)
+++ include/posix-threads.h (working copy)
@@ -350,7 +350,4 @@
void _Jv_ThreadInterrupt (_Jv_Thread_t *data);
-void _Jv_ThreadUnpark (::java::lang::Thread *thread);
-void _Jv_ThreadPark (jboolean isAbsolute, jlong time);
-
#endif /* __JV_POSIX_THREADS__ */
Index: include/jvm.h
===================================================================
--- include/jvm.h (revision 119567)
+++ include/jvm.h (working copy)
@@ -775,8 +775,8 @@
// 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;
+ _Jv_Mutex_t park_mutex;
+ _Jv_ConditionVariable_t park_cond;
// 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,66 @@
void
sun::misc::Unsafe::unpark (::java::lang::Thread *thread)
{
- _Jv_ThreadUnpark (thread);
+ using namespace ::java::lang;
+ natThread *nt = (natThread *) thread->data;
+ volatile obj_addr_t *ptr = &nt->park_permit;
+
+ /* If this thread is in state RUNNING, give it a permit and return
+ immediately. */
+ if (compare_and_swap
+ (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PERMIT))
+ return;
+
+ /* If this thread is parked, put it into state RUNNING and send it a
+ signal. */
+ if (compare_and_swap
+ (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING))
+ {
+ _Jv_MutexLock (&nt->park_mutex);
+ _Jv_CondNotify (&nt->park_cond, &nt->park_mutex);
+ _Jv_MutexUnlock (&nt->park_mutex);
+ }
}
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;
+ volatile obj_addr_t *ptr = &nt->park_permit;
+
+ /* If we have a permit, return immediately. */
+ if (compare_and_swap
+ (ptr, Thread::THREAD_PARK_PERMIT, Thread::THREAD_PARK_RUNNING))
+ return;
+
+ jlong millis = 0, nanos = 0;
+
+ if (time)
+ {
+ if (isAbsolute)
+ {
+ millis = time;
+ nanos = 0;
+ }
+ else
+ {
+ millis = java::lang::System::currentTimeMillis();
+ nanos = time;
+ }
+ }
+
+ _Jv_MutexLock (&nt->park_mutex);
+ if (compare_and_swap
+ (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PARKED))
+ {
+ _Jv_CondWait (&nt->park_cond, &nt->park_mutex, millis, nanos);
+ /* If we were unparked by some other thread, this will already
+ be in state THREAD_PARK_RUNNING. If we were interrupted or
+ timed out, we have to do it ourself. */
+ compare_and_swap
+ (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING);
+ }
+ _Jv_MutexUnlock (&nt->park_mutex);
}
Index: posix-threads.cc
===================================================================
--- posix-threads.cc (revision 119567)
+++ posix-threads.cc (working copy)
@@ -339,129 +339,6 @@
pthread_mutex_unlock (&data->wait_mutex);
}
-/**
- * Releases the block on a thread created by _Jv_ThreadPark(). This
- * method can also be used to terminate a blockage caused by a prior
- * call to park. This operation is unsafe, as the thread must be
- * guaranteed to be live.
- *
- * @param thread the thread to unblock.
- */
-
-void
-_Jv_ThreadUnpark (::java::lang::Thread *thread)
-{
- using namespace ::java::lang;
- natThread *nt = (natThread *) thread->data;
- volatile obj_addr_t *ptr = &nt->park_permit;
-
- /* If this thread is in state RUNNING, give it a permit and return
- immediately. */
- if (compare_and_swap
- (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PERMIT))
- return;
-
- /* If this thread is parked, put it into state RUNNING and send it a
- signal. */
- 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);
- }
-}
-
-/**
- * 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
- * value of zero is defined as no timeout. When isAbsolute is true,
- * the timeout is in milliseconds relative to the epoch. Otherwise,
- * the value is the number of nanoseconds which must occur before
- * timeout. This call may also return spuriously (i.e. for no
- * apparent reason).
- *
- * @param isAbsolute true if the timeout is specified in milliseconds from
- * the epoch.
- * @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)
-{
- using namespace ::java::lang;
- Thread *thread = Thread::currentThread();
- natThread *nt = (natThread *) thread->data;
- volatile obj_addr_t *ptr = &nt->park_permit;
-
- /* If we have a permit, return immediately. */
- if (compare_and_swap
- (ptr, Thread::THREAD_PARK_PERMIT, Thread::THREAD_PARK_RUNNING))
- return;
-
- struct timespec ts;
- jlong millis = 0, nanos = 0;
-
- if (time)
- {
- if (isAbsolute)
- {
- millis = time;
- nanos = 0;
- }
- else
- {
- millis = java::lang::System::currentTimeMillis();
- nanos = time;
- }
-
- if (millis > 0 || nanos > 0)
- {
- // Calculate the abstime corresponding to the timeout.
- // Everything is in milliseconds.
- //
- // We use `unsigned long long' rather than jlong because our
- // caller may pass up to Long.MAX_VALUE millis. This would
- // overflow the range of a timespec.
-
- unsigned long long m = (unsigned long long)millis;
- unsigned long long seconds = m / 1000;
-
- ts.tv_sec = seconds;
- if (ts.tv_sec < 0 || (unsigned long long)ts.tv_sec != seconds)
- {
- // We treat a timeout that won't fit into a struct timespec
- // as a wait forever.
- millis = nanos = 0;
- }
- else
- {
- m %= 1000;
- ts.tv_nsec = m * 1000000 + (unsigned long long)nanos;
- }
- }
- }
-
- pthread_mutex_lock (&nt->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);
- else
- pthread_cond_timedwait (&nt->park_cond, &nt->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);
-}
-
static void
handle_intr (int)
{
Index: java/lang/natThread.cc
===================================================================
--- java/lang/natThread.cc (revision 119567)
+++ java/lang/natThread.cc (working copy)
@@ -54,8 +54,8 @@
_Jv_MutexInit (&nt->join_mutex);
_Jv_CondInit (&nt->join_cond);
- pthread_mutex_init (&nt->park_mutex, NULL);
- pthread_cond_init (&nt->park_cond, NULL);
+ _Jv_MutexInit (&nt->park_mutex);
+ _Jv_CondInit (&nt->park_cond);
nt->thread = _Jv_ThreadInitData (this);
// FIXME: if JNI_ENV is set we will want to free it. It is
@@ -70,14 +70,14 @@
_Jv_ThreadDestroyData (nt->thread);
#ifdef _Jv_HaveCondDestroy
_Jv_CondDestroy (&nt->join_cond);
+ _Jv_CondDestroy (&nt->park_cond);
#endif
#ifdef _Jv_HaveMutexDestroy
_Jv_MutexDestroy (&nt->join_mutex);
+ _Jv_MutexDestroy (&nt->park_mutex);
#endif
_Jv_FreeJNIEnv((JNIEnv*)nt->jni_env);
- pthread_mutex_destroy (&nt->park_mutex);
- pthread_cond_destroy (&nt->park_cond);
}
jint
@@ -128,10 +128,6 @@
_Jv_ThreadInterrupt (nt->thread);
compare_and_swap
(&nt->alive_flag, THREAD_SIGNALED, Thread::THREAD_ALIVE);
-
- // Even though we've interrupted this thread, it might still be
- // parked.
- _Jv_ThreadUnpark (this);
}
}
Index: win32-threads.cc
===================================================================
--- win32-threads.cc (revision 119567)
+++ win32-threads.cc (working copy)
@@ -419,40 +419,3 @@
SetEvent (data->interrupt_event);
LeaveCriticalSection (&data->interrupt_mutex);
}
-
-/**
- * Releases the block on a thread created by _Jv_ThreadPark(). This
- * method can also be used to terminate a blockage caused by a prior
- * call to park. This operation is unsafe, as the thread must be
- * guaranteed to be live.
- *
- * @param thread the thread to unblock.
- */
-
-void
-_Jv_ThreadUnpark (::java::lang::Thread *thread)
-{
- // WRITEME:
-}
-
-/**
- * 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
- * value of zero is defined as no timeout. When isAbsolute is true,
- * the timeout is in milliseconds relative to the epoch. Otherwise,
- * the value is the number of nanoseconds which must occur before
- * timeout. This call may also return spuriously (i.e. for no
- * apparent reason).
- *
- * @param isAbsolute true if the timeout is specified in milliseconds from
- * the epoch.
- * @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)
-{
- // WRITEME:
-}