1 /*
2 * Copyright (c) International Business Machines Corp., 2009
3 * Some wrappers for clone functionality. Thrown together by Serge Hallyn
4 * <serue@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 "config.h"
32 #include "tst_clone.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@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
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)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
ltp_clone(unsigned long flags,int (* fn)(void * arg),void * arg,size_t stack_size,void * stack)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
ltp_clone7(unsigned long flags,int (* fn)(void * arg),void * arg,size_t stack_size,void * stack,...)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_alloc_stack: allocate stack of size 'size', that is sufficiently
122 * aligned for all arches. User is responsible for freeing allocated
123 * memory.
124 * Returns pointer to new stack. On error, returns NULL with errno set.
125 */
ltp_alloc_stack(size_t size)126 void *ltp_alloc_stack(size_t size)
127 {
128 void *ret = NULL;
129 int err;
130
131 err = posix_memalign(&ret, 64, size);
132 if (err)
133 errno = err;
134
135 return ret;
136 }
137
138 /*
139 * ltp_clone_alloc: also does the memory allocation for clone with a
140 * caller-specified size.
141 */
142 int
ltp_clone_alloc(unsigned long clone_flags,int (* fn)(void * arg),void * arg,size_t stack_size)143 ltp_clone_alloc(unsigned long clone_flags, int (*fn) (void *arg), void *arg,
144 size_t stack_size)
145 {
146 void *stack;
147 int ret;
148 int saved_errno;
149
150 stack = ltp_alloc_stack(stack_size);
151 if (stack == NULL)
152 return -1;
153
154 ret = ltp_clone(clone_flags, fn, arg, stack_size, stack);
155
156 if (ret == -1) {
157 saved_errno = errno;
158 free(stack);
159 errno = saved_errno;
160 }
161
162 return ret;
163 }
164
165 /*
166 * ltp_clone_quick: calls ltp_clone_alloc with predetermined stack size.
167 * Experience thus far suggests that one page is often insufficient,
168 * while 6*getpagesize() seems adequate.
169 */
ltp_clone_quick(unsigned long clone_flags,int (* fn)(void * arg),void * arg)170 int ltp_clone_quick(unsigned long clone_flags, int (*fn) (void *arg), void *arg)
171 {
172 size_t stack_size = getpagesize() * 6;
173
174 return ltp_clone_alloc(clone_flags, fn, arg, stack_size);
175 }
176