Back to index

glibc  2.9
Defines | Functions | Variables
createthread.c File Reference
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <atomic.h>
#include <ldsodefs.h>
#include <tls.h>
#include "kernel-features.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.


#define TLS_VALUE   pd
#define ARCH_CLONE   __clone


static int do_clone (struct pthread *pd, const struct pthread_attr *attr, int clone_flags, int(*fct)(void *), STACK_VARIABLES_PARMS, int stopped)
static int create_thread (struct pthread *pd, const struct pthread_attr *attr, STACK_VARIABLES_PARMS)


int *__libc_multiple_threads_ptr attribute_hidden

Define Documentation

#define ARCH_CLONE   __clone

Definition at line 40 of file createthread.c.


Definition at line 31 of file createthread.c.

#define TLS_VALUE   pd

Definition at line 36 of file createthread.c.

Function Documentation

static int create_thread ( struct pthread pd,
const struct pthread_attr attr,
) [static]

Definition at line 144 of file createthread.c.

#ifdef TLS_TCB_AT_TP
  assert (pd->header.tcb != NULL);

  /* We rely heavily on various flags the CLONE function understands:

       These flags select semantics with shared address space and
       file descriptors according to what POSIX requires.

       This flag selects the POSIX signal semantics.

       The sixth parameter to CLONE determines the TLS area for the
       new thread.

       The kernels writes the thread ID of the newly created thread
       into the location pointed to by the fifth parameters to CLONE.

       Note that it would be semantically equivalent to use
       CLONE_CHILD_SETTID but it is be more expensive in the kernel.

       The kernels clears the thread ID of a thread that has called
       sys_exit() in the location pointed to by the seventh parameter
       to CLONE.

       No signal is generated if the thread exists and it is
       automatically reaped.

     The termination signal is chosen to be zero which means no signal
     is sent.  */
                   | CLONE_DETACHED
                   | 0);

  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
      /* The parent thread is supposed to report events.  Check whether
        the TD_CREATE event is needed, too.  */
      const int _idx = __td_eventword (TD_CREATE);
      const uint32_t _mask = __td_eventmask (TD_CREATE);

      if ((_mask & (__nptl_threads_events.event_bits[_idx]
                  | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
         /* We always must have the thread start stopped.  */
         pd->stopped_start = true;

         /* Create the thread.  We always create the thread stopped
            so that it does not get far before we tell the debugger.  */
         int res = do_clone (pd, attr, clone_flags, start_thread,
                           STACK_VARIABLES_ARGS, 1);
         if (res == 0)
             /* Now fill in the information about the new thread in
               the newly created thread's data structure.  We cannot let
               the new thread do this since we don't know whether it was
               already scheduled when we send the event.  */
             pd->eventbuf.eventnum = TD_CREATE;
             pd->eventbuf.eventdata = pd;

             /* Enqueue the descriptor.  */
              pd->nextevent = __nptl_last_event;
             while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
                                                    pd, pd->nextevent)
                   != 0);

             /* Now call the function which signals the event.  */
             __nptl_create_event ();

             /* And finally restart the new thread.  */
             lll_unlock (pd->lock, LLL_PRIVATE);

         return res;


  /* Determine whether the newly created threads has to be started
     stopped since we have to set the scheduling parameters or set the
     affinity.  */
  bool stopped = false;
  if (attr != NULL && (attr->cpuset != NULL
                     || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
    stopped = true;
  pd->stopped_start = stopped;
  pd->parent_cancelhandling = THREAD_GETMEM (THREAD_SELF, cancelhandling);

  /* Actually create the thread.  */
  int res = do_clone (pd, attr, clone_flags, start_thread,
                    STACK_VARIABLES_ARGS, stopped);

  if (res == 0 && stopped)
    /* And finally restart the new thread.  */
    lll_unlock (pd->lock, LLL_PRIVATE);

  return res;

Here is the call graph for this function:

Here is the caller graph for this function:

static int do_clone ( struct pthread pd,
const struct pthread_attr attr,
int  clone_flags,
int(*)(void *)  fct,
int  stopped 
) [static]

Definition at line 51 of file createthread.c.


  if (__builtin_expect (stopped != 0, 0))
    /* We make sure the thread does not run far by forcing it to get a
       lock.  We lock it here too so that the new thread cannot continue
       until we tell it to.  */
    lll_lock (pd->lock, LLL_PRIVATE);

  /* One more thread.  We cannot have the thread do this itself, since it
     might exist but not have been scheduled yet by the time we've returned
     and need to check the value to behave correctly.  We must do it before
     creating the thread, in case it does get scheduled first and then
     might mistakenly think it was the only thread.  In the failure case,
     we momentarily store a false value; this doesn't matter because there
     is no kosher thing a signal handler interrupting us right here can do
     that cares whether the thread count is correct.  */
  atomic_increment (&__nptl_nthreads);

  if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
                pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
      atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second.  */

      /* Failed.  If the thread is detached, remove the TCB here since
        the caller cannot do this.  The caller remembered the thread
        as detached and cannot reverify that it is not since it must
        not access the thread descriptor again.  */
      if (IS_DETACHED (pd))
       __deallocate_stack (pd);

      /* We have to translate error codes.  */
      return errno == ENOMEM ? EAGAIN : errno;

  /* Now we have the possibility to set scheduling parameters etc.  */
  if (__builtin_expect (stopped != 0, 0))
      int res = 0;

      /* Set the affinity mask if necessary.  */
      if (attr->cpuset != NULL)
         res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
                              attr->cpusetsize, attr->cpuset);

         if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
             /* The operation failed.  We have to kill the thread.  First
               send it the cancellation signal.  */
             INTERNAL_SYSCALL_DECL (err2);
             (void) INTERNAL_SYSCALL (tgkill, err2, 3,
                                   THREAD_GETMEM (THREAD_SELF, pid),
                                   pd->tid, SIGCANCEL);
             (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);

             return (INTERNAL_SYSCALL_ERROR_P (res, err)
                    ? INTERNAL_SYSCALL_ERRNO (res, err)
                    : 0);

      /* Set the scheduling parameters.  */
      if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
         res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
                              pd->schedpolicy, &pd->schedparam);

         if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
           goto err_out;

  /* We now have for sure more than one thread.  The main thread might
     not yet have the flag set.  No need to set the global variable
     again if this is what we use.  */
  THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);

  return 0;

Here is the call graph for this function:

Here is the caller graph for this function:

Variable Documentation

Definition at line 46 of file createthread.c.