summaryrefslogtreecommitdiffstats
path: root/lib/libc_r
diff options
context:
space:
mode:
authordeischen <deischen@FreeBSD.org>2001-11-17 14:28:39 +0000
committerdeischen <deischen@FreeBSD.org>2001-11-17 14:28:39 +0000
commitb43c906fd478d13c3c092a2c7ba3198b5557eac6 (patch)
treed9b490926b6ae401659e2052a1b89c5bea09c6d4 /lib/libc_r
parent82943ba6834c1d4951740dd6dd59a8ff1373b2f8 (diff)
downloadFreeBSD-src-b43c906fd478d13c3c092a2c7ba3198b5557eac6.zip
FreeBSD-src-b43c906fd478d13c3c092a2c7ba3198b5557eac6.tar.gz
Fix pthread_join so that it works if the target thread exits while
the joining thread is in a signal handler. Reported by: Loren James Rittle <rittle@labs.mot.com> MFC after: 1 week
Diffstat (limited to 'lib/libc_r')
-rw-r--r--lib/libc_r/uthread/pthread_private.h13
-rw-r--r--lib/libc_r/uthread/uthread_exit.c5
-rw-r--r--lib/libc_r/uthread/uthread_join.c12
-rw-r--r--lib/libc_r/uthread/uthread_sig.c12
4 files changed, 32 insertions, 10 deletions
diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h
index 151fd03..b60d8b7 100644
--- a/lib/libc_r/uthread/pthread_private.h
+++ b/lib/libc_r/uthread/pthread_private.h
@@ -601,6 +601,11 @@ struct pthread_state_data {
/* XXX - What about thread->timeout and/or thread->error? */
};
+struct join_status {
+ struct pthread *thread;
+ int ret;
+ int error;
+};
/*
* Normally thread contexts are stored as jmp_bufs via _setjmp()/_longjmp(),
@@ -757,8 +762,12 @@ struct pthread {
*/
int error;
- /* Pointer to a thread that is waiting to join (NULL if no joiner). */
- struct pthread *joiner;
+ /*
+ * The joiner is the thread that is joining to this thread. The
+ * join status keeps track of a join operation to another thread.
+ */
+ struct pthread *joiner;
+ struct join_status join_status;
/*
* The current thread can belong to only one scheduling queue at
diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c
index 9376350..d916f5c 100644
--- a/lib/libc_r/uthread/uthread_exit.c
+++ b/lib/libc_r/uthread/uthread_exit.c
@@ -220,8 +220,9 @@ _pthread_exit(void *status)
}
/* Set the return value for the joining thread: */
- pthread->ret = curthread->ret;
- pthread->error = 0;
+ pthread->join_status.ret = curthread->ret;
+ pthread->join_status.error = 0;
+ pthread->join_status.thread = NULL;
/* Make this thread collectable by the garbage collector. */
PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) ==
diff --git a/lib/libc_r/uthread/uthread_join.c b/lib/libc_r/uthread/uthread_join.c
index 454c79a..0f5e8fc 100644
--- a/lib/libc_r/uthread/uthread_join.c
+++ b/lib/libc_r/uthread/uthread_join.c
@@ -122,18 +122,20 @@ _pthread_join(pthread_t pthread, void **thread_return)
pthread->joiner = curthread;
/* Keep track of which thread we're joining to: */
- curthread->data.thread = pthread;
+ curthread->join_status.thread = pthread;
- /* Schedule the next thread: */
- _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
+ while (curthread->join_status.thread == pthread) {
+ /* Schedule the next thread: */
+ _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
+ }
/*
* The thread return value and error are set by the thread we're
* joining to when it exits or detaches:
*/
- ret = curthread->error;
+ ret = curthread->join_status.error;
if ((ret == 0) && (thread_return != NULL))
- *thread_return = curthread->ret;
+ *thread_return = curthread->join_status.ret;
} else {
/*
* The thread exited (is dead) without being detached, and no
diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c
index 9ca197e..a05f914 100644
--- a/lib/libc_r/uthread/uthread_sig.c
+++ b/lib/libc_r/uthread/uthread_sig.c
@@ -671,7 +671,6 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
* signal handler to run:
*/
case PS_COND_WAIT:
- case PS_JOIN:
case PS_MUTEX_WAIT:
/*
* Remove the thread from the wait queue. It will
@@ -681,6 +680,17 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
PTHREAD_WAITQ_REMOVE(pthread);
break;
+ case PS_JOIN:
+ /*
+ * Remove the thread from the wait queue. It will
+ * be added back to the wait queue once all signal
+ * handlers have been invoked.
+ */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ /* Make the thread runnable: */
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
/*
* States which are interruptible but may need to be removed
* from queues before any signal handler is called.
OpenPOWER on IntegriCloud