Blame sysdeps/unix/sysv/linux/createthread.c

Packit 6c4009
/* Low-level thread creation for NPTL.  Linux version.
Packit 6c4009
   Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sched.h>
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <atomic.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
Packit 6c4009
#include <arch-fork.h>
Packit 6c4009
Packit 6c4009
#ifdef __NR_clone2
Packit 6c4009
# define ARCH_CLONE __clone2
Packit 6c4009
#else
Packit 6c4009
# define ARCH_CLONE __clone
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* See the comments in pthread_create.c for the requirements for these
Packit 6c4009
   two macros and the create_thread function.  */
Packit 6c4009
Packit 6c4009
#define START_THREAD_DEFN \
Packit 6c4009
  static int __attribute__ ((noreturn)) start_thread (void *arg)
Packit 6c4009
#define START_THREAD_SELF arg
Packit 6c4009
Packit 6c4009
/* pthread_create.c defines this using START_THREAD_DEFN
Packit 6c4009
   We need a forward declaration here so we can take its address.  */
Packit 6c4009
static int start_thread (void *arg) __attribute__ ((noreturn));
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
create_thread (struct pthread *pd, const struct pthread_attr *attr,
Packit 6c4009
	       bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran)
Packit 6c4009
{
Packit 6c4009
  /* Determine whether the newly created threads has to be started
Packit 6c4009
     stopped since we have to set the scheduling parameters or set the
Packit 6c4009
     affinity.  */
Packit 6c4009
  if (attr != NULL
Packit 6c4009
      && (__glibc_unlikely (attr->cpuset != NULL)
Packit 6c4009
	  || __glibc_unlikely ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)))
Packit 6c4009
    *stopped_start = true;
Packit 6c4009
Packit 6c4009
  pd->stopped_start = *stopped_start;
Packit 6c4009
  if (__glibc_unlikely (*stopped_start))
Packit 6c4009
    /* See CONCURRENCY NOTES in nptl/pthread_creat.c.  */
Packit 6c4009
    lll_lock (pd->lock, LLL_PRIVATE);
Packit 6c4009
Packit 6c4009
  /* We rely heavily on various flags the CLONE function understands:
Packit 6c4009
Packit 6c4009
     CLONE_VM, CLONE_FS, CLONE_FILES
Packit 6c4009
	These flags select semantics with shared address space and
Packit 6c4009
	file descriptors according to what POSIX requires.
Packit 6c4009
Packit 6c4009
     CLONE_SIGHAND, CLONE_THREAD
Packit 6c4009
	This flag selects the POSIX signal semantics and various
Packit 6c4009
	other kinds of sharing (itimers, POSIX timers, etc.).
Packit 6c4009
Packit 6c4009
     CLONE_SETTLS
Packit 6c4009
	The sixth parameter to CLONE determines the TLS area for the
Packit 6c4009
	new thread.
Packit 6c4009
Packit 6c4009
     CLONE_PARENT_SETTID
Packit 6c4009
	The kernels writes the thread ID of the newly created thread
Packit 6c4009
	into the location pointed to by the fifth parameters to CLONE.
Packit 6c4009
Packit 6c4009
	Note that it would be semantically equivalent to use
Packit 6c4009
	CLONE_CHILD_SETTID but it is be more expensive in the kernel.
Packit 6c4009
Packit 6c4009
     CLONE_CHILD_CLEARTID
Packit 6c4009
	The kernels clears the thread ID of a thread that has called
Packit 6c4009
	sys_exit() in the location pointed to by the seventh parameter
Packit 6c4009
	to CLONE.
Packit 6c4009
Packit 6c4009
     The termination signal is chosen to be zero which means no signal
Packit 6c4009
     is sent.  */
Packit 6c4009
  const int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SYSVSEM
Packit 6c4009
			   | CLONE_SIGHAND | CLONE_THREAD
Packit 6c4009
			   | CLONE_SETTLS | CLONE_PARENT_SETTID
Packit 6c4009
			   | CLONE_CHILD_CLEARTID
Packit 6c4009
			   | 0);
Packit 6c4009
Packit 6c4009
  TLS_DEFINE_INIT_TP (tp, pd);
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (ARCH_CLONE (&start_thread, STACK_VARIABLES_ARGS,
Packit 6c4009
				    clone_flags, pd, &pd->tid, tp, &pd->tid)
Packit 6c4009
			== -1))
Packit 6c4009
    return errno;
Packit 6c4009
Packit 6c4009
  /* It's started now, so if we fail below, we'll have to cancel it
Packit 6c4009
     and let it clean itself up.  */
Packit 6c4009
  *thread_ran = true;
Packit 6c4009
Packit 6c4009
  /* Now we have the possibility to set scheduling parameters etc.  */
Packit 6c4009
  if (attr != NULL)
Packit 6c4009
    {
Packit 6c4009
      INTERNAL_SYSCALL_DECL (err);
Packit 6c4009
      int res;
Packit 6c4009
Packit 6c4009
      /* Set the affinity mask if necessary.  */
Packit 6c4009
      if (attr->cpuset != NULL)
Packit 6c4009
	{
Packit 6c4009
	  assert (*stopped_start);
Packit 6c4009
Packit 6c4009
	  res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
Packit 6c4009
				  attr->cpusetsize, attr->cpuset);
Packit 6c4009
Packit 6c4009
	  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res, err)))
Packit 6c4009
	  err_out:
Packit 6c4009
	    {
Packit 6c4009
	      /* The operation failed.  We have to kill the thread.
Packit 6c4009
		 We let the normal cancellation mechanism do the work.  */
Packit 6c4009
Packit 6c4009
	      pid_t pid = __getpid ();
Packit 6c4009
	      INTERNAL_SYSCALL_DECL (err2);
Packit 6c4009
	      (void) INTERNAL_SYSCALL_CALL (tgkill, err2, pid, pd->tid,
Packit 6c4009
					    SIGCANCEL);
Packit 6c4009
Packit 6c4009
	      return INTERNAL_SYSCALL_ERRNO (res, err);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Set the scheduling parameters.  */
Packit 6c4009
      if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
Packit 6c4009
	{
Packit 6c4009
	  assert (*stopped_start);
Packit 6c4009
Packit 6c4009
	  res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
Packit 6c4009
				  pd->schedpolicy, &pd->schedparam);
Packit 6c4009
Packit 6c4009
	  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res, err)))
Packit 6c4009
	    goto err_out;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}