diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2017-04-17 14:48:50 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2017-05-14 10:29:09 +0200 |
commit | 69ea4c1f65bff99575cd7f0210312dc355929240 (patch) | |
tree | 43fe11a4e27c85b742e2434f6e8ec0b25576d8af /libc/sysdeps/linux/or1k/clone.c | |
parent | be6a02b9a0317a7441de9aa2e3e07fe838787d57 (diff) |
or1k: add clone() from old GNU libc implementation
Diffstat (limited to 'libc/sysdeps/linux/or1k/clone.c')
-rw-r--r-- | libc/sysdeps/linux/or1k/clone.c | 127 |
1 files changed, 49 insertions, 78 deletions
diff --git a/libc/sysdeps/linux/or1k/clone.c b/libc/sysdeps/linux/or1k/clone.c index ebb048ad4..2b61b638f 100644 --- a/libc/sysdeps/linux/or1k/clone.c +++ b/libc/sysdeps/linux/or1k/clone.c @@ -1,88 +1,59 @@ -/* - * clone syscall for OpenRISC - * - * Copyright (c) 2010 Jonas Bonn <jonas@southpole.se> - * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au> - * Copyright (C) 2002,03 NEC Electronics Corporation - * Copyright (C) 2002,03 Miles Bader <miles@gnu.org> - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License. See the file COPYING.LIB in the main - * directory of this archive for more details. - * - * OpenRISC port by Jonas Bonn <jonas@southpole.se> - */ +/* Copyright (C) 1998, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. -#include <errno.h> -#include <sys/syscall.h> -#include <sched.h> -#include <unistd.h> - -/* The userland implementation is: - int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg, ...) - the kernel entry is: - int clone (long flags, void *child_stack) -*/ - -int -clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg, ...) -{ - int err; - - /* OK, here's the skinny on this one... - * OR1K GCC does weird things with varargs functions... the last - * parameter is NEVER passed on the stack -- i.e. arg, in this case. - * So we need to push at least 'arg' onto the child stack so that - * the new thread can find it. Just to be totally safe, we'll - * push both 'fn' and 'arg'; that way we don't need to care what - * GCC does with parameters, whether they are passed in registers - * or on stack. - */ + The GNU C Library 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. - /* Put 'fn' and 'arg' on child stack */ - __asm__ __volatile__ ( - "l.sw -4(%0),%1;" - "l.sw -8(%0),%2;" - : - : "r" (child_stack), "r" (fn), "r" (arg) - ); + The GNU C Library 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. - /* Sanity check the arguments */ - err = -EINVAL; - if (!fn) - goto syscall_error; - if (!child_stack) - goto syscall_error; + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ - err = INLINE_SYSCALL(clone, 2, flags, child_stack); - - /* NB: from here you are in child thread or parent thread. - * - * Do not use any functions here that may write data _up_ - * onto the stack because they will overwrite the child's - * thread descriptor... i.e. don't use printf - */ - - if (err < 0) - goto syscall_error; - else if (err != 0) { - return err; - } +#include <stdarg.h> +#include <sysdep.h> +#include <unistd.h> - /* NB: from here you exclusively in child thread */ +extern int __or1k_clone (int (*fn)(void *), void *child_stack, + int flags, void *arg, pid_t *ptid, + void *tls, pid_t *ctid); - /* Grab 'fn' and 'arg' from child stack */ - __asm__ __volatile__ ( - "l.lwz %0,-4(%2);" - "l.lwz %1,-8(%2);" - : "=&r" (fn), "=r" (arg) - : "r" (child_stack) - : "0", "1" - ); - _exit(fn(arg)); +/* or1k ABI uses stack for varargs, syscall uses registers. + * This function moves from varargs to regs. */ +int +__clone (int (*fn)(void *), void *child_stack, + int flags, void *arg, ... + /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ ) +{ + void *ptid; + void *tls; + void *ctid; + va_list ap; + int err; + + va_start (ap, arg); + ptid = va_arg (ap, void *); + tls = va_arg (ap, void *); + ctid = va_arg (ap, void *); + va_end (ap); + + /* Sanity check the arguments */ + err = -EINVAL; + if (!fn) + goto syscall_error; + if (!child_stack) + goto syscall_error; + + return __or1k_clone (fn, child_stack, flags, arg, ptid, tls, ctid); syscall_error: - __set_errno (-err); - return -1; + __set_errno (-err); + return -1; } +weak_alias (__clone, clone) |