Because atfork lock is held while forking, a thread cancellation triggered
by atfork handler is unsafe, use intenal flag no_cancel to disable it.
This commit is contained in:
parent
7c243121b7
commit
4173ebef4f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=212841
@ -206,7 +206,7 @@ _pthread_exit_mask(void *status, sigset_t *mask)
|
||||
|
||||
/* Flag this thread as exiting. */
|
||||
curthread->cancelling = 1;
|
||||
curthread->cancel_enable = 0;
|
||||
curthread->no_cancel = 1;
|
||||
curthread->cancel_async = 0;
|
||||
curthread->cancel_point = 0;
|
||||
if (mask != NULL)
|
||||
|
@ -137,7 +137,7 @@ _fork(void)
|
||||
struct pthread *curthread;
|
||||
struct pthread_atfork *af;
|
||||
pid_t ret;
|
||||
int errsave;
|
||||
int errsave, cancelsave;
|
||||
int was_threaded;
|
||||
int rtld_locks[MAX_RTLD_LOCKS];
|
||||
|
||||
@ -145,7 +145,8 @@ _fork(void)
|
||||
return (__sys_fork());
|
||||
|
||||
curthread = _get_curthread();
|
||||
|
||||
cancelsave = curthread->no_cancel;
|
||||
curthread->no_cancel = 1;
|
||||
_thr_rwl_rdlock(&_thr_atfork_lock);
|
||||
|
||||
/* Run down atfork prepare handlers. */
|
||||
@ -223,6 +224,7 @@ _fork(void)
|
||||
af->child();
|
||||
}
|
||||
_thr_rwlock_unlock(&_thr_atfork_lock);
|
||||
curthread->no_cancel = cancelsave;
|
||||
} else {
|
||||
/* Parent process */
|
||||
errsave = errno;
|
||||
@ -244,6 +246,9 @@ _fork(void)
|
||||
}
|
||||
|
||||
_thr_rwlock_unlock(&_thr_atfork_lock);
|
||||
curthread->no_cancel = cancelsave;
|
||||
/* test async cancel */
|
||||
_thr_testcancel(curthread);
|
||||
}
|
||||
errno = errsave;
|
||||
|
||||
|
@ -356,9 +356,9 @@ struct pthread {
|
||||
struct pthread_attr attr;
|
||||
|
||||
#define SHOULD_CANCEL(thr) \
|
||||
((thr)->cancel_pending && \
|
||||
((thr)->cancel_pending && (thr)->cancel_enable && \
|
||||
((thr)->cancel_point || (thr)->cancel_async) && \
|
||||
(thr)->cancel_enable && (thr)->cancelling == 0)
|
||||
(thr)->no_cancel == 0)
|
||||
|
||||
/* Cancellation is enabled */
|
||||
int cancel_enable;
|
||||
@ -369,8 +369,8 @@ struct pthread {
|
||||
/* Thread is at cancellation point */
|
||||
int cancel_point;
|
||||
|
||||
/* Cancellation should be synchoronized */
|
||||
int cancel_defer;
|
||||
/* Cancellation is temporarily disabled */
|
||||
int no_cancel;
|
||||
|
||||
/* Asynchronouse cancellation is enabled */
|
||||
int cancel_async;
|
||||
|
@ -187,7 +187,6 @@ handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
|
||||
struct pthread *curthread = _get_curthread();
|
||||
ucontext_t uc2;
|
||||
__siginfohandler_t *sigfunc;
|
||||
int cancel_defer;
|
||||
int cancel_point;
|
||||
int cancel_async;
|
||||
int cancel_enable;
|
||||
@ -213,12 +212,10 @@ handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
|
||||
* cancellation is pending, to avoid this problem while thread is in
|
||||
* deferring mode, cancellation is temporarily disabled.
|
||||
*/
|
||||
cancel_defer = curthread->cancel_defer;
|
||||
cancel_point = curthread->cancel_point;
|
||||
cancel_async = curthread->cancel_async;
|
||||
cancel_enable = curthread->cancel_enable;
|
||||
curthread->cancel_point = 0;
|
||||
curthread->cancel_defer = 0;
|
||||
if (!cancel_async)
|
||||
curthread->cancel_enable = 0;
|
||||
|
||||
@ -245,7 +242,6 @@ handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
|
||||
err = errno;
|
||||
|
||||
curthread->in_sigsuspend = in_sigsuspend;
|
||||
curthread->cancel_defer = cancel_defer;
|
||||
curthread->cancel_point = cancel_point;
|
||||
curthread->cancel_enable = cancel_enable;
|
||||
|
||||
@ -275,7 +271,7 @@ check_cancel(struct pthread *curthread, ucontext_t *ucp)
|
||||
{
|
||||
|
||||
if (__predict_true(!curthread->cancel_pending || !curthread->cancel_enable ||
|
||||
curthread->cancelling))
|
||||
curthread->no_cancel))
|
||||
return;
|
||||
|
||||
if (curthread->cancel_async) {
|
||||
|
Loading…
Reference in New Issue
Block a user