Back to index

glibc  2.9
Defines | Functions | Variables
init.c File Reference
#include <assert.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <pthreadP.h>
#include <atomic.h>
#include <ldsodefs.h>
#include <tls.h>
#include <fork.h>
#include <version.h>
#include <shlib-compat.h>
#include <smp.h>
#include <lowlevellock.h>
#include <kernel-features.h>

Go to the source code of this file.

Defines

#define set_robust_list_not_avail()   __set_robust_list_avail = -1
#define ptr_pthread_functions   NULL

Functions

void __libc_setup_tls (size_t tcbsize, size_t tcbalign)
static void sigcancel_handler (int sig, siginfo_t *si, void *ctx)
static void sighandler_setxid (int sig, siginfo_t *si, void *ctx)
void ** __libc_dl_error_tsd (void)

Variables

size_t __static_tls_size
size_t __static_tls_align_m1
int __set_robust_list_avail
static const char nptl_version[] __attribute_used__ = VERSION
struct xid_command *__xidcmd attribute_hidden

Define Documentation

Definition at line 125 of file init.c.

Definition at line 46 of file init.c.


Function Documentation

void** __libc_dl_error_tsd ( void  )

Definition at line 235 of file init.c.

{
#ifndef SHARED
  /* Unlike in the dynamically linked case the dynamic linker has not
     taken care of initializing the TLS data structures.  */
  __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN);

  /* We must prevent gcc from being clever and move any of the
     following code ahead of the __libc_setup_tls call.  This function
     will initialize the thread register which is subsequently
     used.  */
  __asm __volatile ("");
#endif

  /* Minimal initialization of the thread descriptor.  */
  struct pthread *pd = THREAD_SELF;
  INTERNAL_SYSCALL_DECL (err);
  pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid);
  THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
  THREAD_SETMEM (pd, user_stack, true);
  if (LLL_LOCK_INITIALIZER != 0)
    THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
#if HP_TIMING_AVAIL
  THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
#endif

  /* Initialize the robust mutex data.  */
#ifdef __PTHREAD_MUTEX_HAVE_PREV
  pd->robust_prev = &pd->robust_head;
#endif
  pd->robust_head.list = &pd->robust_head;
#ifdef __NR_set_robust_list
  pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
                              - offsetof (pthread_mutex_t,
                                         __data.__list.__next));
  int res = INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
                           sizeof (struct robust_list_head));
  if (INTERNAL_SYSCALL_ERROR_P (res, err))
#endif
    set_robust_list_not_avail ();

#ifndef __ASSUME_PRIVATE_FUTEX
  /* Private futexes are always used (at least internally) so that
     doing the test once this early is beneficial.  */
  {
    int word = 0;
    word = INTERNAL_SYSCALL (futex, err, 3, &word,
                         FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
    if (!INTERNAL_SYSCALL_ERROR_P (word, err))
      THREAD_SETMEM (pd, header.private_futex, FUTEX_PRIVATE_FLAG);
  }
#endif

  /* Set initial thread's stack block from 0 up to __libc_stack_end.
     It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
     purposes this is good enough.  */
  THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);

  /* Initialize the list of all running threads with the main thread.  */
  INIT_LIST_HEAD (&__stack_user);
  list_add (&pd->list, &__stack_user);

  /* Before initializing __stack_user, the debugger could not find us and
     had to set __nptl_initial_report_events.  Propagate its setting.  */
  THREAD_SETMEM (pd, report_events, __nptl_initial_report_events);

  /* Install the cancellation signal handler.  If for some reason we
     cannot install the handler we do not abort.  Maybe we should, but
     it is only asynchronous cancellation which is affected.  */
  struct sigaction sa;
  sa.sa_sigaction = sigcancel_handler;
  sa.sa_flags = SA_SIGINFO;
  __sigemptyset (&sa.sa_mask);

  (void) __libc_sigaction (SIGCANCEL, &sa, NULL);

  /* Install the handle to change the threads' uid/gid.  */
  sa.sa_sigaction = sighandler_setxid;
  sa.sa_flags = SA_SIGINFO | SA_RESTART;

  (void) __libc_sigaction (SIGSETXID, &sa, NULL);

  /* The parent process might have left the signals blocked.  Just in
     case, unblock it.  We reuse the signal mask in the sigaction
     structure.  It is already cleared.  */
  __sigaddset (&sa.sa_mask, SIGCANCEL);
  __sigaddset (&sa.sa_mask, SIGSETXID);
  (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
                        NULL, _NSIG / 8);

  /* Get the size of the static and alignment requirements for the TLS
     block.  */
  size_t static_tls_align;
  _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);

  /* Make sure the size takes all the alignments into account.  */
  if (STACK_ALIGN > static_tls_align)
    static_tls_align = STACK_ALIGN;
  __static_tls_align_m1 = static_tls_align - 1;

  __static_tls_size = roundup (__static_tls_size, static_tls_align);

  /* Determine the default allowed stack size.  This is the size used
     in case the user does not specify one.  */
  struct rlimit limit;
  if (getrlimit (RLIMIT_STACK, &limit) != 0
      || limit.rlim_cur == RLIM_INFINITY)
    /* The system limit is not usable.  Use an architecture-specific
       default.  */
    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
  else if (limit.rlim_cur < PTHREAD_STACK_MIN)
    /* The system limit is unusably small.
       Use the minimal size acceptable.  */
    limit.rlim_cur = PTHREAD_STACK_MIN;

  /* Make sure it meets the minimum size that allocate_stack
     (allocatestack.c) will demand, which depends on the page size.  */
  const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
  const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
  if (limit.rlim_cur < minstack)
    limit.rlim_cur = minstack;

  /* Round the resource limit up to page size.  */
  limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz;
  __default_stacksize = limit.rlim_cur;

#ifdef SHARED
  /* Transfer the old value from the dynamic linker's internal location.  */
  *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) ();
  GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;

  /* Make __rtld_lock_{,un}lock_recursive use pthread_mutex_{,un}lock,
     keep the lock count from the ld.so implementation.  */
  GL(dl_rtld_lock_recursive) = (void *) INTUSE (__pthread_mutex_lock);
  GL(dl_rtld_unlock_recursive) = (void *) INTUSE (__pthread_mutex_unlock);
  unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count;
  GL(dl_load_lock).mutex.__data.__count = 0;
  while (rtld_lock_count-- > 0)
    INTUSE (__pthread_mutex_lock) (&GL(dl_load_lock).mutex);

  GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
#endif

  GL(dl_init_static_tls) = &__pthread_init_static_tls;

  GL(dl_wait_lookup_done) = &__wait_lookup_done;

  /* Register the fork generation counter with the libc.  */
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
  __libc_multiple_threads_ptr =
#endif
    __libc_pthread_init (&__fork_generation, __reclaim_stacks,
                      ptr_pthread_functions);

  /* Determine whether the machine is SMP or not.  */
  __is_smp = is_smp_system ();
}

Here is the call graph for this function:

void __libc_setup_tls ( size_t  tcbsize,
size_t  tcbalign 
)

Definition at line 110 of file libc-tls.c.

{
  void *tlsblock;
  size_t memsz = 0;
  size_t filesz = 0;
  void *initimage = NULL;
  size_t align = 0;
  size_t max_align = tcbalign;
  size_t tcb_offset;
  ElfW(Phdr) *phdr;

  /* Look through the TLS segment if there is any.  */
  if (_dl_phdr != NULL)
    for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
      if (phdr->p_type == PT_TLS)
       {
         /* Remember the values we need.  */
         memsz = phdr->p_memsz;
         filesz = phdr->p_filesz;
         initimage = (void *) phdr->p_vaddr;
         align = phdr->p_align;
         if (phdr->p_align > max_align)
           max_align = phdr->p_align;
         break;
       }

  /* We have to set up the TCB block which also (possibly) contains
     'errno'.  Therefore we avoid 'malloc' which might touch 'errno'.
     Instead we use 'sbrk' which would only uses 'errno' if it fails.
     In this case we are right away out of memory and the user gets
     what she/he deserves.

     The initialized value of _dl_tls_static_size is provided by dl-open.c
     to request some surplus that permits dynamic loading of modules with
     IE-model TLS.  */
#if TLS_TCB_AT_TP
  tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign);
  tlsblock = __sbrk (tcb_offset + tcbsize + max_align);
#elif TLS_DTV_AT_TP
  tcb_offset = roundup (tcbsize, align ?: 1);
  tlsblock = __sbrk (tcb_offset + memsz + max_align
                   + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
  tlsblock += TLS_PRE_TCB_SIZE;
#else
  /* In case a model with a different layout for the TCB and DTV
     is defined add another #elif here and in the following #ifs.  */
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif

  /* Align the TLS block.  */
  tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
                     & ~(max_align - 1));

  /* Initialize the dtv.  [0] is the length, [1] the generation counter.  */
  static_dtv[0].counter = (sizeof (static_dtv) / sizeof (static_dtv[0])) - 2;
  // static_dtv[1].counter = 0;           would be needed if not already done

  /* Initialize the TLS block.  */
#if TLS_TCB_AT_TP
  static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
                            - roundup (memsz, align ?: 1));
  static_map.l_tls_offset = roundup (memsz, align ?: 1);
#elif TLS_DTV_AT_TP
  static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
  static_map.l_tls_offset = tcb_offset;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
  static_dtv[2].pointer.is_static = true;
  /* sbrk gives us zero'd memory, so we don't need to clear the remainder.  */
  memcpy (static_dtv[2].pointer.val, initimage, filesz);

  /* Install the pointer to the dtv.  */

  /* Initialize the thread pointer.  */
#if TLS_TCB_AT_TP
  INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv);

  const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0);
#elif TLS_DTV_AT_TP
  INSTALL_DTV (tlsblock, static_dtv);
  const char *lossage = TLS_INIT_TP (tlsblock, 0);
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
  if (__builtin_expect (lossage != NULL, 0))
    __libc_fatal (lossage);

  /* We have to create a fake link map which normally would be created
     by the dynamic linker.  It just has to have enough information to
     make the TLS routines happy.  */
  static_map.l_tls_align = align;
  static_map.l_tls_blocksize = memsz;
  static_map.l_tls_initimage = initimage;
  static_map.l_tls_initimage_size = filesz;
  static_map.l_type = lt_executable;
  static_map.l_tls_modid = 1;

  init_slotinfo ();
  // static_slotinfo.si.slotinfo[1].gen = 0; already zero
  static_slotinfo.si.slotinfo[1].map = &static_map;

  memsz = roundup (memsz, align ?: 1);

#if TLS_TCB_AT_TP
  memsz += tcbsize;
#elif TLS_DTV_AT_TP
  memsz += tcb_offset;
#endif

  init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sigcancel_handler ( int  sig,
siginfo_t *  si,
void *  ctx 
) [static]

Definition at line 131 of file init.c.

{
#ifdef __ASSUME_CORRECT_SI_PID
  /* Determine the process ID.  It might be negative if the thread is
     in the middle of a fork() call.  */
  pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
  if (__builtin_expect (pid < 0, 0))
    pid = -pid;
#endif

  /* Safety check.  It would be possible to call this function for
     other signals and send a signal from another process.  This is not
     correct and might even be a security problem.  Try to catch as
     many incorrect invocations as possible.  */
  if (sig != SIGCANCEL
#ifdef __ASSUME_CORRECT_SI_PID
      /* Kernels before 2.5.75 stored the thread ID and not the process
        ID in si_pid so we skip this test.  */
      || si->si_pid != pid
#endif
      || si->si_code != SI_TKILL)
    return;

  struct pthread *self = THREAD_SELF;

  int oldval = THREAD_GETMEM (self, cancelhandling);
  while (1)
    {
      /* We are canceled now.  When canceled by another thread this flag
        is already set but if the signal is directly send (internally or
        from another process) is has to be done here.  */
      int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;

      if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
       /* Already canceled or exiting.  */
       break;

      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
                                         oldval);
      if (curval == oldval)
       {
         /* Set the return value.  */
         THREAD_SETMEM (self, result, PTHREAD_CANCELED);

         /* Make sure asynchronous cancellation is still enabled.  */
         if ((newval & CANCELTYPE_BITMASK) != 0)
           /* Run the registered destructors and terminate the thread.  */
           __do_cancel ();

         break;
       }

      oldval = curval;
    }
}

Here is the caller graph for this function:

static void sighandler_setxid ( int  sig,
siginfo_t *  si,
void *  ctx 
) [static]

Definition at line 192 of file init.c.

{
#ifdef __ASSUME_CORRECT_SI_PID
  /* Determine the process ID.  It might be negative if the thread is
     in the middle of a fork() call.  */
  pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
  if (__builtin_expect (pid < 0, 0))
    pid = -pid;
#endif

  /* Safety check.  It would be possible to call this function for
     other signals and send a signal from another process.  This is not
     correct and might even be a security problem.  Try to catch as
     many incorrect invocations as possible.  */
  if (sig != SIGSETXID
#ifdef __ASSUME_CORRECT_SI_PID
      /* Kernels before 2.5.75 stored the thread ID and not the process
        ID in si_pid so we skip this test.  */
      || si->si_pid != pid
#endif
      || si->si_code != SI_TKILL)
    return;

  INTERNAL_SYSCALL_DECL (err);
  INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0],
                     __xidcmd->id[1], __xidcmd->id[2]);

  if (atomic_decrement_val (&__xidcmd->cntr) == 0)
    lll_futex_wake (&__xidcmd->cntr, 1, LLL_PRIVATE);

  /* Reset the SETXID flag.  */
  struct pthread *self = THREAD_SELF;
  int flags = THREAD_GETMEM (self, cancelhandling);
  THREAD_SETMEM (self, cancelhandling, flags & ~SETXID_BITMASK);

  /* And release the futex.  */
  self->setxid_futex = 1;
  lll_futex_wake (&self->setxid_futex, 1, LLL_PRIVATE);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char nptl_version [] __attribute_used__ = VERSION [static]

Definition at line 53 of file init.c.

Definition at line 45 of file init.c.

Definition at line 41 of file init.c.

Definition at line 40 of file init.c.

struct xid_command* __xidcmd attribute_hidden

Definition at line 188 of file init.c.