1 #define _GNU_SOURCE
2 #include <stdarg.h>
3 #include <unistd.h>
4 #include <sched.h>
5 #include <signal.h>
6 #include "pthread_impl.h"
7 #include "syscall.h"
8 #include "libc.h"
9
10 struct __clone_args {
11 int (*func)(void *);
12 void *arg;
13 };
14
__start_child(void * clone_args)15 static int __start_child(void *clone_args)
16 {
17 int status;
18 sigset_t set;
19 int (*func)(void *) = ((struct __clone_args *)clone_args)->func;
20 void *arg = ((struct __clone_args *)clone_args)->arg;
21
22 __block_all_sigs(&set);
23 pthread_t self = __pthread_self();
24 self->tid = __syscall(SYS_gettid);
25 self->robust_list.off = 0;
26 self->robust_list.pending = 0;
27 self->next = self->prev = self;
28 __thread_list_lock = 0;
29 libc.threads_minus_1 = 0;
30 libc.exit = 0;
31 signal(SIGSYS, arm_do_signal);
32 __restore_sigs(&set);
33
34 status = func(arg);
35 exit(status);
36 }
37
clone(int (* func)(void *),void * stack,int flags,void * arg,...)38 int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
39 {
40 int ret;
41 va_list ap;
42 pid_t *ptid, *ctid;
43 void *tls;
44 void *mmap_stack = NULL;
45 void *clone_stack = stack;
46 int (*clone_func)(void *) = func;
47 struct __clone_args *clone_args = (struct __clone_args *)arg;
48
49 va_start(ap, arg);
50 ptid = va_arg(ap, pid_t *);
51 tls = va_arg(ap, void *);
52 ctid = va_arg(ap, pid_t *);
53 va_end(ap);
54
55 if (!(flags & (CLONE_VM | CLONE_VFORK))) {
56 if (func) {
57 if (!stack) {
58 mmap_stack = __mmap(0, __default_stacksize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
59 if (mmap_stack == MAP_FAILED) {
60 errno = ENOMEM;
61 return -1;
62 }
63 clone_args = (struct __clone_args *)((char *)mmap_stack + __default_stacksize);
64 } else {
65 clone_args = (struct __clone_args *)stack;
66 }
67 clone_args = (struct __clone_args *)((uintptr_t)clone_args - ((uintptr_t)clone_args % sizeof(uintptr_t)));
68 clone_args = (struct __clone_args *)((char *)clone_args - sizeof(struct __clone_args));
69 clone_args->func = clone_func;
70 clone_args->arg = arg;
71 clone_func = __start_child;
72 clone_stack = (void *)clone_args;
73 }
74 }
75 ret = __syscall_ret(__clone(clone_func, clone_stack, flags, (void *)clone_args, ptid, tls, ctid));
76 if (mmap_stack) {
77 __munmap(mmap_stack, __default_stacksize);
78 }
79 return ret;
80 }
81