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
This commit is contained in:
Daniel Eischen 2001-11-17 14:28:39 +00:00
parent 608f31f640
commit ccc7b69205
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=86499
12 changed files with 96 additions and 30 deletions

View File

@ -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

View File

@ -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) ==

View File

@ -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

View File

@ -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.

View File

@ -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) ==

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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) ==

View File

@ -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

View File

@ -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

View File

@ -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.