2 #include "pthread_impl.h"
3 #include "stdio_impl.h"
12 weak_alias(dummy_0, __acquire_ptc);
13 weak_alias(dummy_0, __release_ptc);
14 weak_alias(dummy_0, __pthread_tsd_run_dtors);
15 weak_alias(dummy_0, __do_orphaned_stdio_locks);
16 weak_alias(dummy_0, __dl_thread_cleanup);
18 static void *dummy_1(void *p)
22 weak_alias(dummy_1, __start_sched);
24 _Noreturn void __pthread_exit(void *result)
26 pthread_t self = __pthread_self();
29 self->canceldisable = 1;
30 self->cancelasync = 0;
31 self->result = result;
33 while (self->cancelbuf) {
34 void (*f)(void *) = self->cancelbuf->__f;
35 void *x = self->cancelbuf->__x;
36 self->cancelbuf = self->cancelbuf->__next;
40 __pthread_tsd_run_dtors();
42 /* Access to target the exiting thread with syscalls that use
43 * its kernel tid is controlled by killlock. For detached threads,
44 * any use past this point would have undefined behavior, but for
45 * joinable threads it's a valid usage that must be handled. */
48 /* Block all signals before decrementing the live thread count.
49 * This is important to ensure that dynamically allocated TLS
50 * is not under-allocated/over-committed, and possibly for other
52 __block_all_sigs(&set);
54 /* It's impossible to determine whether this is "the last thread"
55 * until performing the atomic decrement, since multiple threads
56 * could exit at the same time. For the last thread, revert the
57 * decrement, restore the tid, and unblock signals to give the
58 * atexit handlers and stdio cleanup code a consistent state. */
59 if (a_fetch_add(&libc.threads_minus_1, -1)==0) {
60 libc.threads_minus_1 = 0;
61 UNLOCK(self->killlock);
66 /* Process robust list in userspace to handle non-pshared mutexes
67 * and the detached thread case where the robust list head will
68 * be invalid when the kernel would process it. */
70 volatile void *volatile *rp;
71 while ((rp=self->robust_list.head) && rp != &self->robust_list.head) {
72 pthread_mutex_t *m = (void *)((char *)rp
73 - offsetof(pthread_mutex_t, _m_next));
74 int waiters = m->_m_waiters;
75 int priv = (m->_m_type & 128) ^ 128;
76 self->robust_list.pending = rp;
77 self->robust_list.head = *rp;
78 int cont = a_swap(&m->_m_lock, 0x40000000);
79 self->robust_list.pending = 0;
80 if (cont < 0 || waiters)
81 __wake(&m->_m_lock, 1, priv);
85 __do_orphaned_stdio_locks();
86 __dl_thread_cleanup();
88 /* This atomic potentially competes with a concurrent pthread_detach
89 * call; the loser is responsible for freeing thread resources. */
90 int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING);
92 if (state>=DT_DETACHED && self->map_base) {
93 /* Detached threads must avoid the kernel clear_child_tid
94 * feature, since the virtual address will have been
95 * unmapped and possibly already reused by a new mapping
96 * at the time the kernel would perform the write. In
97 * the case of threads that started out detached, the
98 * initial clone flags are correct, but if the thread was
99 * detached later, we need to clear it here. */
100 if (state == DT_DYNAMIC) __syscall(SYS_set_tid_address, 0);
102 /* Robust list will no longer be valid, and was already
103 * processed above, so unregister it with the kernel. */
104 if (self->robust_list.off)
105 __syscall(SYS_set_robust_list, 0, 3*sizeof(long));
107 /* Since __unmapself bypasses the normal munmap code path,
108 * explicitly wait for vmlock holders first. */
111 /* The following call unmaps the thread's stack mapping
112 * and then exits without touching the stack. */
113 __unmapself(self->map_base, self->map_size);
116 /* After the kernel thread exits, its tid may be reused. Clear it
117 * to prevent inadvertent use and inform functions that would use
118 * it that it's no longer available. */
120 UNLOCK(self->killlock);
122 for (;;) __syscall(SYS_exit, 0);
125 void __do_cleanup_push(struct __ptcb *cb)
127 struct pthread *self = __pthread_self();
128 cb->__next = self->cancelbuf;
129 self->cancelbuf = cb;
132 void __do_cleanup_pop(struct __ptcb *cb)
134 __pthread_self()->cancelbuf = cb->__next;
137 static int start(void *p)
140 if (self->unblock_cancel)
141 __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
142 SIGPT_SET, 0, _NSIG/8);
143 __pthread_exit(self->start(self->start_arg));
147 static int start_c11(void *p)
150 int (*start)(void*) = (int(*)(void*)) self->start;
151 __pthread_exit((void *)(uintptr_t)start(self->start_arg));
155 #define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
157 /* pthread_key_create.c overrides this */
158 static volatile size_t dummy = 0;
159 weak_alias(dummy, __pthread_tsd_size);
160 static void *dummy_tsd[1] = { 0 };
161 weak_alias(dummy_tsd, __pthread_tsd_main);
163 volatile int __block_new_threads = 0;
164 extern size_t __default_stacksize;
165 extern size_t __default_guardsize;
167 static FILE *volatile dummy_file = 0;
168 weak_alias(dummy_file, __stdin_used);
169 weak_alias(dummy_file, __stdout_used);
170 weak_alias(dummy_file, __stderr_used);
172 static void init_file_lock(FILE *f)
174 if (f && f->lock<0) f->lock = 0;
177 int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg)
179 int ret, c11 = (attrp == __ATTRP_C11_THREAD);
181 struct pthread *self, *new;
182 unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit;
183 unsigned flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
184 | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS
185 | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED;
187 pthread_attr_t attr = { 0 };
188 struct start_sched_args ssa;
190 if (!libc.can_do_threads) return ENOSYS;
191 self = __pthread_self();
192 if (!libc.threaded) {
193 for (FILE *f=*__ofl_lock(); f; f=f->next)
196 init_file_lock(__stdin_used);
197 init_file_lock(__stdout_used);
198 init_file_lock(__stderr_used);
199 __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8);
200 self->tsd = (void **)__pthread_tsd_main;
203 if (attrp && !c11) attr = *attrp;
207 attr._a_stacksize = __default_stacksize;
208 attr._a_guardsize = __default_guardsize;
211 if (__block_new_threads) __wait(&__block_new_threads, 0, 1, 1);
213 if (attr._a_stackaddr) {
214 size_t need = libc.tls_size + __pthread_tsd_size;
215 size = attr._a_stacksize;
216 stack = (void *)(attr._a_stackaddr & -16);
217 stack_limit = (void *)(attr._a_stackaddr - size);
218 /* Use application-provided stack for TLS only when
219 * it does not take more than ~12% or 2k of the
220 * application's stack space. */
221 if (need < size/8 && need < 2048) {
222 tsd = stack - __pthread_tsd_size;
223 stack = tsd - libc.tls_size;
224 memset(stack, 0, need);
230 guard = ROUND(attr._a_guardsize);
231 size = guard + ROUND(attr._a_stacksize
232 + libc.tls_size + __pthread_tsd_size);
237 map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
238 if (map == MAP_FAILED) goto fail;
239 if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)
240 && errno != ENOSYS) {
245 map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
246 if (map == MAP_FAILED) goto fail;
248 tsd = map + size - __pthread_tsd_size;
250 stack = tsd - libc.tls_size;
251 stack_limit = map + guard;
255 new = __copy_tls(tsd - libc.tls_size);
257 new->map_size = size;
259 new->stack_size = stack - stack_limit;
260 new->guard_size = guard;
262 new->start_arg = arg;
264 new->tsd = (void *)tsd;
265 new->locale = &libc.global_locale;
266 if (attr._a_detach) {
267 new->detach_state = DT_DETACHED;
268 flags -= CLONE_CHILD_CLEARTID;
270 new->detach_state = DT_JOINABLE;
275 ssa.start_fn = new->start;
276 ssa.start_arg = new->start_arg;
278 new->start = __start_sched;
279 new->start_arg = &ssa;
280 __block_app_sigs(&ssa.mask);
282 new->robust_list.head = &new->robust_list.head;
283 new->unblock_cancel = self->cancel;
284 new->CANARY = self->CANARY;
286 a_inc(&libc.threads_minus_1);
287 ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->detach_state);
292 __restore_sigs(&ssa.mask);
296 a_dec(&libc.threads_minus_1);
297 if (map) __munmap(map, size);
302 __futexwait(&ssa.futex, -1, 1);
314 weak_alias(__pthread_exit, pthread_exit);
315 weak_alias(__pthread_create, pthread_create);