chiark / gitweb /
util-lib: Add sparc64 support for process creation (#3348)
authorMichael Karcher <github@mkarcher.dialup.fu-berlin.de>
Mon, 30 May 2016 00:03:51 +0000 (02:03 +0200)
committerSven Eden <yamakuzure@gmx.net>
Fri, 16 Jun 2017 08:12:59 +0000 (10:12 +0200)
The current raw_clone function takes two arguments, the cloning flags and
a pointer to the stack for the cloned child. The raw cloning without
passing a "thread main" function does not make sense if a new stack is
specified, as it returns in both the parent and the child, which will fail
in the child as the stack is virgin. All uses of raw_clone indeed pass NULL
for the stack pointer which indicates that both processes should share the
stack address (so you better don't pass CLONE_VM).

This commit refactors the code to not require the caller to pass the stack
address, as NULL is the only sensible option. It also adds the magic code
needed to make raw_clone work on sparc64, which does not return 0 in %o0
for the child, but indicates the child process by setting %o1 to non-zero.
This refactoring is not plain aesthetic, because non-NULL stack addresses
need to get mangled before being passed to the clone syscall (you have to
apply STACK_BIAS), whereas NULL must not be mangled. Implementing the
conditional mangling of the stack address would needlessly complicate the
code.

raw_clone is moved to a separete header, because the burden of including
the assert machinery and sched.h shouldn't be applied to every user of
missing_syscalls.h

src/basic/raw-clone.h [new file with mode: 0644]

diff --git a/src/basic/raw-clone.h b/src/basic/raw-clone.h
new file mode 100644 (file)
index 0000000..1bef6f2
--- /dev/null
@@ -0,0 +1,81 @@
+#pragma once
+
+/***
+  This file is part of elogind.
+
+  Copyright 2010 Lennart Poettering
+  Copyright 2016 Michael Karcher
+  elogind is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  elogind is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with elogind; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sched.h>
+#include <sys/syscall.h>
+
+#include "log.h"
+#include "macro.h"
+
+/**
+ * raw_clone() - uses clone to create a new process with clone flags
+ * @flags: Flags to pass to the clone system call
+ *
+ * Uses the clone system call to create a new process with the cloning
+ * flags and termination signal passed in the flags parameter. Opposed
+ * to glibc's clone funtion, using this function does not set up a
+ * separate stack for the child, but relies on copy-on-write semantics
+ * on the one stack at a common virtual address, just as fork does.
+ *
+ * To obtain copy-on-write semantics, flags must not contain CLONE_VM,
+ * and thus CLONE_THREAD and CLONE_SIGHAND (which require CLONE_VM) are
+ * not usabale.
+ * Additionally, as this function does not pass the ptid, newtls and ctid
+ * parameters to the kernel, flags must not contain CLONE_PARENT_SETTID,
+ * CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID or CLONE_SETTLS.
+ *
+ * Returns: 0 in the child process and the child process id in the parent.
+ */
+static inline int raw_clone(unsigned long flags) {
+        assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|
+                         CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0);
+#if defined(__s390__) || defined(__CRIS__)
+        /* On s390 and cris the order of the first and second arguments
+         * of the raw clone() system call is reversed. */
+        return (int) syscall(__NR_clone, NULL, flags);
+#elif defined(__sparc__) && defined(__arch64__)
+        {
+                /**
+                 * sparc64 always returns the other process id in %o0, and
+                 * a boolean flag whether this is the child or the parent in
+                 * %o1. Inline assembly is needed to get the flag returned
+                 * in %o1.
+                 */
+                int in_child;
+                int child_pid;
+                asm volatile("mov %2, %%g1\n\t"
+                             "mov %3, %%o0\n\t"
+                             "mov 0 , %%o1\n\t"
+                             "t 0x6d\n\t"
+                             "mov %%o1, %0\n\t"
+                             "mov %%o0, %1" :
+                             "=r"(in_child), "=r"(child_pid) :
+                             "i"(__NR_clone), "r"(flags) :
+                             "%o1", "%o0", "%g1" );
+                if (in_child)
+                        return 0;
+                else
+                        return child_pid;
+        }
+#else
+        return (int) syscall(__NR_clone, flags, NULL);
+#endif
+}