Blame nptl/nptl-init.c

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 <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/resource.h>
Packit 6c4009
#include <pthreadP.h>
Packit 6c4009
#include <atomic.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
#include <list.h>
Packit 6c4009
#include <fork.h>
Packit 6c4009
#include <version.h>
Packit 6c4009
#include <shlib-compat.h>
Packit 6c4009
#include <smp.h>
Packit 6c4009
#include <lowlevellock.h>
Packit 6c4009
#include <futex-internal.h>
Packit 6c4009
#include <kernel-features.h>
Packit 6c4009
#include <libc-pointer-arith.h>
Packit 6c4009
#include <pthread-pids.h>
Packit 6c4009
Packit 6c4009
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
Packit 6c4009
/* Pointer to the corresponding variable in libc.  */
Packit 6c4009
int *__libc_multiple_threads_ptr attribute_hidden;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Size and alignment of static TLS block.  */
Packit 6c4009
size_t __static_tls_size;
Packit 6c4009
size_t __static_tls_align_m1;
Packit 6c4009
Packit 6c4009
#ifndef __ASSUME_SET_ROBUST_LIST
Packit 6c4009
/* Negative if we do not have the system call and we can use it.  */
Packit 6c4009
int __set_robust_list_avail;
Packit 6c4009
# define set_robust_list_not_avail() \
Packit 6c4009
  __set_robust_list_avail = -1
Packit 6c4009
#else
Packit 6c4009
# define set_robust_list_not_avail() do { } while (0)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
Packit 6c4009
/* Nonzero if we do not have FUTEX_CLOCK_REALTIME.  */
Packit 6c4009
int __have_futex_clock_realtime;
Packit 6c4009
# define __set_futex_clock_realtime() \
Packit 6c4009
  __have_futex_clock_realtime = 1
Packit 6c4009
#else
Packit 6c4009
#define __set_futex_clock_realtime() do { } while (0)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Version of the library, used in libthread_db to detect mismatches.  */
Packit 6c4009
static const char nptl_version[] __attribute_used__ = VERSION;
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
static
Packit 6c4009
#else
Packit 6c4009
extern
Packit 6c4009
#endif
Packit 6c4009
void __nptl_set_robust (struct pthread *);
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
static const struct pthread_functions pthread_functions =
Packit 6c4009
  {
Packit 6c4009
    .ptr_pthread_attr_destroy = __pthread_attr_destroy,
Packit 6c4009
# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
Packit 6c4009
    .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0,
Packit 6c4009
# endif
Packit 6c4009
    .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1,
Packit 6c4009
    .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate,
Packit 6c4009
    .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate,
Packit 6c4009
    .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched,
Packit 6c4009
    .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched,
Packit 6c4009
    .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam,
Packit 6c4009
    .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam,
Packit 6c4009
    .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy,
Packit 6c4009
    .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy,
Packit 6c4009
    .ptr_pthread_attr_getscope = __pthread_attr_getscope,
Packit 6c4009
    .ptr_pthread_attr_setscope = __pthread_attr_setscope,
Packit 6c4009
    .ptr_pthread_condattr_destroy = __pthread_condattr_destroy,
Packit 6c4009
    .ptr_pthread_condattr_init = __pthread_condattr_init,
Packit 6c4009
    .ptr___pthread_cond_broadcast = __pthread_cond_broadcast,
Packit 6c4009
    .ptr___pthread_cond_destroy = __pthread_cond_destroy,
Packit 6c4009
    .ptr___pthread_cond_init = __pthread_cond_init,
Packit 6c4009
    .ptr___pthread_cond_signal = __pthread_cond_signal,
Packit 6c4009
    .ptr___pthread_cond_wait = __pthread_cond_wait,
Packit 6c4009
    .ptr___pthread_cond_timedwait = __pthread_cond_timedwait,
Packit 6c4009
# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
Packit 6c4009
    .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0,
Packit 6c4009
    .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0,
Packit 6c4009
    .ptr___pthread_cond_init_2_0 = __pthread_cond_init_2_0,
Packit 6c4009
    .ptr___pthread_cond_signal_2_0 = __pthread_cond_signal_2_0,
Packit 6c4009
    .ptr___pthread_cond_wait_2_0 = __pthread_cond_wait_2_0,
Packit 6c4009
    .ptr___pthread_cond_timedwait_2_0 = __pthread_cond_timedwait_2_0,
Packit 6c4009
# endif
Packit 6c4009
    .ptr_pthread_equal = __pthread_equal,
Packit 6c4009
    .ptr___pthread_exit = __pthread_exit,
Packit 6c4009
    .ptr_pthread_getschedparam = __pthread_getschedparam,
Packit 6c4009
    .ptr_pthread_setschedparam = __pthread_setschedparam,
Packit 6c4009
    .ptr_pthread_mutex_destroy = __pthread_mutex_destroy,
Packit 6c4009
    .ptr_pthread_mutex_init = __pthread_mutex_init,
Packit 6c4009
    .ptr_pthread_mutex_lock = __pthread_mutex_lock,
Packit 6c4009
    .ptr_pthread_mutex_unlock = __pthread_mutex_unlock,
Packit 6c4009
    .ptr___pthread_setcancelstate = __pthread_setcancelstate,
Packit 6c4009
    .ptr_pthread_setcanceltype = __pthread_setcanceltype,
Packit 6c4009
    .ptr___pthread_cleanup_upto = __pthread_cleanup_upto,
Packit 6c4009
    .ptr___pthread_once = __pthread_once,
Packit 6c4009
    .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock,
Packit 6c4009
    .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock,
Packit 6c4009
    .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock,
Packit 6c4009
    .ptr___pthread_key_create = __pthread_key_create,
Packit 6c4009
    .ptr___pthread_getspecific = __pthread_getspecific,
Packit 6c4009
    .ptr___pthread_setspecific = __pthread_setspecific,
Packit 6c4009
    .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer,
Packit 6c4009
    .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore,
Packit 6c4009
    .ptr_nthreads = &__nptl_nthreads,
Packit 6c4009
    .ptr___pthread_unwind = &__pthread_unwind,
Packit 6c4009
    .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
Packit 6c4009
# ifdef SIGSETXID
Packit 6c4009
    .ptr__nptl_setxid = __nptl_setxid,
Packit 6c4009
# endif
Packit 6c4009
    .ptr_set_robust = __nptl_set_robust
Packit 6c4009
  };
Packit 6c4009
# define ptr_pthread_functions &pthread_functions
Packit 6c4009
#else
Packit 6c4009
# define ptr_pthread_functions NULL
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
static
Packit 6c4009
#endif
Packit 6c4009
void
Packit 6c4009
__nptl_set_robust (struct pthread *self)
Packit 6c4009
{
Packit 6c4009
#ifdef __NR_set_robust_list
Packit 6c4009
  INTERNAL_SYSCALL_DECL (err);
Packit 6c4009
  INTERNAL_SYSCALL (set_robust_list, err, 2, &self->robust_head,
Packit 6c4009
		    sizeof (struct robust_list_head));
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef SIGCANCEL
Packit 6c4009
/* For asynchronous cancellation we use a signal.  This is the handler.  */
Packit 6c4009
static void
Packit 6c4009
sigcancel_handler (int sig, siginfo_t *si, void *ctx)
Packit 6c4009
{
Packit 6c4009
  /* Safety check.  It would be possible to call this function for
Packit 6c4009
     other signals and send a signal from another process.  This is not
Packit 6c4009
     correct and might even be a security problem.  Try to catch as
Packit 6c4009
     many incorrect invocations as possible.  */
Packit 6c4009
  if (sig != SIGCANCEL
Packit 6c4009
      || si->si_pid != __getpid()
Packit 6c4009
      || si->si_code != SI_TKILL)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  struct pthread *self = THREAD_SELF;
Packit 6c4009
Packit 6c4009
  int oldval = THREAD_GETMEM (self, cancelhandling);
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* We are canceled now.  When canceled by another thread this flag
Packit 6c4009
	 is already set but if the signal is directly send (internally or
Packit 6c4009
	 from another process) is has to be done here.  */
Packit 6c4009
      int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
Packit 6c4009
Packit 6c4009
      if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
Packit 6c4009
	/* Already canceled or exiting.  */
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
Packit 6c4009
					      oldval);
Packit 6c4009
      if (curval == oldval)
Packit 6c4009
	{
Packit 6c4009
	  /* Set the return value.  */
Packit 6c4009
	  THREAD_SETMEM (self, result, PTHREAD_CANCELED);
Packit 6c4009
Packit 6c4009
	  /* Make sure asynchronous cancellation is still enabled.  */
Packit 6c4009
	  if ((newval & CANCELTYPE_BITMASK) != 0)
Packit 6c4009
	    /* Run the registered destructors and terminate the thread.  */
Packit 6c4009
	    __do_cancel ();
Packit 6c4009
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      oldval = curval;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef SIGSETXID
Packit 6c4009
struct xid_command *__xidcmd attribute_hidden;
Packit 6c4009
Packit 6c4009
/* We use the SIGSETXID signal in the setuid, setgid, etc. implementations to
Packit 6c4009
   tell each thread to call the respective setxid syscall on itself.  This is
Packit 6c4009
   the handler.  */
Packit 6c4009
static void
Packit 6c4009
sighandler_setxid (int sig, siginfo_t *si, void *ctx)
Packit 6c4009
{
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
  /* Safety check.  It would be possible to call this function for
Packit 6c4009
     other signals and send a signal from another process.  This is not
Packit 6c4009
     correct and might even be a security problem.  Try to catch as
Packit 6c4009
     many incorrect invocations as possible.  */
Packit 6c4009
  if (sig != SIGSETXID
Packit 6c4009
      || si->si_pid != __getpid ()
Packit 6c4009
      || si->si_code != SI_TKILL)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  INTERNAL_SYSCALL_DECL (err);
Packit 6c4009
  result = INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0],
Packit 6c4009
				 __xidcmd->id[1], __xidcmd->id[2]);
Packit 6c4009
  int error = 0;
Packit 6c4009
  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
Packit 6c4009
    error = INTERNAL_SYSCALL_ERRNO (result, err);
Packit 6c4009
  __nptl_setxid_error (__xidcmd, error);
Packit 6c4009
Packit 6c4009
  /* Reset the SETXID flag.  */
Packit 6c4009
  struct pthread *self = THREAD_SELF;
Packit 6c4009
  int flags, newval;
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      flags = THREAD_GETMEM (self, cancelhandling);
Packit 6c4009
      newval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
Packit 6c4009
					  flags & ~SETXID_BITMASK, flags);
Packit 6c4009
    }
Packit 6c4009
  while (flags != newval);
Packit 6c4009
Packit 6c4009
  /* And release the futex.  */
Packit 6c4009
  self->setxid_futex = 1;
Packit 6c4009
  futex_wake (&self->setxid_futex, 1, FUTEX_PRIVATE);
Packit 6c4009
Packit 6c4009
  if (atomic_decrement_val (&__xidcmd->cntr) == 0)
Packit 6c4009
    futex_wake ((unsigned int *) &__xidcmd->cntr, 1, FUTEX_PRIVATE);
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* When using __thread for this, we do it in libc so as not
Packit 6c4009
   to give libpthread its own TLS segment just for this.  */
Packit 6c4009
extern void **__libc_dl_error_tsd (void) __attribute__ ((const));
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This can be set by the debugger before initialization is complete.  */
Packit 6c4009
static bool __nptl_initial_report_events __attribute_used__;
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__pthread_initialize_minimal_internal (void)
Packit 6c4009
{
Packit 6c4009
  /* Minimal initialization of the thread descriptor.  */
Packit 6c4009
  struct pthread *pd = THREAD_SELF;
Packit 6c4009
  __pthread_initialize_pids (pd);
Packit 6c4009
  THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
Packit 6c4009
  THREAD_SETMEM (pd, user_stack, true);
Packit 6c4009
  if (LLL_LOCK_INITIALIZER != 0)
Packit 6c4009
    THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
Packit 6c4009
Packit 6c4009
  /* Initialize the robust mutex data.  */
Packit 6c4009
  {
Packit 6c4009
#if __PTHREAD_MUTEX_HAVE_PREV
Packit 6c4009
    pd->robust_prev = &pd->robust_head;
Packit 6c4009
#endif
Packit 6c4009
    pd->robust_head.list = &pd->robust_head;
Packit 6c4009
#ifdef __NR_set_robust_list
Packit 6c4009
    pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
Packit 6c4009
				    - offsetof (pthread_mutex_t,
Packit 6c4009
						__data.__list.__next));
Packit 6c4009
    INTERNAL_SYSCALL_DECL (err);
Packit 6c4009
    int res = INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
Packit 6c4009
				sizeof (struct robust_list_head));
Packit 6c4009
    if (INTERNAL_SYSCALL_ERROR_P (res, err))
Packit 6c4009
#endif
Packit 6c4009
      set_robust_list_not_avail ();
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
#ifdef __NR_futex
Packit 6c4009
# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
Packit 6c4009
    {
Packit 6c4009
      int word = 0;
Packit 6c4009
      /* NB: the syscall actually takes six parameters.  The last is the
Packit 6c4009
	 bit mask.  But since we will not actually wait at all the value
Packit 6c4009
	 is irrelevant.  Given that passing six parameters is difficult
Packit 6c4009
	 on some architectures we just pass whatever random value the
Packit 6c4009
	 calling convention calls for to the kernel.  It causes no harm.  */
Packit 6c4009
      INTERNAL_SYSCALL_DECL (err);
Packit 6c4009
      word = INTERNAL_SYSCALL (futex, err, 5, &word,
Packit 6c4009
			       FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME
Packit 6c4009
			       | FUTEX_PRIVATE_FLAG, 1, NULL, 0);
Packit 6c4009
      assert (INTERNAL_SYSCALL_ERROR_P (word, err));
Packit 6c4009
      if (INTERNAL_SYSCALL_ERRNO (word, err) != ENOSYS)
Packit 6c4009
	__set_futex_clock_realtime ();
Packit 6c4009
    }
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Set initial thread's stack block from 0 up to __libc_stack_end.
Packit 6c4009
     It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
Packit 6c4009
     purposes this is good enough.  */
Packit 6c4009
  THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
Packit 6c4009
Packit 6c4009
  /* Initialize the list of all running threads with the main thread.  */
Packit 6c4009
  INIT_LIST_HEAD (&__stack_user);
Packit 6c4009
  list_add (&pd->list, &__stack_user);
Packit 6c4009
Packit 6c4009
  /* Before initializing __stack_user, the debugger could not find us and
Packit 6c4009
     had to set __nptl_initial_report_events.  Propagate its setting.  */
Packit 6c4009
  THREAD_SETMEM (pd, report_events, __nptl_initial_report_events);
Packit 6c4009
Packit 6c4009
#if defined SIGCANCEL || defined SIGSETXID
Packit 6c4009
  struct sigaction sa;
Packit 6c4009
  __sigemptyset (&sa.sa_mask);
Packit 6c4009
Packit 6c4009
# ifdef SIGCANCEL
Packit 6c4009
  /* Install the cancellation signal handler.  If for some reason we
Packit 6c4009
     cannot install the handler we do not abort.  Maybe we should, but
Packit 6c4009
     it is only asynchronous cancellation which is affected.  */
Packit 6c4009
  sa.sa_sigaction = sigcancel_handler;
Packit 6c4009
  sa.sa_flags = SA_SIGINFO;
Packit 6c4009
  (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
# ifdef SIGSETXID
Packit 6c4009
  /* Install the handle to change the threads' uid/gid.  */
Packit 6c4009
  sa.sa_sigaction = sighandler_setxid;
Packit 6c4009
  sa.sa_flags = SA_SIGINFO | SA_RESTART;
Packit 6c4009
  (void) __libc_sigaction (SIGSETXID, &sa, NULL);
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
  /* The parent process might have left the signals blocked.  Just in
Packit 6c4009
     case, unblock it.  We reuse the signal mask in the sigaction
Packit 6c4009
     structure.  It is already cleared.  */
Packit 6c4009
# ifdef SIGCANCEL
Packit 6c4009
  __sigaddset (&sa.sa_mask, SIGCANCEL);
Packit 6c4009
# endif
Packit 6c4009
# ifdef SIGSETXID
Packit 6c4009
  __sigaddset (&sa.sa_mask, SIGSETXID);
Packit 6c4009
# endif
Packit 6c4009
  {
Packit 6c4009
    INTERNAL_SYSCALL_DECL (err);
Packit 6c4009
    (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
Packit 6c4009
			     NULL, _NSIG / 8);
Packit 6c4009
  }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Get the size of the static and alignment requirements for the TLS
Packit 6c4009
     block.  */
Packit 6c4009
  size_t static_tls_align;
Packit 6c4009
  _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);
Packit 6c4009
Packit 6c4009
  /* Make sure the size takes all the alignments into account.  */
Packit 6c4009
  if (STACK_ALIGN > static_tls_align)
Packit 6c4009
    static_tls_align = STACK_ALIGN;
Packit 6c4009
  __static_tls_align_m1 = static_tls_align - 1;
Packit 6c4009
Packit 6c4009
  __static_tls_size = roundup (__static_tls_size, static_tls_align);
Packit 6c4009
Packit 6c4009
  /* Determine the default allowed stack size.  This is the size used
Packit 6c4009
     in case the user does not specify one.  */
Packit 6c4009
  struct rlimit limit;
Packit 6c4009
  if (__getrlimit (RLIMIT_STACK, &limit) != 0
Packit 6c4009
      || limit.rlim_cur == RLIM_INFINITY)
Packit 6c4009
    /* The system limit is not usable.  Use an architecture-specific
Packit 6c4009
       default.  */
Packit 6c4009
    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
Packit 6c4009
  else if (limit.rlim_cur < PTHREAD_STACK_MIN)
Packit 6c4009
    /* The system limit is unusably small.
Packit 6c4009
       Use the minimal size acceptable.  */
Packit 6c4009
    limit.rlim_cur = PTHREAD_STACK_MIN;
Packit 6c4009
Packit 6c4009
  /* Make sure it meets the minimum size that allocate_stack
Packit 6c4009
     (allocatestack.c) will demand, which depends on the page size.  */
Packit 6c4009
  const uintptr_t pagesz = GLRO(dl_pagesize);
Packit 6c4009
  const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
Packit 6c4009
  if (limit.rlim_cur < minstack)
Packit 6c4009
    limit.rlim_cur = minstack;
Packit 6c4009
Packit 6c4009
  /* Round the resource limit up to page size.  */
Packit 6c4009
  limit.rlim_cur = ALIGN_UP (limit.rlim_cur, pagesz);
Packit 6c4009
  lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
Packit 6c4009
  __default_pthread_attr.stacksize = limit.rlim_cur;
Packit 6c4009
  __default_pthread_attr.guardsize = GLRO (dl_pagesize);
Packit 6c4009
  lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* Make __rtld_lock_{,un}lock_recursive use pthread_mutex_{,un}lock,
Packit 6c4009
     keep the lock count from the ld.so implementation.  */
Packit 6c4009
  GL(dl_rtld_lock_recursive) = (void *) __pthread_mutex_lock;
Packit 6c4009
  GL(dl_rtld_unlock_recursive) = (void *) __pthread_mutex_unlock;
Packit 6c4009
  unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count;
Packit 6c4009
  GL(dl_load_lock).mutex.__data.__count = 0;
Packit 6c4009
  while (rtld_lock_count-- > 0)
Packit 6c4009
    __pthread_mutex_lock (&GL(dl_load_lock).mutex);
Packit 6c4009
Packit 6c4009
  GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  GL(dl_init_static_tls) = &__pthread_init_static_tls;
Packit 6c4009
Packit 6c4009
  GL(dl_wait_lookup_done) = &__wait_lookup_done;
Packit 6c4009
Packit 6c4009
  /* Register the fork generation counter with the libc.  */
Packit 6c4009
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
Packit 6c4009
  __libc_multiple_threads_ptr =
Packit 6c4009
#endif
Packit 6c4009
    __libc_pthread_init (&__fork_generation, __reclaim_stacks,
Packit 6c4009
			 ptr_pthread_functions);
Packit 6c4009
Packit 6c4009
  /* Determine whether the machine is SMP or not.  */
Packit 6c4009
  __is_smp = is_smp_system ();
Packit 6c4009
}
Packit 6c4009
strong_alias (__pthread_initialize_minimal_internal,
Packit 6c4009
	      __pthread_initialize_minimal)
Packit 6c4009
Packit 6c4009
Packit 6c4009
size_t
Packit 6c4009
__pthread_get_minstack (const pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  return GLRO(dl_pagesize) + __static_tls_size + PTHREAD_STACK_MIN;
Packit 6c4009
}