xref: /aosp_15_r20/external/ltp/lib/cloner.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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