mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
process-util: add clone_with_nested_stack() helper
This wraps glibc's clone() but deals with the 'stack' parameter in a sensible way. Only supports invocations without CLONE_VM, i.e. when child is a CoW copy of parent.
This commit is contained in:
parent
09f9530baf
commit
29c3520f28
@ -1149,6 +1149,41 @@ static void restore_sigsetp(sigset_t **ssp) {
|
||||
(void) sigprocmask(SIG_SETMASK, *ssp, NULL);
|
||||
}
|
||||
|
||||
pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata) {
|
||||
size_t ps;
|
||||
pid_t pid;
|
||||
void *mystack;
|
||||
|
||||
/* A wrapper around glibc's clone() call that automatically sets up a "nested" stack. Only supports
|
||||
* invocations without CLONE_VM, so that we can continue to use the parent's stack mapping.
|
||||
*
|
||||
* Note: glibc's clone() wrapper does not synchronize malloc() locks. This means that if the parent
|
||||
* is threaded these locks will be in an undefined state in the child, and hence memory allocations
|
||||
* are likely going to run into deadlocks. Hence: if you use this function make sure your parent is
|
||||
* strictly single-threaded or your child never calls malloc(). */
|
||||
|
||||
assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|
|
||||
CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0);
|
||||
|
||||
/* We allocate some space on the stack to use as the stack for the child (hence "nested"). Note that
|
||||
* the net effect is that the child will have the start of its stack inside the stack of the parent,
|
||||
* but since they are a CoW copy of each other that's fine. We allocate one page-aligned page. But
|
||||
* since we don't want to deal with differences between systems where the stack grows backwards or
|
||||
* forwards we'll allocate one more and place the stack address in the middle. Except that we also
|
||||
* want it page aligned, hence we'll allocate one page more. Makes 3. */
|
||||
|
||||
ps = page_size();
|
||||
mystack = alloca(ps*3);
|
||||
mystack = (uint8_t*) mystack + ps; /* move pointer one page ahead since stacks usually grow backwards */
|
||||
mystack = (void*) ALIGN_TO((uintptr_t) mystack, ps); /* align to page size (moving things further ahead) */
|
||||
|
||||
pid = clone(fn, mystack, flags, userdata);
|
||||
if (pid < 0)
|
||||
return -errno;
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
int safe_fork_full(
|
||||
const char *name,
|
||||
const int stdio_fds[3],
|
||||
|
@ -139,6 +139,8 @@ void reset_cached_pid(void);
|
||||
|
||||
int must_be_root(void);
|
||||
|
||||
pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata);
|
||||
|
||||
typedef enum ForkFlags {
|
||||
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
|
||||
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
|
||||
|
Loading…
Reference in New Issue
Block a user