diff options
Diffstat (limited to 'libjava/posix-threads.cc')
-rw-r--r-- | libjava/posix-threads.cc | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/libjava/posix-threads.cc b/libjava/posix-threads.cc index db21c93a823..19a7631d64a 100644 --- a/libjava/posix-threads.cc +++ b/libjava/posix-threads.cc @@ -327,6 +327,129 @@ _Jv_ThreadInterrupt (_Jv_Thread_t *data) 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) { |