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