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