]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
8869a0b4 MK |
2 | #pragma once |
3 | ||
4 | /*** | |
96b2fb93 | 5 | Copyright © 2016 Michael Karcher |
8869a0b4 MK |
6 | ***/ |
7 | ||
96f64eb5 | 8 | #include <errno.h> |
8869a0b4 MK |
9 | #include <sched.h> |
10 | #include <sys/syscall.h> | |
11 | ||
12 | #include "log.h" | |
13 | #include "macro.h" | |
14 | ||
15 | /** | |
16 | * raw_clone() - uses clone to create a new process with clone flags | |
17 | * @flags: Flags to pass to the clone system call | |
18 | * | |
799a960d | 19 | * Uses the clone system call to create a new process with the cloning flags and termination signal passed in the flags |
5238e957 | 20 | * parameter. Opposed to glibc's clone function, using this function does not set up a separate stack for the child, but |
799a960d | 21 | * relies on copy-on-write semantics on the one stack at a common virtual address, just as fork does. |
8869a0b4 | 22 | * |
799a960d LP |
23 | * To obtain copy-on-write semantics, flags must not contain CLONE_VM, and thus CLONE_THREAD and CLONE_SIGHAND (which |
24 | * require CLONE_VM) are not usable. | |
25 | * | |
26 | * Additionally, as this function does not pass the ptid, newtls and ctid parameters to the kernel, flags must not | |
27 | * contain CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID or CLONE_SETTLS. | |
8869a0b4 MK |
28 | * |
29 | * Returns: 0 in the child process and the child process id in the parent. | |
30 | */ | |
799a960d LP |
31 | static inline pid_t raw_clone(unsigned long flags) { |
32 | pid_t ret; | |
33 | ||
8869a0b4 MK |
34 | assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID| |
35 | CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0); | |
ae9d60ce LP |
36 | #if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) |
37 | /* On s390/s390x and cris the order of the first and second arguments | |
8869a0b4 | 38 | * of the raw clone() system call is reversed. */ |
799a960d | 39 | ret = (pid_t) syscall(__NR_clone, NULL, flags); |
e4aa2c34 | 40 | #elif defined(__sparc__) |
8869a0b4 MK |
41 | { |
42 | /** | |
e4aa2c34 | 43 | * sparc always returns the other process id in %o0, and |
8869a0b4 MK |
44 | * a boolean flag whether this is the child or the parent in |
45 | * %o1. Inline assembly is needed to get the flag returned | |
46 | * in %o1. | |
47 | */ | |
96f64eb5 | 48 | int in_child, child_pid, error; |
799a960d | 49 | |
96f64eb5 MG |
50 | asm volatile("mov %3, %%g1\n\t" |
51 | "mov %4, %%o0\n\t" | |
8869a0b4 | 52 | "mov 0 , %%o1\n\t" |
e4aa2c34 | 53 | #if defined(__arch64__) |
8869a0b4 | 54 | "t 0x6d\n\t" |
e4aa2c34 MG |
55 | #else |
56 | "t 0x10\n\t" | |
57 | #endif | |
96f64eb5 | 58 | "addx %%g0, 0, %2\n\t" |
8869a0b4 MK |
59 | "mov %%o1, %0\n\t" |
60 | "mov %%o0, %1" : | |
96f64eb5 | 61 | "=r"(in_child), "=r"(child_pid), "=r"(error) : |
8869a0b4 | 62 | "i"(__NR_clone), "r"(flags) : |
358248ca | 63 | "%o1", "%o0", "%g1", "cc" ); |
799a960d | 64 | |
96f64eb5 MG |
65 | if (error) { |
66 | errno = child_pid; | |
67 | ret = -1; | |
68 | } else | |
69 | ret = in_child ? 0 : child_pid; | |
8869a0b4 MK |
70 | } |
71 | #else | |
799a960d | 72 | ret = (pid_t) syscall(__NR_clone, flags, NULL); |
8869a0b4 | 73 | #endif |
799a960d LP |
74 | |
75 | if (ret == 0) | |
76 | reset_cached_pid(); | |
77 | ||
78 | return ret; | |
8869a0b4 | 79 | } |