| 1 | #define _GNU_SOURCE |
| 2 | #include <stdarg.h> |
| 3 | #include <unistd.h> |
| 4 | #include <sched.h> |
| 5 | #include "pthread_impl.h" |
| 6 | #include "syscall.h" |
| 7 | #include "lock.h" |
| 8 | #include "fork_impl.h" |
| 9 | |
| 10 | struct clone_start_args { |
| 11 | 	int (*func)(void *); |
| 12 | 	void *arg; |
| 13 | 	sigset_t sigmask; |
| 14 | }; |
| 15 | |
| 16 | static int clone_start(void *arg) |
| 17 | { |
| 18 | 	struct clone_start_args *csa = arg; |
| 19 | 	__post_Fork(0); |
| 20 | 	__restore_sigs(&csa->sigmask); |
| 21 | 	return csa->func(csa->arg); |
| 22 | } |
| 23 | |
| 24 | int clone(int (*func)(void *), void *stack, int flags, void *arg, ...) |
| 25 | { |
| 26 | 	struct clone_start_args csa; |
| 27 | 	va_list ap; |
| 28 | 	pid_t *ptid = 0, *ctid = 0; |
| 29 | 	void *tls = 0; |
| 30 | |
| 31 | 	/* Flags that produce an invalid thread/TLS state are disallowed. */ |
| 32 | 	int badflags = CLONE_THREAD | CLONE_SETTLS | CLONE_CHILD_CLEARTID; |
| 33 | |
| 34 | 	if ((flags & badflags) || !stack) |
| 35 | 		return __syscall_ret(-EINVAL); |
| 36 | |
| 37 | 	va_start(ap, arg); |
| 38 | 	if (flags & (CLONE_PIDFD | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID)) |
| 39 | 	 	ptid = va_arg(ap, pid_t *); |
| 40 | 	if (flags & CLONE_CHILD_SETTID) { |
| 41 | 		tls = va_arg(ap, void *); |
| 42 | 		ctid = va_arg(ap, pid_t *); |
| 43 | 	} |
| 44 | 	va_end(ap); |
| 45 | |
| 46 | 	/* If CLONE_VM is used, it's impossible to give the child a consistent |
| 47 | 	 * thread structure. In this case, the best we can do is assume the |
| 48 | 	 * caller is content with an extremely restrictive execution context |
| 49 | 	 * like the one vfork() would provide. */ |
| 50 | 	if (flags & CLONE_VM) return __syscall_ret( |
| 51 | 		__clone(func, stack, flags, arg, ptid, tls, ctid)); |
| 52 | |
| 53 | 	__block_all_sigs(&csa.sigmask); |
| 54 | 	LOCK(__abort_lock); |
| 55 | |
| 56 | 	/* Setup the a wrapper start function for the child process to do |
| 57 | 	 * mimic _Fork in producing a consistent execution state. */ |
| 58 | 	csa.func = func; |
| 59 | 	csa.arg = arg; |
| 60 | 	int ret = __clone(clone_start, stack, flags, &csa, ptid, tls, ctid); |
| 61 | |
| 62 | 	__post_Fork(ret); |
| 63 | 	__restore_sigs(&csa.sigmask); |
| 64 | 	return __syscall_ret(ret); |
| 65 | } |