use a separate signal from SIGCANCEL for SIGEV_THREAD timers
[musl] / src / thread / pthread_create.c
1 #include "pthread_impl.h"
2
3 static void dummy_0()
4 {
5 }
6 weak_alias(dummy_0, __rsyscall_lock);
7 weak_alias(dummy_0, __rsyscall_unlock);
8
9 static void dummy_1(pthread_t self)
10 {
11 }
12 weak_alias(dummy_1, __pthread_tsd_run_dtors);
13
14 #ifdef __pthread_unwind_next
15 #undef __pthread_unwind_next
16 #define __pthread_unwind_next __pthread_unwind_next_3
17 #endif
18
19 void __pthread_unwind_next(struct __ptcb *cb)
20 {
21         pthread_t self;
22
23         if (cb->__next) longjmp((void *)cb->__next->__jb, 1);
24
25         self = pthread_self();
26
27         LOCK(&self->exitlock);
28
29         __pthread_tsd_run_dtors(self);
30
31         /* Mark this thread dead before decrementing count */
32         self->dead = 1;
33
34         if (!a_fetch_add(&libc.threads_minus_1, -1))
35                 exit(0);
36
37         if (self->detached && self->map_base) {
38                 __syscall(SYS_rt_sigprocmask, SIG_BLOCK, (long)(uint64_t[1]){-1},0,8);
39                 __unmapself(self->map_base, self->map_size);
40         }
41
42         __syscall(SYS_exit, 0);
43 }
44
45 static void docancel(struct pthread *self)
46 {
47         struct __ptcb cb = { .__next = self->cancelbuf };
48         self->canceldisable = 1;
49         self->cancelasync = 0;
50         __pthread_unwind_next(&cb);
51 }
52
53 static void cancel_handler(int sig, siginfo_t *si, void *ctx)
54 {
55         struct pthread *self = __pthread_self();
56         if (self->cancel && !self->canceldisable &&
57             (self->cancelasync || (self->cancelpoint==1 && PC_AT_SYS(ctx))))
58                 docancel(self);
59 }
60
61 static void cancelpt(int x)
62 {
63         struct pthread *self = __pthread_self();
64         if ((self->cancelpoint+=x)==1 && self->cancel
65                 && x<2U && !self->canceldisable) docancel(self);
66 }
67
68 static void init_threads()
69 {
70         struct sigaction sa = { .sa_flags = SA_SIGINFO | SA_RESTART };
71         libc.lock = __lock;
72         libc.lockfile = __lockfile;
73         libc.cancelpt = cancelpt;
74
75         sigemptyset(&sa.sa_mask);
76         sa.sa_sigaction = cancel_handler;
77         __libc_sigaction(SIGCANCEL, &sa, 0);
78
79         sigaddset(&sa.sa_mask, SIGSYSCALL);
80         sigaddset(&sa.sa_mask, SIGCANCEL);
81         __libc_sigprocmask(SIG_UNBLOCK, &sa.sa_mask, 0);
82 }
83
84 static int start(void *p)
85 {
86         struct pthread *self = p;
87         if (self->unblock_cancel) {
88                 sigset_t set;
89                 sigemptyset(&set);
90                 sigaddset(&set, SIGCANCEL);
91                 __libc_sigprocmask(SIG_UNBLOCK, &set, 0);
92         }
93         pthread_exit(self->start(self->start_arg));
94         return 0;
95 }
96
97 int __uniclone(void *, int (*)(), void *);
98
99 #define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
100
101 /* pthread_key_create.c overrides this */
102 static const size_t dummy = 0;
103 weak_alias(dummy, __pthread_tsd_size);
104
105 int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(void *), void *arg)
106 {
107         static int init;
108         int ret;
109         size_t size, guard;
110         struct pthread *self = pthread_self(), *new;
111         unsigned char *map, *stack, *tsd;
112         const pthread_attr_t default_attr = { 0 };
113
114         if (!self) return ENOSYS;
115         if (!init && ++init) init_threads();
116
117         if (!attr) attr = &default_attr;
118         guard = ROUND(attr->_a_guardsize + DEFAULT_GUARD_SIZE);
119         size = guard + ROUND(attr->_a_stacksize + DEFAULT_STACK_SIZE);
120         size += __pthread_tsd_size;
121         map = mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
122         if (!map) return EAGAIN;
123         if (guard) mprotect(map, guard, PROT_NONE);
124
125         tsd = map + size - __pthread_tsd_size;
126         new = (void *)(tsd - sizeof *new - PAGE_SIZE%sizeof *new);
127         new->map_base = map;
128         new->map_size = size;
129         new->pid = self->pid;
130         new->errno_ptr = &new->errno_val;
131         new->start = entry;
132         new->start_arg = arg;
133         new->self = new;
134         new->tsd = (void *)tsd;
135         new->detached = attr->_a_detach;
136         new->attr = *attr;
137         new->unblock_cancel = self->cancel;
138         new->result = PTHREAD_CANCELED;
139         memcpy(new->tlsdesc, self->tlsdesc, sizeof new->tlsdesc);
140         new->tlsdesc[1] = (uintptr_t)new;
141         stack = (void *)((uintptr_t)new-1 & ~(uintptr_t)15);
142
143         __rsyscall_lock();
144
145         a_inc(&libc.threads_minus_1);
146         ret = __uniclone(stack, start, new);
147
148         __rsyscall_unlock();
149
150         if (ret < 0) {
151                 a_dec(&libc.threads_minus_1);
152                 munmap(map, size);
153                 return EAGAIN;
154         }
155         *res = new;
156         return 0;
157 }
158
159 void pthread_exit(void *result)
160 {
161         struct pthread *self = pthread_self();
162         self->result = result;
163         docancel(self);
164 }