• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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