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 |