1 /* 2 * Copyright (c) International Business Machines Corp., 2009 3 * Some wrappers for clone functionality. Thrown together by Serge Hallyn 4 * <serue (at) us.ibm.com> based on existing clone usage in ltp. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 * the GNU General Public License for more details. 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #ifndef _GNU_SOURCE 21 # define _GNU_SOURCE 22 #endif 23 24 #include <stdio.h> 25 #include <errno.h> 26 #include <unistd.h> 27 #include <string.h> 28 #include <stdlib.h> 29 #include <sched.h> 30 #include <stdarg.h> 31 #include "test.h" 32 #include "config.h" 33 34 #undef clone /* we want to use clone() */ 35 36 /* 37 * The ia64 port has never included a prototype for __clone2(). It was updated 38 * to take eight parameters in glibc commit: 39 * 40 * commit 625f22fc7f8e0d61e3e6cff2c65468b91dbad426 41 * Author: Ulrich Drepper <drepper (at) redhat.com> 42 * Date: Mon Mar 3 19:53:27 2003 +0000 43 * 44 * The first release that contained this commit was glibc-2.3.3 which is old 45 * enough to assume that __clone2() takes eight parameters. 46 */ 47 #if defined(__ia64__) 48 extern int __clone2(int (*fn) (void *arg), void *child_stack_base, 49 size_t child_stack_size, int flags, void *arg, 50 pid_t *parent_tid, void *tls, pid_t *child_tid); 51 #endif 52 53 #ifndef CLONE_SUPPORTS_7_ARGS 54 # define clone(fn, stack, flags, arg, ptid, tls, ctid) \ 55 clone(fn, stack, flags, arg) 56 #endif 57 58 /* 59 * ltp_clone: wrapper for clone to hide the architecture dependencies. 60 * 1. hppa takes bottom of stack and no stacksize (stack grows up) 61 * 2. __ia64__ takes bottom of stack and uses clone2 62 * 3. all others take top of stack (stack grows down) 63 */ 64 static int 65 ltp_clone_(unsigned long flags, int (*fn)(void *arg), void *arg, 66 size_t stack_size, void *stack, pid_t *ptid, void *tls, pid_t *ctid) 67 { 68 int ret; 69 70 #if defined(__ia64__) 71 ret = __clone2(fn, stack, stack_size, flags, arg, ptid, tls, ctid); 72 #else 73 # if defined(__hppa__) || defined(__metag__) 74 /* 75 * These arches grow their stack up, so don't need to adjust the base. 76 * XXX: This should be made into a runtime test. 77 */ 78 # else 79 /* 80 * For archs where stack grows downwards, stack points to the topmost 81 * address of the memory space set up for the child stack. 82 */ 83 if (stack) 84 stack += stack_size; 85 # endif 86 87 ret = clone(fn, stack, flags, arg, ptid, tls, ctid); 88 #endif 89 90 return ret; 91 } 92 93 int ltp_clone(unsigned long flags, int (*fn)(void *arg), void *arg, 94 size_t stack_size, void *stack) 95 { 96 return ltp_clone_(flags, fn, arg, stack_size, stack, NULL, NULL, NULL); 97 } 98 99 int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg, 100 size_t stack_size, void *stack, ...) 101 { 102 pid_t *ptid, *ctid; 103 void *tls; 104 va_list arg_clone; 105 106 va_start(arg_clone, stack); 107 ptid = va_arg(arg_clone, pid_t *); 108 tls = va_arg(arg_clone, void *); 109 ctid = va_arg(arg_clone, pid_t *); 110 va_end(arg_clone); 111 112 #ifdef CLONE_SUPPORTS_7_ARGS 113 return ltp_clone_(flags, fn, arg, stack_size, stack, ptid, tls, ctid); 114 #else 115 errno = ENOSYS; 116 return -1; 117 #endif 118 } 119 120 /* 121 * ltp_clone_malloc: also does the memory allocation for clone with a 122 * caller-specified size. 123 */ 124 int 125 ltp_clone_malloc(unsigned long clone_flags, int (*fn) (void *arg), void *arg, 126 size_t stack_size) 127 { 128 void *stack; 129 int ret; 130 int saved_errno; 131 132 stack = malloc(stack_size); 133 if (stack == NULL) 134 return -1; 135 136 ret = ltp_clone(clone_flags, fn, arg, stack_size, stack); 137 138 if (ret == -1) { 139 saved_errno = errno; 140 free(stack); 141 errno = saved_errno; 142 } 143 144 return ret; 145 } 146 147 /* 148 * ltp_clone_quick: calls ltp_clone_malloc with predetermined stack size. 149 * Experience thus far suggests that one page is often insufficient, 150 * while 6*getpagesize() seems adequate. 151 */ 152 int ltp_clone_quick(unsigned long clone_flags, int (*fn) (void *arg), void *arg) 153 { 154 size_t stack_size = getpagesize() * 6; 155 156 return ltp_clone_malloc(clone_flags, fn, arg, stack_size); 157 } 158