mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 03:03:09 +00:00
66 lines
1.7 KiB
C
Vendored
66 lines
1.7 KiB
C
Vendored
#define _GNU_SOURCE
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <sched.h>
|
|
#include "pthread_impl.h"
|
|
#include "syscall.h"
|
|
#include "lock.h"
|
|
#include "fork_impl.h"
|
|
|
|
struct clone_start_args {
|
|
int (*func)(void *);
|
|
void *arg;
|
|
sigset_t sigmask;
|
|
};
|
|
|
|
static int clone_start(void *arg)
|
|
{
|
|
struct clone_start_args *csa = arg;
|
|
__post_Fork(0);
|
|
__restore_sigs(&csa->sigmask);
|
|
return csa->func(csa->arg);
|
|
}
|
|
|
|
int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
|
|
{
|
|
struct clone_start_args csa;
|
|
va_list ap;
|
|
pid_t *ptid = 0, *ctid = 0;
|
|
void *tls = 0;
|
|
|
|
/* Flags that produce an invalid thread/TLS state are disallowed. */
|
|
int badflags = CLONE_THREAD | CLONE_SETTLS | CLONE_CHILD_CLEARTID;
|
|
|
|
if ((flags & badflags) || !stack)
|
|
return __syscall_ret(-EINVAL);
|
|
|
|
va_start(ap, arg);
|
|
if (flags & (CLONE_PIDFD | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID))
|
|
ptid = va_arg(ap, pid_t *);
|
|
if (flags & CLONE_CHILD_SETTID) {
|
|
tls = va_arg(ap, void *);
|
|
ctid = va_arg(ap, pid_t *);
|
|
}
|
|
va_end(ap);
|
|
|
|
/* If CLONE_VM is used, it's impossible to give the child a consistent
|
|
* thread structure. In this case, the best we can do is assume the
|
|
* caller is content with an extremely restrictive execution context
|
|
* like the one vfork() would provide. */
|
|
if (flags & CLONE_VM) return __syscall_ret(
|
|
__clone(func, stack, flags, arg, ptid, tls, ctid));
|
|
|
|
__block_all_sigs(&csa.sigmask);
|
|
LOCK(__abort_lock);
|
|
|
|
/* Setup the a wrapper start function for the child process to do
|
|
* mimic _Fork in producing a consistent execution state. */
|
|
csa.func = func;
|
|
csa.arg = arg;
|
|
int ret = __clone(clone_start, stack, flags, &csa, ptid, tls, ctid);
|
|
|
|
__post_Fork(ret);
|
|
__restore_sigs(&csa.sigmask);
|
|
return __syscall_ret(ret);
|
|
}
|