Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright (c) International Business Machines Corp., 2009
      3  * Some wrappers for clone functionality.  Thrown together by Serge Hallyn
      4  * <serue (at) 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 "test.h"
     32 #include "config.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 (at) 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
     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 
     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 
     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_clone_malloc: also does the memory allocation for clone with a
    122  * caller-specified size.
    123  */
    124 int
    125 ltp_clone_malloc(unsigned long clone_flags, int (*fn) (void *arg), void *arg,
    126 		 size_t stack_size)
    127 {
    128 	void *stack;
    129 	int ret;
    130 	int saved_errno;
    131 
    132 	stack = malloc(stack_size);
    133 	if (stack == NULL)
    134 		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 
    147 /*
    148  * ltp_clone_quick: calls ltp_clone_malloc with predetermined stack size.
    149  * Experience thus far suggests that one page is often insufficient,
    150  * while 6*getpagesize() seems adequate.
    151  */
    152 int ltp_clone_quick(unsigned long clone_flags, int (*fn) (void *arg), void *arg)
    153 {
    154 	size_t stack_size = getpagesize() * 6;
    155 
    156 	return ltp_clone_malloc(clone_flags, fn, arg, stack_size);
    157 }
    158