aboutsummaryrefslogtreecommitdiff
path: root/lib/libpthread/thread/thr_detach.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/thread/thr_detach.c')
-rw-r--r--lib/libpthread/thread/thr_detach.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c
index 59d363e48674..30b7ce55dbd3 100644
--- a/lib/libpthread/thread/thr_detach.c
+++ b/lib/libpthread/thread/thr_detach.c
@@ -42,7 +42,10 @@ __weak_reference(_pthread_detach, pthread_detach);
int
_pthread_detach(pthread_t pthread)
{
- struct pthread *curthread, *joiner;
+ struct pthread *curthread = _get_curthread();
+ struct pthread *joiner;
+ kse_critical_t crit;
+ int dead;
int rval = 0;
/* Check for invalid calling parameters: */
@@ -50,13 +53,19 @@ _pthread_detach(pthread_t pthread)
/* Return an invalid argument error: */
rval = EINVAL;
+ else if ((rval = _thr_ref_add(curthread, pthread,
+ /*include dead*/1)) != 0) {
+ /* Return an error: */
+ _thr_leave_cancellation_point(curthread);
+ }
+
/* Check if the thread is already detached: */
- else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0)
+ else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
/* Return an error: */
+ _thr_ref_delete(curthread, pthread);
rval = EINVAL;
- else {
+ } else {
/* Lock the detached thread: */
- curthread = _get_curthread();
THR_SCHED_LOCK(curthread, pthread);
/* Flag the thread as detached: */
@@ -65,20 +74,35 @@ _pthread_detach(pthread_t pthread)
/* Retrieve any joining thread and remove it: */
joiner = pthread->joiner;
pthread->joiner = NULL;
+ if (joiner->kseg == pthread->kseg) {
+ /*
+ * We already own the scheduler lock for the joiner.
+ * Take advantage of that and make the joiner runnable.
+ */
+ if (joiner->join_status.thread == pthread) {
+ /*
+ * Set the return value for the woken thread:
+ */
+ joiner->join_status.error = ESRCH;
+ joiner->join_status.ret = NULL;
+ joiner->join_status.thread = NULL;
- /* We are already in a critical region. */
- KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
- if ((pthread->flags & THR_FLAGS_GC_SAFE) != 0) {
- THR_LIST_REMOVE(pthread);
- THR_GCLIST_ADD(pthread);
- atomic_store_rel_int(&_gc_check, 1);
- if (KSE_WAITING(_kse_initial))
- KSE_WAKEUP(_kse_initial);
+ _thr_setrunnable_unlocked(joiner);
+ }
+ joiner = NULL;
}
- KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
-
+ dead = (pthread->flags & THR_FLAGS_GC_SAFE) != 0;
THR_SCHED_UNLOCK(curthread, pthread);
+ if (dead != 0) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+ THR_GCLIST_ADD(pthread);
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ }
+ _thr_ref_delete(curthread, pthread);
+
/* See if there is a thread waiting in pthread_join(): */
if (joiner != NULL) {
/* Lock the joiner before fiddling with it. */