(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
clone-internal.c
       1  /* The internal wrapper of clone and clone3.
       2     Copyright (C) 2021-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library.  If not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <sysdep.h>
      20  #include <stddef.h>
      21  #include <errno.h>
      22  #include <sched.h>
      23  #include <clone_internal.h>
      24  #include <libc-pointer-arith.h>	/* For cast_to_pointer.  */
      25  #include <stackinfo.h>		/* For _STACK_GROWS_{UP,DOWN}.  */
      26  
      27  #define CLONE_ARGS_SIZE_VER0 64 /* sizeof first published struct */
      28  #define CLONE_ARGS_SIZE_VER1 80 /* sizeof second published struct */
      29  #define CLONE_ARGS_SIZE_VER2 88 /* sizeof third published struct */
      30  
      31  #define sizeof_field(TYPE, MEMBER) sizeof ((((TYPE *)0)->MEMBER))
      32  #define offsetofend(TYPE, MEMBER) \
      33    (offsetof (TYPE, MEMBER) + sizeof_field (TYPE, MEMBER))
      34  
      35  _Static_assert (__alignof (struct clone_args) == 8,
      36  		"__alignof (struct clone_args) != 8");
      37  _Static_assert (offsetofend (struct clone_args, tls) == CLONE_ARGS_SIZE_VER0,
      38  		"offsetofend (struct clone_args, tls) != CLONE_ARGS_SIZE_VER0");
      39  _Static_assert (offsetofend (struct clone_args, set_tid_size) == CLONE_ARGS_SIZE_VER1,
      40  		"offsetofend (struct clone_args, set_tid_size) != CLONE_ARGS_SIZE_VER1");
      41  _Static_assert (offsetofend (struct clone_args, cgroup) == CLONE_ARGS_SIZE_VER2,
      42  		"offsetofend (struct clone_args, cgroup) != CLONE_ARGS_SIZE_VER2");
      43  _Static_assert (sizeof (struct clone_args) == CLONE_ARGS_SIZE_VER2,
      44  		"sizeof (struct clone_args) != CLONE_ARGS_SIZE_VER2");
      45  
      46  int
      47  __clone_internal_fallback (struct clone_args *cl_args,
      48  			   int (*func) (void *arg), void *arg)
      49  {
      50    /* Map clone3 arguments to clone arguments.  NB: No need to check
      51       invalid clone3 specific bits in flags nor exit_signal since this
      52       is an internal function.  */
      53    int flags = cl_args->flags | cl_args->exit_signal;
      54    void *stack = cast_to_pointer (cl_args->stack);
      55    int ret;
      56  
      57  #ifdef __ia64__
      58    ret = __clone2 (func, stack, cl_args->stack_size,
      59  		  flags, arg,
      60  		  cast_to_pointer (cl_args->parent_tid),
      61  		  cast_to_pointer (cl_args->tls),
      62  		  cast_to_pointer (cl_args->child_tid));
      63  #else
      64  # if !_STACK_GROWS_DOWN && !_STACK_GROWS_UP
      65  #  error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
      66  # endif
      67  
      68  # if _STACK_GROWS_DOWN
      69    stack += cl_args->stack_size;
      70  # endif
      71    ret = __clone (func, stack, flags, arg,
      72  		 cast_to_pointer (cl_args->parent_tid),
      73  		 cast_to_pointer (cl_args->tls),
      74  		 cast_to_pointer (cl_args->child_tid));
      75  #endif
      76    return ret;
      77  }
      78  
      79  int
      80  __clone3_internal (struct clone_args *cl_args, int (*func) (void *args),
      81  		   void *arg)
      82  {
      83  #ifdef HAVE_CLONE3_WRAPPER
      84  # if __ASSUME_CLONE3
      85    return __clone3 (cl_args, sizeof (*cl_args), func, arg);
      86  # else
      87    static int clone3_supported = 1;
      88    if (atomic_load_relaxed (&clone3_supported) == 1)
      89      {
      90        int ret = __clone3 (cl_args, sizeof (*cl_args), func, arg);
      91        if (ret != -1 || errno != ENOSYS)
      92  	return ret;
      93  
      94        atomic_store_relaxed (&clone3_supported, 0);
      95      }
      96  # endif
      97  #endif
      98    __set_errno (ENOSYS);
      99    return -1;
     100  }
     101  
     102  int
     103  __clone_internal (struct clone_args *cl_args,
     104  		  int (*func) (void *arg), void *arg)
     105  {
     106  #ifdef HAVE_CLONE3_WRAPPER
     107    int saved_errno = errno;
     108    int ret = __clone3_internal (cl_args, func, arg);
     109    if (ret != -1 || errno != ENOSYS)
     110      return ret;
     111  
     112    /* NB: Restore errno since errno may be checked against non-zero
     113       return value.  */
     114    __set_errno (saved_errno);
     115  #endif
     116  
     117    return __clone_internal_fallback (cl_args, func, arg);
     118  }
     119  
     120  libc_hidden_def (__clone_internal)