diff options
author | davidxu <davidxu@FreeBSD.org> | 2010-09-21 06:47:04 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2010-09-21 06:47:04 +0000 |
commit | 585e6320d26e15f5dff4229f1a26ce1e355a6c11 (patch) | |
tree | 760e6d7b8318698197d8b89fb444c785f39ea09c /lib/libthr | |
parent | daa9ae80c8f7311a4f1186dcf7b9ca8293a17450 (diff) | |
download | FreeBSD-src-585e6320d26e15f5dff4229f1a26ce1e355a6c11.zip FreeBSD-src-585e6320d26e15f5dff4229f1a26ce1e355a6c11.tar.gz |
If we are at cancellation point, always work as deferred mode despite
whether asynchronous mode is turned on or not, this always gives us a
chance to decide whether thread should be canceled or not in
cancellation points.
Diffstat (limited to 'lib/libthr')
-rw-r--r-- | lib/libthr/thread/thr_sig.c | 66 |
1 files changed, 32 insertions, 34 deletions
diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c index a9b8d1c..a2c1e53 100644 --- a/lib/libthr/thread/thr_sig.c +++ b/lib/libthr/thread/thr_sig.c @@ -270,46 +270,44 @@ static void check_cancel(struct pthread *curthread, ucontext_t *ucp) { - if (__predict_true(!curthread->cancel_pending || !curthread->cancel_enable || - curthread->no_cancel)) + if (__predict_true(!curthread->cancel_pending || + !curthread->cancel_enable || curthread->no_cancel)) return; - if (curthread->cancel_async) { + /* + * Otherwise, we are in defer mode, and we are at + * cancel point, tell kernel to not block the current + * thread on next cancelable system call. + * + * There are three cases we should call thr_wake() to + * turn on TDP_WAKEUP or send SIGCANCEL in kernel: + * 1) we are going to call a cancelable system call, + * non-zero cancel_point means we are already in + * cancelable state, next system call is cancelable. + * 2) because _thr_ast() may be called by + * THR_CRITICAL_LEAVE() which is used by rtld rwlock + * and any libthr internal locks, when rtld rwlock + * is used, it is mostly caused my an unresolved PLT. + * those routines may clear the TDP_WAKEUP flag by + * invoking some system calls, in those cases, we + * also should reenable the flag. + * 3) thread is in sigsuspend(), and the syscall insists + * on getting a signal before it agrees to return. + */ + if (curthread->cancel_point) { + if (curthread->in_sigsuspend && ucp) { + SIGADDSET(ucp->uc_sigmask, SIGCANCEL); + curthread->unblock_sigcancel = 1; + _thr_send_sig(curthread, SIGCANCEL); + } else + thr_wake(curthread->tid); + } else if (curthread->cancel_async) { /* - * asynchronous cancellation mode, act upon + * asynchronous cancellation mode, act upon * immediately. - */ + */ _pthread_exit_mask(PTHREAD_CANCELED, ucp? &ucp->uc_sigmask : NULL); - } else { - /* - * Otherwise, we are in defer mode, and we are at - * cancel point, tell kernel to not block the current - * thread on next cancelable system call. - * - * There are three cases we should call thr_wake() to - * turn on TDP_WAKEUP or send SIGCANCEL in kernel: - * 1) we are going to call a cancelable system call, - * non-zero cancel_point means we are already in - * cancelable state, next system call is cancelable. - * 2) because _thr_ast() may be called by - * THR_CRITICAL_LEAVE() which is used by rtld rwlock - * and any libthr internal locks, when rtld rwlock - * is used, it is mostly caused my an unresolved PLT. - * those routines may clear the TDP_WAKEUP flag by - * invoking some system calls, in those cases, we - * also should reenable the flag. - * 3) thread is in sigsuspend(), and the syscall insists - * on getting a signal before it agrees to return. - */ - if (curthread->cancel_point) { - if (curthread->in_sigsuspend && ucp) { - SIGADDSET(ucp->uc_sigmask, SIGCANCEL); - curthread->unblock_sigcancel = 1; - _thr_send_sig(curthread, SIGCANCEL); - } else - thr_wake(curthread->tid); - } } } |