mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-26 02:20:51 +01:00
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:
parent
608f31f640
commit
ccc7b69205
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=86499
@ -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
|
||||
|
@ -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) ==
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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) ==
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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) ==
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user