blob: 63f223d2a15077938b0f39726d58a7b7b771f66a [file] [log] [blame]
vapierf6d7f092009-11-03 20:07:35 +00001/*
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
Wanlong Gao4548c6c2012-10-19 18:03:36 +080017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
vapierf6d7f092009-11-03 20:07:35 +000018 */
19
yaberauneya8680b282009-11-14 10:27:29 +000020#ifndef _GNU_SOURCE
Zeng Linggang1db62662014-01-09 20:10:11 +080021# define _GNU_SOURCE
yaberauneya8680b282009-11-14 10:27:29 +000022#endif
vapierf6d7f092009-11-03 20:07:35 +000023
24#include <stdio.h>
25#include <errno.h>
Wanlong Gao2b9f5012012-12-25 16:42:54 +080026#include <unistd.h>
vapierf6d7f092009-11-03 20:07:35 +000027#include <string.h>
Wanlong Gao2b9f5012012-12-25 16:42:54 +080028#include <stdlib.h>
29#include <sched.h>
zenglg.jy5f5cb632013-12-18 17:29:51 +080030#include <stdarg.h>
vapierf6d7f092009-11-03 20:07:35 +000031#include "test.h"
Zeng Linggang1db62662014-01-09 20:10:11 +080032#include "config.h"
vapierf6d7f092009-11-03 20:07:35 +000033
Wanlong Gao354ebb42012-12-07 10:10:04 +080034#undef clone /* we want to use clone() */
vapierf6d7f092009-11-03 20:07:35 +000035
Zeng Linggang1db62662014-01-09 20:10:11 +080036/*
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 */
Cyril Hrubis9317d9c2014-01-09 14:42:23 +010047#if defined(__ia64__)
Wanlong Gao354ebb42012-12-07 10:10:04 +080048extern int __clone2(int (*fn) (void *arg), void *child_stack_base,
Zeng Linggang1db62662014-01-09 20:10:11 +080049 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)
vapierf6d7f092009-11-03 20:07:35 +000056#endif
57
Wanlong Gao2b9f5012012-12-25 16:42:54 +080058/*
vapierf6d7f092009-11-03 20:07:35 +000059 * 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)
Wanlong Gao2b9f5012012-12-25 16:42:54 +080063 */
Zeng Linggang1db62662014-01-09 20:10:11 +080064static int
65ltp_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)
vapierf6d7f092009-11-03 20:07:35 +000067{
68 int ret;
69
Mike Frysinger93c60312014-01-09 09:35:08 -050070#if defined(__ia64__)
Zeng Linggang1db62662014-01-09 20:10:11 +080071 ret = __clone2(fn, stack, stack_size, flags, arg, ptid, tls, ctid);
Garrett Cooper9185e832010-11-20 19:32:18 -080072#else
Mike Frysinger93c60312014-01-09 09:35:08 -050073# 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
Garrett Cooper0056e392010-07-22 08:45:53 -070079 /*
Garrett Cooper9185e832010-11-20 19:32:18 -080080 * For archs where stack grows downwards, stack points to the topmost
81 * address of the memory space set up for the child stack.
Garrett Cooper0056e392010-07-22 08:45:53 -070082 */
Mike Frysinger93c60312014-01-09 09:35:08 -050083 if (stack)
84 stack += stack_size;
85# endif
86
Zeng Linggang1db62662014-01-09 20:10:11 +080087 ret = clone(fn, stack, flags, arg, ptid, tls, ctid);
vapierf6d7f092009-11-03 20:07:35 +000088#endif
89
90 return ret;
91}
92
Zeng Linggang1db62662014-01-09 20:10:11 +080093int 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
99int 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
Wanlong Gao2b9f5012012-12-25 16:42:54 +0800120/*
vapierf6d7f092009-11-03 20:07:35 +0000121 * ltp_clone_malloc: also does the memory allocation for clone with a
122 * caller-specified size.
Wanlong Gao2b9f5012012-12-25 16:42:54 +0800123 */
vapierf6d7f092009-11-03 20:07:35 +0000124int
Wanlong Gao354ebb42012-12-07 10:10:04 +0800125ltp_clone_malloc(unsigned long clone_flags, int (*fn) (void *arg), void *arg,
126 size_t stack_size)
vapierf6d7f092009-11-03 20:07:35 +0000127{
Garrett Cooper619e6a72010-12-16 05:15:14 -0800128 void *stack;
vapierf6d7f092009-11-03 20:07:35 +0000129 int ret;
vapierf6d7f092009-11-03 20:07:35 +0000130 int saved_errno;
131
Wanlong Gao2b9f5012012-12-25 16:42:54 +0800132 stack = malloc(stack_size);
133 if (stack == NULL)
vapierf6d7f092009-11-03 20:07:35 +0000134 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
Wanlong Gao2b9f5012012-12-25 16:42:54 +0800147/*
vapierf6d7f092009-11-03 20:07:35 +0000148 * ltp_clone_quick: calls ltp_clone_malloc with predetermined stack size.
149 * Experience thus far suggests that one page is often insufficient,
Cyril Hrubise97ba6f2012-02-23 17:44:51 +0100150 * while 6*getpagesize() seems adequate.
Wanlong Gao2b9f5012012-12-25 16:42:54 +0800151 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800152int ltp_clone_quick(unsigned long clone_flags, int (*fn) (void *arg), void *arg)
vapierf6d7f092009-11-03 20:07:35 +0000153{
Cyril Hrubise97ba6f2012-02-23 17:44:51 +0100154 size_t stack_size = getpagesize() * 6;
vapierf6d7f092009-11-03 20:07:35 +0000155
156 return ltp_clone_malloc(clone_flags, fn, arg, stack_size);
Cyril Hrubise97ba6f2012-02-23 17:44:51 +0100157}