1 /*
2 * Copyright (c) International Business Machines Corp., 2009
3 * Some wrappers for clone functionality. Thrown together by Serge Hallyn
4 * <[email protected]> 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 <[email protected]>
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 /*
54 * ltp_clone: wrapper for clone to hide the architecture dependencies.
55 * 1. hppa takes bottom of stack and no stacksize (stack grows up)
56 * 2. __ia64__ takes bottom of stack and uses clone2
57 * 3. all others take top of stack (stack grows down)
58 */
59 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)60 ltp_clone_(unsigned long flags, int (*fn)(void *arg), void *arg,
61 size_t stack_size, void *stack, pid_t *ptid, void *tls, pid_t *ctid)
62 {
63 int ret;
64
65 #if defined(__ia64__)
66 ret = __clone2(fn, stack, stack_size, flags, arg, ptid, tls, ctid);
67 #else
68 # if defined(__hppa__) || defined(__metag__)
69 /*
70 * These arches grow their stack up, so don't need to adjust the base.
71 * XXX: This should be made into a runtime test.
72 */
73 # else
74 /*
75 * For archs where stack grows downwards, stack points to the topmost
76 * address of the memory space set up for the child stack.
77 */
78 if (stack)
79 stack += stack_size;
80 # endif
81
82 ret = clone(fn, stack, flags, arg, ptid, tls, ctid);
83 #endif
84
85 return ret;
86 }
87
ltp_clone(unsigned long flags,int (* fn)(void * arg),void * arg,size_t stack_size,void * stack)88 int ltp_clone(unsigned long flags, int (*fn)(void *arg), void *arg,
89 size_t stack_size, void *stack)
90 {
91 return ltp_clone_(flags, fn, arg, stack_size, stack, NULL, NULL, NULL);
92 }
93
ltp_clone7(unsigned long flags,int (* fn)(void * arg),void * arg,size_t stack_size,void * stack,...)94 int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg,
95 size_t stack_size, void *stack, ...)
96 {
97 pid_t *ptid, *ctid;
98 void *tls;
99 va_list arg_clone;
100
101 va_start(arg_clone, stack);
102 ptid = va_arg(arg_clone, pid_t *);
103 tls = va_arg(arg_clone, void *);
104 ctid = va_arg(arg_clone, pid_t *);
105 va_end(arg_clone);
106
107 return ltp_clone_(flags, fn, arg, stack_size, stack, ptid, tls, ctid);
108 }
109
110 /*
111 * ltp_alloc_stack: allocate stack of size 'size', that is sufficiently
112 * aligned for all arches. User is responsible for freeing allocated
113 * memory.
114 * Returns pointer to new stack. On error, returns NULL with errno set.
115 */
ltp_alloc_stack(size_t size)116 void *ltp_alloc_stack(size_t size)
117 {
118 void *ret = NULL;
119 int err;
120
121 err = posix_memalign(&ret, 64, size);
122 if (err)
123 errno = err;
124
125 return ret;
126 }
127