dummy implementation of set_thread_area
[musl] / src / thread / forkall.c
1 #include "pthread_impl.h"
2 #include <setjmp.h>
3
4 struct thread {
5         struct thread *next;
6         pthread_t td;
7         jmp_buf jb;
8         void *tmp, *stack;
9 };
10
11 struct ctx {
12         struct thread *list;
13         pthread_t caller;
14         pid_t pid;
15         size_t cnt;
16         pthread_barrier_t barrier;
17 };
18
19 static void restart_thread(pthread_t self)
20 {
21         struct thread *t = self->start_arg;
22         self->start_arg = t->tmp;
23         self->pid = getpid();
24         longjmp(t->jb, 1);
25 }
26
27 static void do_forkall(void *p)
28 {
29         struct ctx *c = p, *volatile cv = c;
30         char tmpstack[2048];
31         struct thread *tp, t = {
32                 .td = __pthread_self(),
33                 .next = c->list,
34                 .stack = tmpstack+1024
35         };
36
37         if (t.td != c->caller) {
38                 c->cnt++;
39                 t.tmp = t.td->start_arg;
40                 t.td->start_arg = &t;
41                 if (setjmp(t.jb)) {
42                         c = cv;
43                         if (c->pid) return;
44                         pthread_barrier_wait(&c->barrier);
45                         return;
46                 }
47                 c->list = &t;
48                 __synccall_wait();
49                 return;
50         }
51         c->pid = syscall(SYS_fork);
52         if (c->pid) return;
53
54         pthread_barrier_init(&c->barrier, 0, c->cnt);
55         for (tp=c->list; tp; tp=tp->next)
56                 if (__uniclone(tp->stack, restart_thread, tp->td) < 0)
57                         _exit(127);
58         pthread_barrier_wait(&c->barrier);
59 }
60
61 pid_t forkall()
62 {
63         struct ctx c = { .caller = pthread_self() };
64         __synccall(do_forkall, &c);
65         return c.pid;
66 }