diff options
author | bryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-03-28 02:22:24 +0000 |
---|---|---|
committer | bryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-03-28 02:22:24 +0000 |
commit | af3502d049ecdf4dbaa54db91794e5fa8e55abbd (patch) | |
tree | 1644e34b97bb6d57435386decdbf6dbeadd31a58 /libjava/posix-threads.cc | |
parent | d21373270e4e1e74c194a06641bad4d28d29dd8b (diff) | |
download | gcc-af3502d049ecdf4dbaa54db91794e5fa8e55abbd.tar.gz |
* Makefile.in: New #defines and friends for Thread.h.
* posix-threads.cc: (struct starter): Remove `object'.
(_Jv_CondWait): Use interruptable condition variables and new
recursive mutexes. New return codes on interrupt or non-ownership
of mutex.
(_Jv_CondNotify): Ditto.
(_Jv_CondNotifyAll): Ditto.
(_Jv_ThreadInterrupt): Set thread interrupt flag directly. Interrupt
the target thread by signaling its wait condition.
(_Jv_ThreadInitData): Set `thread_obj' in the thread data struct,
not the starter struct. Initialize wait_mutex and wait_cond.
(_Jv_MutexLock): New recursive mutex implementation. Moved from
posix-threads.h.
(_Jv_MutexUnlock): Ditto.
(really_start): Set info->data->thread from pthread_self() to work
around a race condition. Destroy wait_mutex and wait_cond when run()
returns.
* java/lang/Thread.java: (isInterrupted_): Renamed to overloaded
`isInterrupted(boolean)'. Clear interrupted flag if clear_flag is
set.
startable_flag: New private field.
(Thread): Initialize `startable_flag'.
(toString): Check for null thread group.
* java/lang/natThread.cc: (struct natThread): New fields
`join_mutex', `join_cond'. Removed fields `joiner', `next'.
(class locker): Removed.
(initialize_native): Initialize `join_cond' and `join_mutex'.
(interrupt): Now just calls _Jv_ThreadInterrupt().
(join): Simplified. Just wait on the target thread's join condition.
(finish_): Remove join list code. Unset thread group. Signal
potential joiners by notifying the dying threads join_cond.
(start): Check for illegal restarts.
* java/lang/natObject.cc: Check for return value of _Jv_CondWait and
act appropriatly.
* include/posix-threads.h: Remove all HAVE_RECURSIVE_MUTEX related
#defines and #ifdefs.
(struct _Jv_Thread_t): New fields `thread_obj', `wait_cond',
`wait_mutex', `next'.
(struct _Jv_ConditionVariable_t): Define as a struct instead of
directly mapping to pthread_cond_t.
(struct _Jv_Mutex_t): New recursive implementation.
(_Jv_PthreadCheckMonitor): Reimplemented. Simple `owner' check.
_Jv_HaveCondDestroy: Never define this for posix-threads.
(_Jv_CondNotify): Remove inline implementation(s), prototype instead.
(_Jv_CondNotifyAll): Ditto.
(_Jv_MutexLock): Ditto.
(_Jv_MutexUnlock): Ditto.
(_Jv_MutexInit): Changed to reflect new mutex implementation.
(_Jv_MutexDestroy): Ditto.
(_Jv_CondDestroy): Removed.
(_Jv_PthreadGetMutex): Removed.
* include/win32-threads.h: (_Jv_CondNotify): Guess _JV_NOT_OWNER on an
error. Add a FIXME about this.
(_Jv_CondNotifyAll): Ditto.
* win32-threads.cc: (_Jv_CondWait): Return 0 on a timeout. Guess
_JV_NOT_OWNER on other errors. Add FIXME.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32773 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/posix-threads.cc')
-rw-r--r-- | libjava/posix-threads.cc | 374 |
1 files changed, 207 insertions, 167 deletions
diff --git a/libjava/posix-threads.cc b/libjava/posix-threads.cc index cf29a258a33..a664ee37060 100644 --- a/libjava/posix-threads.cc +++ b/libjava/posix-threads.cc @@ -40,7 +40,6 @@ extern "C" struct starter { _Jv_ThreadStartFunc *method; - java::lang::Thread *object; _Jv_Thread_t *data; }; @@ -78,30 +77,23 @@ static int non_daemon_count; +// Wait for the condition variable "CV" to be notified. +// Return values: +// 0: the condition was notified, or the timeout expired. +// _JV_NOT_OWNER: the thread does not own the mutex "MU". +// _JV_INTERRUPTED: the thread was interrupted. Its interrupted flag is set. int _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, jlong millis, jint nanos) { - if (_Jv_PthreadCheckMonitor (mu)) - return 1; + pthread_t self = pthread_self(); + if (mu->owner != self) + return _JV_NOT_OWNER; - int r; - pthread_mutex_t *pmu = _Jv_PthreadGetMutex (mu); struct timespec ts; - jlong m, m2, startTime; - bool done_sleeping = false; + jlong m, startTime; - if (millis == 0 && nanos == 0) - { -#ifdef LINUX_THREADS - // pthread_cond_timedwait can be interrupted by a signal on linux, while - // pthread_cond_wait can not. So pthread_cond_timedwait() forever. - m = java::lang::Long::MAX_VALUE; - ts.tv_sec = LONG_MAX; - ts.tv_nsec = 0; -#endif - } - else + if (millis > 0 || nanos > 0) { startTime = java::lang::System::currentTimeMillis(); m = millis + startTime; @@ -109,172 +101,178 @@ _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, ts.tv_nsec = ((m % 1000) * 1000000) + nanos; } - java::lang::Thread *current = _Jv_ThreadCurrent(); + _Jv_Thread_t *current = _Jv_ThreadCurrentData (); + java::lang::Thread *current_obj = _Jv_ThreadCurrent (); + + // Add this thread to the cv's wait set. + current->next = NULL; - do + if (cv->first == NULL) + cv->first = current; + else + for (_Jv_Thread_t *t = cv->first;; t = t->next) + { + if (t->next == NULL) + { + t->next = current; + break; + } + } + + pthread_mutex_lock (¤t->wait_mutex); + + // Now that we hold the wait mutex, check if this thread has been + // interrupted already. + if (current_obj->interrupt_flag) { - r = EINTR; - // Check to ensure the thread hasn't already been interrupted. - if (!(current->isInterrupted ())) + pthread_mutex_unlock (¤t->wait_mutex); + return _JV_INTERRUPTED; + } + + // Record the current lock depth, so it can be restored when we re-aquire it. + int count = mu->count; + + // Release the monitor mutex. + mu->count = 0; + mu->owner = 0; + pthread_mutex_unlock (&mu->mutex); + + int r = 0; + bool done_sleeping = false; + + while (! done_sleeping) + { + if (millis == 0 && nanos == 0) + r = pthread_cond_wait (¤t->wait_cond, ¤t->wait_mutex); + else + r = pthread_cond_timedwait (¤t->wait_cond, ¤t->wait_mutex, + &ts); + + // In older glibc's (prior to 2.1.3), the cond_wait functions may + // spuriously wake up on a signal. Catch that here. + if (r != EINTR) + done_sleeping = true; + } + + // Check for an interrupt *before* unlocking the wait mutex. + jboolean interrupted = current_obj->interrupt_flag; + + pthread_mutex_unlock (¤t->wait_mutex); + + // Reaquire the monitor mutex, and restore the lock count. + pthread_mutex_lock (&mu->mutex); + mu->owner = self; + mu->count = count; + + // If we were interrupted, or if a timeout occured, remove ourself from + // the cv wait list now. (If we were notified normally, notify() will have + // already taken care of this) + if (r == ETIMEDOUT || interrupted) + { + _Jv_Thread_t *prev = NULL; + for (_Jv_Thread_t *t = cv->first; t != NULL; t = t->next) { -#ifdef LINUX_THREADS - // FIXME: in theory, interrupt() could be called on this thread - // between the test above and the wait below, resulting in the - // interupt() call failing. I don't see a way to fix this - // without significant changes to the implementation. - r = pthread_cond_timedwait (cv, pmu, &ts); -#else - if (millis == 0 && nanos == 0) - r = pthread_cond_wait (cv, pmu); - else - r = pthread_cond_timedwait (cv, pmu, &ts); -#endif - } - - if (r == EINTR) - { - /* We were interrupted by a signal. Either this is - because we were interrupted intentionally (i.e. by - Thread.interrupt()) or by the GC if it is - signal-based. */ - if (current->isInterrupted ()) + if (t == current) { - r = 0; - done_sleeping = true; - } - else - { - /* We were woken up by the GC or another signal. */ - m2 = java::lang::System::currentTimeMillis (); - if (m2 >= m) - { - r = 0; - done_sleeping = true; - } + if (prev != NULL) + prev->next = t->next; + else + cv->first = t->next; + t->next = NULL; + break; } + prev = t; } - else if (r == ETIMEDOUT) - { - /* A timeout is a normal result. */ - r = 0; - done_sleeping = true; - } - else - done_sleeping = true; + if (interrupted) + return _JV_INTERRUPTED; } - while (! done_sleeping); - - return r != 0; + + return 0; } -#ifndef RECURSIVE_MUTEX_IS_DEFAULT - -void -_Jv_MutexInit (_Jv_Mutex_t *mu) +int +_Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu) { -#ifdef HAVE_RECURSIVE_MUTEX - pthread_mutexattr_t *val = NULL; - -#if defined (HAVE_PTHREAD_MUTEXATTR_SETTYPE) - pthread_mutexattr_t attr; - - // If this is slow, then allocate it statically and only initialize - // it once. - pthread_mutexattr_init (&attr); - pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); - val = &attr; -#elif defined (HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) - pthread_mutexattr_t attr; - pthread_mutexattr_init (&attr); - pthread_mutexattr_setkind_np (&attr, PTHREAD_MUTEX_RECURSIVE_NP); - val = &attr; -#endif - - pthread_mutex_init (_Jv_PthreadGetMutex (mu), val); -#ifdef PTHREAD_MUTEX_IS_STRUCT - mu->count = 0; -#endif - -#if defined (HAVE_PTHREAD_MUTEXATTR_SETTYPE) || defined (HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) - pthread_mutexattr_destroy (&attr); -#endif + if (_Jv_PthreadCheckMonitor (mu)) + return _JV_NOT_OWNER; -#else /* HAVE_RECURSIVE_MUTEX */ + _Jv_Thread_t *target; + _Jv_Thread_t *prev = NULL; - // No recursive mutex, so simulate one. - pthread_mutex_init (&mu->mutex, NULL); - pthread_mutex_init (&mu->mutex2, NULL); - pthread_cond_init (&mu->cond, 0); - mu->count = 0; + for (target = cv->first; target != NULL; target = target->next) + { + pthread_mutex_lock (&target->wait_mutex); -#endif /* HAVE_RECURSIVE_MUTEX */ -} + if (target->thread_obj->interrupt_flag) + { + // Don't notify a thread that has already been interrupted. + pthread_mutex_unlock (&target->wait_mutex); + prev = target; + continue; + } -#endif /* not RECURSIVE_MUTEX_IS_DEFAULT */ + pthread_cond_signal (&target->wait_cond); + pthread_mutex_unlock (&target->wait_mutex); -#if ! defined (LINUX_THREADS) && ! defined (HAVE_RECURSIVE_MUTEX) + // Two successive notify() calls should not be delivered to the same + // thread, so we remove the target thread from the cv wait list now. + if (prev == NULL) + cv->first = target->next; + else + prev->next = target->next; + + target->next = NULL; + + break; + } -void -_Jv_MutexDestroy (_Jv_Mutex_t *mu) -{ - pthread_mutex_destroy (&mu->mutex); - pthread_mutex_destroy (&mu->mutex2); - pthread_cond_destroy (&mu->cond); + return 0; } int -_Jv_MutexLock (_Jv_Mutex_t *mu) +_Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu) { - if (pthread_mutex_lock (&mu->mutex)) - return -1; - while (1) + if (_Jv_PthreadCheckMonitor (mu)) + return _JV_NOT_OWNER; + + _Jv_Thread_t *target; + _Jv_Thread_t *prev = NULL; + + for (target = cv->first; target != NULL; target = target->next) { - if (mu->count == 0) - { - // Grab the lock. - mu->thread = pthread_self (); - mu->count = 1; - pthread_mutex_lock (&mu->mutex2); - break; - } - else if (pthread_self () == mu->thread) - { - // Already have the lock. - mu->count += 1; - break; - } - else - { - // Try to acquire the lock. - pthread_cond_wait (&mu->cond, &mu->mutex); - } + pthread_mutex_lock (&target->wait_mutex); + pthread_cond_signal (&target->wait_cond); + pthread_mutex_unlock (&target->wait_mutex); + + if (prev != NULL) + prev->next = NULL; + prev = target; } - pthread_mutex_unlock (&mu->mutex); + if (prev != NULL) + prev->next = NULL; + + cv->first = NULL; + return 0; } -int -_Jv_MutexUnlock (_Jv_Mutex_t *mu) +void +_Jv_ThreadInterrupt (_Jv_Thread_t *data) { - if (pthread_mutex_lock (&mu->mutex)) - return -1; - int r = 0; - if (mu->count == 0 || pthread_self () != mu->thread) - r = -1; - else - { - mu->count -= 1; - if (! mu->count) - { - pthread_mutex_unlock (&mu->mutex2); - pthread_cond_signal (&mu->cond); - } - } - pthread_mutex_unlock (&mu->mutex); - return r; -} + pthread_mutex_lock (&data->wait_mutex); -#endif /* not LINUX_THREADS and not HAVE_RECURSIVE_MUTEX */ + // Set the thread's interrupted flag *after* aquiring its wait_mutex. This + // ensures that there are no races with the interrupt flag being set after + // the waiting thread checks it and before pthread_cond_wait is entered. + data->thread_obj->interrupt_flag = true; + + // Interrupt blocking system calls using a signal. +// pthread_kill (data->thread, INTR); + + pthread_cond_signal (&data->wait_cond); + + pthread_mutex_unlock (&data->wait_mutex); +} static void handle_intr (int) @@ -300,10 +298,14 @@ _Jv_InitThreads (void) } void -_Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *) +_Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *obj) { _Jv_Thread_t *info = new _Jv_Thread_t; info->flags = 0; + info->thread_obj = obj; + + pthread_mutex_init (&info->wait_mutex, NULL); + pthread_cond_init (&info->wait_cond, NULL); // FIXME register a finalizer for INFO here. // FIXME also must mark INFO somehow. @@ -331,10 +333,16 @@ really_start (void *x) { struct starter *info = (struct starter *) x; - pthread_setspecific (_Jv_ThreadKey, info->object); + pthread_setspecific (_Jv_ThreadKey, info->data->thread_obj); pthread_setspecific (_Jv_ThreadDataKey, info->data); - info->method (info->object); + // glibc 2.1.3 doesn't set the value of `thread' until after start_routine + // is called. Since it may need to be accessed from the new thread, work + // around the potential race here by explicitly setting it again. + info->data->thread = pthread_self (); + + info->method (info->data->thread_obj); + if (! (info->data->flags & FLAG_DAEMON)) { pthread_mutex_lock (&daemon_mutex); @@ -343,6 +351,12 @@ really_start (void *x) pthread_cond_signal (&daemon_cond); pthread_mutex_unlock (&daemon_mutex); } + +#ifndef LINUX_THREADS + // Clean up. These calls do nothing on Linux. + pthread_mutex_destroy (&info->data->wait_mutex); + pthread_cond_destroy (&info->data->wait_cond); +#endif /* ! LINUX_THREADS */ return NULL; } @@ -367,7 +381,6 @@ _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, // FIXME: handle marking the info object for GC. info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter)); info->method = meth; - info->object = thread; info->data = data; if (! thread->isDaemon()) @@ -389,6 +402,39 @@ _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, } } +int +_Jv_MutexLock (_Jv_Mutex_t *mu) +{ + pthread_t self = pthread_self (); + if (mu->owner == self) + { + mu->count++; + } + else + { + pthread_mutex_lock (&mu->mutex); + mu->count = 1; + mu->owner = self; + } + return 0; +} + +int +_Jv_MutexUnlock (_Jv_Mutex_t *mu) +{ + if (_Jv_PthreadCheckMonitor (mu)) + return _JV_NOT_OWNER; + + mu->count--; + + if (mu->count == 0) + { + mu->owner = 0; + pthread_mutex_unlock (&mu->mutex); + } + return 0; +} + void _Jv_ThreadWait (void) { @@ -397,9 +443,3 @@ _Jv_ThreadWait (void) pthread_cond_wait (&daemon_cond, &daemon_mutex); pthread_mutex_unlock (&daemon_mutex); } - -void -_Jv_ThreadInterrupt (_Jv_Thread_t *data) -{ - pthread_kill (data->thread, INTR); -} |