]> git.proxmox.com Git - wasi-libc.git/blame - libc-top-half/musl/src/thread/pthread_create.c
wasi_thread_start: remove a useless cast (#354)
[wasi-libc.git] / libc-top-half / musl / src / thread / pthread_create.c
CommitLineData
320054e8
DG
1#define _GNU_SOURCE
2#include "pthread_impl.h"
3#include "stdio_impl.h"
4#include "libc.h"
5#include "lock.h"
241060c3 6#ifdef __wasilibc_unmodified_upstream
320054e8 7#include <sys/mman.h>
241060c3 8#endif
320054e8
DG
9#include <string.h>
10#include <stddef.h>
241060c3
AB
11#ifndef __wasilibc_unmodified_upstream
12#include <stdatomic.h>
13#endif
320054e8 14
a00bf321 15#include <stdalign.h>
16
320054e8
DG
17static void dummy_0()
18{
19}
20weak_alias(dummy_0, __acquire_ptc);
21weak_alias(dummy_0, __release_ptc);
22weak_alias(dummy_0, __pthread_tsd_run_dtors);
23weak_alias(dummy_0, __do_orphaned_stdio_locks);
241060c3 24#ifdef __wasilibc_unmodified_upstream
320054e8 25weak_alias(dummy_0, __dl_thread_cleanup);
f41256b6 26weak_alias(dummy_0, __membarrier_init);
241060c3 27#endif
320054e8 28
f41256b6
DG
29static int tl_lock_count;
30static int tl_lock_waiters;
31
32void __tl_lock(void)
320054e8 33{
f41256b6
DG
34 int tid = __pthread_self()->tid;
35 int val = __thread_list_lock;
36 if (val == tid) {
37 tl_lock_count++;
38 return;
39 }
40 while ((val = a_cas(&__thread_list_lock, 0, tid)))
41 __wait(&__thread_list_lock, &tl_lock_waiters, val, 0);
42}
43
44void __tl_unlock(void)
45{
46 if (tl_lock_count) {
47 tl_lock_count--;
48 return;
49 }
50 a_store(&__thread_list_lock, 0);
51 if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0);
52}
53
54void __tl_sync(pthread_t td)
55{
56 a_barrier();
57 int val = __thread_list_lock;
58 if (!val) return;
59 __wait(&__thread_list_lock, &tl_lock_waiters, val, 0);
60 if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0);
320054e8 61}
320054e8
DG
62
63_Noreturn void __pthread_exit(void *result)
64{
65 pthread_t self = __pthread_self();
66 sigset_t set;
67
68 self->canceldisable = 1;
69 self->cancelasync = 0;
70 self->result = result;
71
72 while (self->cancelbuf) {
73 void (*f)(void *) = self->cancelbuf->__f;
74 void *x = self->cancelbuf->__x;
75 self->cancelbuf = self->cancelbuf->__next;
76 f(x);
77 }
78
79 __pthread_tsd_run_dtors();
80
241060c3 81#ifdef __wasilibc_unmodified_upstream
322bd4ff 82 __block_app_sigs(&set);
241060c3 83#endif
322bd4ff
DG
84
85 /* This atomic potentially competes with a concurrent pthread_detach
86 * call; the loser is responsible for freeing thread resources. */
87 int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING);
88
89 if (state==DT_DETACHED && self->map_base) {
90 /* Since __unmapself bypasses the normal munmap code path,
91 * explicitly wait for vmlock holders first. This must be
92 * done before any locks are taken, to avoid lock ordering
93 * issues that could lead to deadlock. */
241060c3 94#ifdef __wasilibc_unmodified_upstream
322bd4ff 95 __vm_wait();
241060c3 96#endif
322bd4ff
DG
97 }
98
320054e8
DG
99 /* Access to target the exiting thread with syscalls that use
100 * its kernel tid is controlled by killlock. For detached threads,
101 * any use past this point would have undefined behavior, but for
58795582
DG
102 * joinable threads it's a valid usage that must be handled.
103 * Signals must be blocked since pthread_kill must be AS-safe. */
320054e8
DG
104 LOCK(self->killlock);
105
58795582
DG
106 /* The thread list lock must be AS-safe, and thus depends on
107 * application signals being blocked above. */
f41256b6
DG
108 __tl_lock();
109
110 /* If this is the only thread in the list, don't proceed with
111 * termination of the thread, but restore the previous lock and
112 * signal state to prepare for exit to call atexit handlers. */
113 if (self->next == self) {
114 __tl_unlock();
f41256b6 115 UNLOCK(self->killlock);
322bd4ff 116 self->detach_state = state;
241060c3 117#ifdef __wasilibc_unmodified_upstream
58795582 118 __restore_sigs(&set);
241060c3 119#endif
320054e8
DG
120 exit(0);
121 }
122
58795582 123 /* At this point we are committed to thread termination. */
f41256b6 124
241060c3 125#ifdef __wasilibc_unmodified_upstream
320054e8
DG
126 /* Process robust list in userspace to handle non-pshared mutexes
127 * and the detached thread case where the robust list head will
128 * be invalid when the kernel would process it. */
129 __vm_lock();
241060c3 130#endif
320054e8
DG
131 volatile void *volatile *rp;
132 while ((rp=self->robust_list.head) && rp != &self->robust_list.head) {
133 pthread_mutex_t *m = (void *)((char *)rp
134 - offsetof(pthread_mutex_t, _m_next));
135 int waiters = m->_m_waiters;
136 int priv = (m->_m_type & 128) ^ 128;
137 self->robust_list.pending = rp;
138 self->robust_list.head = *rp;
139 int cont = a_swap(&m->_m_lock, 0x40000000);
140 self->robust_list.pending = 0;
141 if (cont < 0 || waiters)
142 __wake(&m->_m_lock, 1, priv);
143 }
241060c3 144#ifdef __wasilibc_unmodified_upstream
320054e8 145 __vm_unlock();
241060c3 146#endif
320054e8
DG
147
148 __do_orphaned_stdio_locks();
241060c3 149#ifdef __wasilibc_unmodified_upstream
320054e8 150 __dl_thread_cleanup();
241060c3 151#endif
320054e8 152
58795582
DG
153 /* Last, unlink thread from the list. This change will not be visible
154 * until the lock is released, which only happens after SYS_exit
155 * has been called, via the exit futex address pointing at the lock.
156 * This needs to happen after any possible calls to LOCK() that might
157 * skip locking if process appears single-threaded. */
158 if (!--libc.threads_minus_1) libc.need_locks = -1;
159 self->next->prev = self->prev;
160 self->prev->next = self->next;
161 self->prev = self->next = self;
162
a00bf321 163#ifndef __wasilibc_unmodified_upstream
164 /* On Linux, the thread is created with CLONE_CHILD_CLEARTID,
165 * and this lock will unlock by kernel when this thread terminates.
166 * So we should unlock it here in WebAssembly.
167 * See also set_tid_address(2) */
168 __tl_unlock();
169#endif
170
241060c3 171#ifdef __wasilibc_unmodified_upstream
f41256b6
DG
172 if (state==DT_DETACHED && self->map_base) {
173 /* Detached threads must block even implementation-internal
174 * signals, since they will not have a stack in their last
175 * moments of existence. */
176 __block_all_sigs(&set);
320054e8
DG
177
178 /* Robust list will no longer be valid, and was already
179 * processed above, so unregister it with the kernel. */
180 if (self->robust_list.off)
181 __syscall(SYS_set_robust_list, 0, 3*sizeof(long));
182
320054e8
DG
183 /* The following call unmaps the thread's stack mapping
184 * and then exits without touching the stack. */
185 __unmapself(self->map_base, self->map_size);
186 }
a00bf321 187#else
188 if (state==DT_DETACHED && self->map_base) {
189 // __syscall(SYS_exit) would unlock the thread, list
190 // do it manually here
191 __tl_unlock();
192 free(self->map_base);
193 // Can't use `exit()` here, because it is too high level
194 for (;;) __wasi_proc_exit(0);
195 }
241060c3 196#endif
320054e8 197
f41256b6 198 /* Wake any joiner. */
322bd4ff 199 a_store(&self->detach_state, DT_EXITED);
f41256b6
DG
200 __wake(&self->detach_state, 1, 1);
201
320054e8
DG
202 /* After the kernel thread exits, its tid may be reused. Clear it
203 * to prevent inadvertent use and inform functions that would use
204 * it that it's no longer available. */
205 self->tid = 0;
206 UNLOCK(self->killlock);
207
241060c3 208#ifdef __wasilibc_unmodified_upstream
320054e8 209 for (;;) __syscall(SYS_exit, 0);
241060c3 210#else
a00bf321 211 // __syscall(SYS_exit) would unlock the thread, list
212 // do it manually here
213 __tl_unlock();
214 // Can't use `exit()` here, because it is too high level
215 for (;;) __wasi_proc_exit(0);
241060c3 216#endif
320054e8
DG
217}
218
219void __do_cleanup_push(struct __ptcb *cb)
220{
221 struct pthread *self = __pthread_self();
222 cb->__next = self->cancelbuf;
223 self->cancelbuf = cb;
224}
225
226void __do_cleanup_pop(struct __ptcb *cb)
227{
228 __pthread_self()->cancelbuf = cb->__next;
229}
230
f41256b6 231struct start_args {
241060c3 232#ifdef __wasilibc_unmodified_upstream
f41256b6
DG
233 void *(*start_func)(void *);
234 void *start_arg;
79a9b408 235 volatile int control;
f41256b6 236 unsigned long sig_mask[_NSIG/8/sizeof(long)];
241060c3
AB
237#else
238 void *(*start_func)(void *);
239 void *start_arg;
a00bf321 240 void *tls_base;
241060c3 241#endif
f41256b6
DG
242};
243
241060c3 244#ifdef __wasilibc_unmodified_upstream
320054e8
DG
245static int start(void *p)
246{
f41256b6 247 struct start_args *args = p;
79a9b408
DG
248 int state = args->control;
249 if (state) {
250 if (a_cas(&args->control, 1, 2)==1)
251 __wait(&args->control, 0, 2, 1);
252 if (args->control) {
241060c3 253#ifdef __wasilibc_unmodified_upstream
79a9b408
DG
254 __syscall(SYS_set_tid_address, &args->control);
255 for (;;) __syscall(SYS_exit, 0);
241060c3 256#endif
f41256b6
DG
257 }
258 }
241060c3 259#ifdef __wasilibc_unmodified_upstream
f41256b6 260 __syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->sig_mask, 0, _NSIG/8);
241060c3 261#endif
f41256b6 262 __pthread_exit(args->start_func(args->start_arg));
320054e8
DG
263 return 0;
264}
265
266static int start_c11(void *p)
267{
f41256b6
DG
268 struct start_args *args = p;
269 int (*start)(void*) = (int(*)(void*)) args->start_func;
270 __pthread_exit((void *)(uintptr_t)start(args->start_arg));
320054e8
DG
271 return 0;
272}
241060c3
AB
273#else
274__attribute__((export_name("wasi_thread_start")))
a00bf321 275_Noreturn void wasi_thread_start(int tid, void *p)
241060c3
AB
276{
277 struct start_args *args = p;
a00bf321 278 __asm__(".globaltype __tls_base, i32\n"
279 "local.get %0\n"
280 "global.set __tls_base\n"
281 :: "r"(args->tls_base));
282 pthread_t self = __pthread_self();
241060c3
AB
283 // Set the thread ID (TID) on the pthread structure. The TID is stored
284 // atomically since it is also stored by the parent thread; this way,
285 // whichever thread (parent or child) reaches this point first can proceed
286 // without waiting.
a00bf321 287 atomic_store((atomic_int *) &(self->tid), tid);
288 // Set the stack pointer.
289 __asm__(".globaltype __stack_pointer, i32\n"
290 "local.get %0\n"
291 "global.set __stack_pointer\n"
292 :: "r"(self->stack));
241060c3 293 // Execute the user's start function.
3209fc11 294 __pthread_exit(args->start_func(args->start_arg));
241060c3
AB
295}
296#endif
320054e8
DG
297
298#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
299
300/* pthread_key_create.c overrides this */
301static volatile size_t dummy = 0;
302weak_alias(dummy, __pthread_tsd_size);
303static void *dummy_tsd[1] = { 0 };
304weak_alias(dummy_tsd, __pthread_tsd_main);
305
320054e8
DG
306static FILE *volatile dummy_file = 0;
307weak_alias(dummy_file, __stdin_used);
308weak_alias(dummy_file, __stdout_used);
309weak_alias(dummy_file, __stderr_used);
310
311static void init_file_lock(FILE *f)
312{
313 if (f && f->lock<0) f->lock = 0;
314}
315
316int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg)
317{
318 int ret, c11 = (attrp == __ATTRP_C11_THREAD);
319 size_t size, guard;
320 struct pthread *self, *new;
321 unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit;
241060c3 322#ifdef __wasilibc_unmodified_upstream
320054e8
DG
323 unsigned flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
324 | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS
325 | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED;
241060c3 326#endif
320054e8 327 pthread_attr_t attr = { 0 };
f41256b6 328 sigset_t set;
a00bf321 329#ifndef __wasilibc_unmodified_upstream
330 size_t tls_size = __builtin_wasm_tls_size();
331 size_t tls_align = __builtin_wasm_tls_align();
332 void* tls_base = __builtin_wasm_tls_base();
333 void* new_tls_base;
334 size_t tls_offset;
335 tls_size += tls_align;
336#endif
320054e8 337
a00bf321 338#ifdef __wasilibc_unmodified_upstream
320054e8 339 if (!libc.can_do_threads) return ENOSYS;
a00bf321 340#endif
320054e8
DG
341 self = __pthread_self();
342 if (!libc.threaded) {
343 for (FILE *f=*__ofl_lock(); f; f=f->next)
344 init_file_lock(f);
345 __ofl_unlock();
346 init_file_lock(__stdin_used);
347 init_file_lock(__stdout_used);
348 init_file_lock(__stderr_used);
241060c3 349#ifdef __wasilibc_unmodified_upstream
320054e8 350 __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8);
241060c3 351#endif
320054e8 352 self->tsd = (void **)__pthread_tsd_main;
241060c3 353#ifdef __wasilibc_unmodified_upstream
f41256b6 354 __membarrier_init();
241060c3 355#endif
320054e8
DG
356 libc.threaded = 1;
357 }
358 if (attrp && !c11) attr = *attrp;
359
360 __acquire_ptc();
361 if (!attrp || c11) {
362 attr._a_stacksize = __default_stacksize;
363 attr._a_guardsize = __default_guardsize;
364 }
365
320054e8 366 if (attr._a_stackaddr) {
a00bf321 367#ifdef __wasilibc_unmodified_upstream
320054e8 368 size_t need = libc.tls_size + __pthread_tsd_size;
a00bf321 369#else
370 size_t need = tls_size + __pthread_tsd_size;
371#endif
320054e8
DG
372 size = attr._a_stacksize;
373 stack = (void *)(attr._a_stackaddr & -16);
374 stack_limit = (void *)(attr._a_stackaddr - size);
375 /* Use application-provided stack for TLS only when
376 * it does not take more than ~12% or 2k of the
377 * application's stack space. */
378 if (need < size/8 && need < 2048) {
379 tsd = stack - __pthread_tsd_size;
a00bf321 380#ifdef __wasilibc_unmodified_upstream
320054e8 381 stack = tsd - libc.tls_size;
a00bf321 382#else
383 stack = tsd - tls_size;
384#endif
320054e8
DG
385 memset(stack, 0, need);
386 } else {
387 size = ROUND(need);
388 }
389 guard = 0;
390 } else {
391 guard = ROUND(attr._a_guardsize);
392 size = guard + ROUND(attr._a_stacksize
a00bf321 393#ifdef __wasilibc_unmodified_upstream
320054e8 394 + libc.tls_size + __pthread_tsd_size);
a00bf321 395#else
396 + tls_size + __pthread_tsd_size);
397#endif
320054e8
DG
398 }
399
400 if (!tsd) {
241060c3 401#ifdef __wasilibc_unmodified_upstream
320054e8
DG
402 if (guard) {
403 map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
404 if (map == MAP_FAILED) goto fail;
405 if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)
406 && errno != ENOSYS) {
407 __munmap(map, size);
408 goto fail;
409 }
410 } else {
411 map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
412 if (map == MAP_FAILED) goto fail;
413 }
241060c3
AB
414#else
415 map = malloc(size);
416 if (!map) goto fail;
417#endif
320054e8
DG
418 tsd = map + size - __pthread_tsd_size;
419 if (!stack) {
a00bf321 420#ifdef __wasilibc_unmodified_upstream
320054e8 421 stack = tsd - libc.tls_size;
a00bf321 422#else
423 stack = tsd - tls_size;
424#endif
320054e8
DG
425 stack_limit = map + guard;
426 }
427 }
428
a00bf321 429#ifdef __wasilibc_unmodified_upstream
320054e8 430 new = __copy_tls(tsd - libc.tls_size);
a00bf321 431#else
432 new_tls_base = __copy_tls(tsd - tls_size);
433 tls_offset = new_tls_base - tls_base;
434 new = (void*)((uintptr_t)self + tls_offset);
435#endif
320054e8
DG
436 new->map_base = map;
437 new->map_size = size;
438 new->stack = stack;
439 new->stack_size = stack - stack_limit;
440 new->guard_size = guard;
320054e8
DG
441 new->self = new;
442 new->tsd = (void *)tsd;
443 new->locale = &libc.global_locale;
444 if (attr._a_detach) {
445 new->detach_state = DT_DETACHED;
320054e8
DG
446 } else {
447 new->detach_state = DT_JOINABLE;
448 }
320054e8 449 new->robust_list.head = &new->robust_list.head;
322bd4ff 450 new->canary = self->canary;
d4db3fa2 451 new->sysinfo = self->sysinfo;
320054e8 452
f41256b6
DG
453 /* Setup argument structure for the new thread on its stack.
454 * It's safe to access from the caller only until the thread
455 * list is unlocked. */
a00bf321 456#ifdef __wasilibc_unmodified_upstream
f41256b6
DG
457 stack -= (uintptr_t)stack % sizeof(uintptr_t);
458 stack -= sizeof(struct start_args);
459 struct start_args *args = (void *)stack;
460 args->start_func = entry;
461 args->start_arg = arg;
79a9b408 462 args->control = attr._a_sched ? 1 : 0;
320054e8 463
f41256b6
DG
464 /* Application signals (but not the synccall signal) must be
465 * blocked before the thread list lock can be taken, to ensure
466 * that the lock is AS-safe. */
467 __block_app_sigs(&set);
468
469 /* Ensure SIGCANCEL is unblocked in new thread. This requires
470 * working with a copy of the set so we can restore the
471 * original mask in the calling thread. */
472 memcpy(&args->sig_mask, &set, sizeof args->sig_mask);
473 args->sig_mask[(SIGCANCEL-1)/8/sizeof(long)] &=
474 ~(1UL<<((SIGCANCEL-1)%(8*sizeof(long))));
241060c3 475#else
a00bf321 476 /* Align the stack to struct start_args */
477 stack -= sizeof(struct start_args);
478 stack -= (uintptr_t)stack % alignof(struct start_args);
479 struct start_args *args = (void *)stack;
480
481 /* Align the stack to 16 and store it */
482 new->stack = (void *)((uintptr_t) stack & -16);
483 /* Correct the stack size */
484 new->stack_size = stack - stack_limit;
485
486 args->start_func = entry;
487 args->start_arg = arg;
488 args->tls_base = (void*)new_tls_base;
241060c3 489#endif
f41256b6
DG
490
491 __tl_lock();
58795582 492 if (!libc.threads_minus_1++) libc.need_locks = 1;
241060c3 493#ifdef __wasilibc_unmodified_upstream
f41256b6 494 ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock);
241060c3
AB
495#else
496 /* Instead of `__clone`, WASI uses a host API to instantiate a new version
497 * of the current module and start executing the entry function. The
498 * wasi-threads specification requires the module to export a
499 * `wasi_thread_start` function, which is invoked with `args`. */
500 ret = __wasi_thread_spawn((void *) args);
501#endif
502
503#ifdef __wasilibc_unmodified_upstream
79a9b408
DG
504 /* All clone failures translate to EAGAIN. If explicit scheduling
505 * was requested, attempt it before unlocking the thread list so
506 * that the failed thread is never exposed and so that we can
507 * clean up all transient resource usage before returning. */
508 if (ret < 0) {
509 ret = -EAGAIN;
510 } else if (attr._a_sched) {
511 ret = __syscall(SYS_sched_setscheduler,
512 new->tid, attr._a_policy, &attr._a_prio);
513 if (a_swap(&args->control, ret ? 3 : 0)==2)
514 __wake(&args->control, 1, 1);
515 if (ret)
516 __wait(&args->control, 0, 3, 0);
517 }
241060c3
AB
518#else
519 /* `wasi_thread_spawn` will either return a host-provided thread ID (TID)
520 * (`>= 0`) or an error code (`< 0`). As in the unmodified version, all
521 * spawn failures translate to EAGAIN; unlike the modified version, there is
522 * no need to "start up" the child thread--the host does this. If the spawn
523 * did succeed, then we store the TID atomically, since this parent thread
524 * is racing with the child thread to set this field; this way, whichever
525 * thread reaches this point first can continue without waiting. */
526 if (ret < 0) {
527 ret = -EAGAIN;
528 } else {
a00bf321 529 atomic_store((atomic_int *) &(new->tid), ret);
241060c3
AB
530 }
531#endif
79a9b408 532
f41256b6
DG
533 if (ret >= 0) {
534 new->next = self->next;
535 new->prev = self;
536 new->next->prev = new;
537 new->prev->next = new;
79a9b408 538 } else {
58795582 539 if (!--libc.threads_minus_1) libc.need_locks = 0;
320054e8 540 }
f41256b6 541 __tl_unlock();
241060c3 542#ifdef __wasilibc_unmodified_upstream
f41256b6 543 __restore_sigs(&set);
241060c3 544#endif
f41256b6 545 __release_ptc();
320054e8
DG
546
547 if (ret < 0) {
241060c3 548#ifdef __wasilibc_unmodified_upstream
320054e8 549 if (map) __munmap(map, size);
241060c3
AB
550#else
551 free(map);
552#endif
79a9b408 553 return -ret;
320054e8
DG
554 }
555
556 *res = new;
557 return 0;
558fail:
559 __release_ptc();
560 return EAGAIN;
561}
562
563weak_alias(__pthread_exit, pthread_exit);
564weak_alias(__pthread_create, pthread_create);