1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| | #define _GNU_SOURCE
#include <stdarg.h>
#include <unistd.h>
#include <sched.h>
#include "pthread_impl.h"
#include "syscall.h"
#include "dynlink.h"
extern int _Forklike(int (*)(void *), void *);
struct clone_args {
int flags;
pid_t *ptid, *ctid;
};
static int do_clone(void *p)
{
struct clone_args *args = p;
int mask = CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID;
int r = __syscall(SYS_clone, args->flags & ~mask, 0);
if (r>0 && (args->flags & CLONE_PARENT_SETTID)) *args->ptid = r;
if (!r && (args->flags & CLONE_CHILD_SETTID)) *args->ctid = __syscall(SYS_gettid);
if (!r && (args->flags & CLONE_CHILD_CLEARTID)) __syscall(SYS_set_tid_address, args->ctid);
return r;
}
int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
{
va_list ap;
pid_t *ptid, *ctid;
void *tls;
va_start(ap, arg);
ptid = va_arg(ap, pid_t *);
tls = va_arg(ap, void *);
ctid = va_arg(ap, pid_t *);
va_end(ap);
if (!(flags & CLONE_VM)) {
struct clone_args args = { .flags = flags, .ptid = ptid, .ctid = ctid };
if (flags & CLONE_THREAD) return __syscall_ret(-EINVAL);
int r = _Forklike(do_clone, &args);
if (r) return r;
CRTJMP(func, stack);
}
return __syscall_ret(__clone(func, stack, flags, arg, ptid, tls, ctid));
}
|