/* * Copyright (c) International Business Machines Corp., 2009 * Some wrappers for clone functionality. Thrown together by Serge Hallyn * based on existing clone usage in ltp. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include "config.h" #include "tst_clone.h" #undef clone /* we want to use clone() */ /* * The ia64 port has never included a prototype for __clone2(). It was updated * to take eight parameters in glibc commit: * * commit 625f22fc7f8e0d61e3e6cff2c65468b91dbad426 * Author: Ulrich Drepper * Date: Mon Mar 3 19:53:27 2003 +0000 * * The first release that contained this commit was glibc-2.3.3 which is old * enough to assume that __clone2() takes eight parameters. */ #if defined(__ia64__) extern int __clone2(int (*fn) (void *arg), void *child_stack_base, size_t child_stack_size, int flags, void *arg, pid_t *parent_tid, void *tls, pid_t *child_tid); #endif #ifndef CLONE_SUPPORTS_7_ARGS # define clone(fn, stack, flags, arg, ptid, tls, ctid) \ clone(fn, stack, flags, arg) #endif /* * ltp_clone: wrapper for clone to hide the architecture dependencies. * 1. hppa takes bottom of stack and no stacksize (stack grows up) * 2. __ia64__ takes bottom of stack and uses clone2 * 3. all others take top of stack (stack grows down) */ static int ltp_clone_(unsigned long flags, int (*fn)(void *arg), void *arg, size_t stack_size, void *stack, pid_t *ptid, void *tls, pid_t *ctid) { int ret; #if defined(__ia64__) ret = __clone2(fn, stack, stack_size, flags, arg, ptid, tls, ctid); #else # if defined(__hppa__) || defined(__metag__) /* * These arches grow their stack up, so don't need to adjust the base. * XXX: This should be made into a runtime test. */ # else /* * For archs where stack grows downwards, stack points to the topmost * address of the memory space set up for the child stack. */ if (stack) stack += stack_size; # endif ret = clone(fn, stack, flags, arg, ptid, tls, ctid); #endif return ret; } int ltp_clone(unsigned long flags, int (*fn)(void *arg), void *arg, size_t stack_size, void *stack) { return ltp_clone_(flags, fn, arg, stack_size, stack, NULL, NULL, NULL); } int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg, size_t stack_size, void *stack, ...) { pid_t *ptid, *ctid; void *tls; va_list arg_clone; va_start(arg_clone, stack); ptid = va_arg(arg_clone, pid_t *); tls = va_arg(arg_clone, void *); ctid = va_arg(arg_clone, pid_t *); va_end(arg_clone); #ifdef CLONE_SUPPORTS_7_ARGS return ltp_clone_(flags, fn, arg, stack_size, stack, ptid, tls, ctid); #else errno = ENOSYS; return -1; #endif } /* * ltp_alloc_stack: allocate stack of size 'size', that is sufficiently * aligned for all arches. User is responsible for freeing allocated * memory. * Returns pointer to new stack. On error, returns NULL with errno set. */ void *ltp_alloc_stack(size_t size) { void *ret = NULL; int err; err = posix_memalign(&ret, 64, size); if (err) errno = err; return ret; } /* * ltp_clone_alloc: also does the memory allocation for clone with a * caller-specified size. */ int ltp_clone_alloc(unsigned long clone_flags, int (*fn) (void *arg), void *arg, size_t stack_size) { void *stack; int ret; int saved_errno; stack = ltp_alloc_stack(stack_size); if (stack == NULL) return -1; ret = ltp_clone(clone_flags, fn, arg, stack_size, stack); if (ret == -1) { saved_errno = errno; free(stack); errno = saved_errno; } return ret; } /* * ltp_clone_quick: calls ltp_clone_alloc with predetermined stack size. * Experience thus far suggests that one page is often insufficient, * while 6*getpagesize() seems adequate. */ int ltp_clone_quick(unsigned long clone_flags, int (*fn) (void *arg), void *arg) { size_t stack_size = getpagesize() * 6; return ltp_clone_alloc(clone_flags, fn, arg, stack_size); }