aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/init.c')
-rw-r--r--nptl/init.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/nptl/init.c b/nptl/init.c
new file mode 100644
index 0000000000..395ede7033
--- /dev/null
+++ b/nptl/init.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#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>
+
+
+/* XXX For the time being... */
+#define __NR_set_tid_address 258
+
+
+/* Default stack size. */
+size_t __default_stacksize attribute_hidden;
+
+/* Size and alignment of static TLS block. */
+size_t __static_tls_size;
+size_t __static_tls_align;
+
+/* Version of the library, used in libthread_db to detect mismatches. */
+static const char nptl_version[] = VERSION;
+
+
+#if defined USE_TLS && !defined SHARED
+extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
+#endif
+
+
+/* For asynchronous cancellation we use a signal. This is the handler. */
+static void
+sigcancel_handler (int sig __attribute ((unused)))
+{
+ struct pthread *self = THREAD_SELF;
+
+ 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 oldval = THREAD_GETMEM (self, cancelhandling);
+ int newval = oldval | CANCELED_BITMASK;
+
+ if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
+ /* Already canceled or exiting. */
+ break;
+
+ if (atomic_compare_and_exchange_acq (&self->cancelhandling, newval,
+ oldval) == 0)
+ {
+ /* Set the return value. */
+ THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+
+ /* Make sure asynchronous cancellation is still enabled. */
+ if ((newval & CANCELTYPE_BITMASK) != 0)
+ {
+ /* The thread is exiting now. */
+ atomic_bit_set (&self->cancelhandling, EXITING_BIT);
+
+ /* Run the registered destructors and terminate the
+ thread. */
+ __do_cancel (CURRENT_STACK_FRAME);
+ }
+
+ break;
+ }
+ }
+}
+
+
+
+void
+#ifdef SHARED
+__attribute ((constructor))
+#endif
+__pthread_initialize_minimal (void)
+{
+ struct sigaction sa;
+ struct rlimit limit;
+#ifdef USE_TLS
+ struct pthread *pd;
+#endif
+
+#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);
+#endif
+
+ /* Minimal initialization of the thread descriptor. */
+ pd = THREAD_SELF;
+ pd->tid = INTERNAL_SYSCALL (set_tid_address, 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
+
+ /* Add the main thread to the list of all running threads. No need
+ to get the lock we are alone so far. */
+ list_add (&pd->header.data.list, &__stack_user);
+
+
+ /* 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. */
+ sa.sa_handler = sigcancel_handler;
+ sa.sa_flags = 0;
+
+ /* Avoid another cancellation signal when we process one. */
+ sigemptyset (&sa.sa_mask);
+ sigaddset (&sa.sa_mask, SIGCANCEL);
+
+ (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
+
+
+ /* Determine the default allowed stack size. This is the size used
+ in case the user does not specify one. */
+ 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;
+
+#ifdef NEED_SEPARATE_REGISTER_STACK
+ __default_stacksize = MAX (limit.rlim_cur / 2, PTHREAD_STACK_MIN);
+#else
+ __default_stacksize = MAX (limit.rlim_cur, PTHREAD_STACK_MIN);
+#endif
+ /* The maximum page size better should be a multiple of the page
+ size. */
+ assert (__default_stacksize % __sysconf (_SC_PAGESIZE) == 0);
+
+ /* Get the size of the static and alignment requirements for the TLS
+ block. */
+ _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_size = roundup (__static_tls_size, __static_tls_align);
+
+ /* Register the fork generation counter with the libc. */
+ __register_pthread_fork_handler (&__fork_generation, __reclaim_stacks);
+}