OLD | NEW |
(Empty) | |
| 1 #define _GNU_SOURCE |
| 2 #include <string.h> |
| 3 #include "pthread_impl.h" |
| 4 #include "syscall.h" |
| 5 #include "libc.h" |
| 6 |
| 7 __attribute__((__visibility__("hidden"))) |
| 8 long __cancel(), __syscall_cp_asm(), __syscall_cp_c(); |
| 9 |
| 10 long __cancel() |
| 11 { |
| 12 pthread_t self = __pthread_self(); |
| 13 if (self->canceldisable == PTHREAD_CANCEL_ENABLE || self->cancelasync) |
| 14 pthread_exit(PTHREAD_CANCELED); |
| 15 self->canceldisable = PTHREAD_CANCEL_DISABLE; |
| 16 return -ECANCELED; |
| 17 } |
| 18 |
| 19 long __syscall_cp_asm(volatile void *, syscall_arg_t, |
| 20 syscall_arg_t, syscall_arg_t, syscall_arg_t, |
| 21 syscall_arg_t, syscall_arg_t, syscall_arg_t); |
| 22 |
| 23 long __syscall_cp_c(syscall_arg_t nr, |
| 24 syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, |
| 25 syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) |
| 26 { |
| 27 pthread_t self; |
| 28 long r; |
| 29 int st; |
| 30 |
| 31 if ((st=(self=__pthread_self())->canceldisable) |
| 32 && (st==PTHREAD_CANCEL_DISABLE || nr==SYS_close)) |
| 33 return __syscall(nr, u, v, w, x, y, z); |
| 34 |
| 35 r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); |
| 36 if (r==-EINTR && nr!=SYS_close && self->cancel && |
| 37 self->canceldisable != PTHREAD_CANCEL_DISABLE) |
| 38 r = __cancel(); |
| 39 return r; |
| 40 } |
| 41 |
| 42 static void _sigaddset(sigset_t *set, int sig) |
| 43 { |
| 44 unsigned s = sig-1; |
| 45 set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1)
; |
| 46 } |
| 47 |
| 48 __attribute__((__visibility__("hidden"))) |
| 49 extern const char __cp_begin[1], __cp_end[1], __cp_cancel[1]; |
| 50 |
| 51 static void cancel_handler(int sig, siginfo_t *si, void *ctx) |
| 52 { |
| 53 pthread_t self = __pthread_self(); |
| 54 ucontext_t *uc = ctx; |
| 55 uintptr_t pc = uc->uc_mcontext.MC_PC; |
| 56 |
| 57 a_barrier(); |
| 58 if (!self->cancel || self->canceldisable == PTHREAD_CANCEL_DISABLE) retu
rn; |
| 59 |
| 60 _sigaddset(&uc->uc_sigmask, SIGCANCEL); |
| 61 |
| 62 if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)
__cp_end) { |
| 63 uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel; |
| 64 return; |
| 65 } |
| 66 |
| 67 __syscall(SYS_tkill, self->tid, SIGCANCEL); |
| 68 } |
| 69 |
| 70 void __testcancel() |
| 71 { |
| 72 pthread_t self = __pthread_self(); |
| 73 if (self->cancel && !self->canceldisable) |
| 74 __cancel(); |
| 75 } |
| 76 |
| 77 static void init_cancellation() |
| 78 { |
| 79 struct sigaction sa = { |
| 80 .sa_flags = SA_SIGINFO | SA_RESTART, |
| 81 .sa_sigaction = cancel_handler |
| 82 }; |
| 83 memset(&sa.sa_mask, -1, _NSIG/8); |
| 84 __libc_sigaction(SIGCANCEL, &sa, 0); |
| 85 } |
| 86 |
| 87 int pthread_cancel(pthread_t t) |
| 88 { |
| 89 static int init; |
| 90 if (!init) { |
| 91 init_cancellation(); |
| 92 init = 1; |
| 93 } |
| 94 a_store(&t->cancel, 1); |
| 95 return pthread_kill(t, SIGCANCEL); |
| 96 } |
OLD | NEW |