/* Linuxthreads - a simple clone()-based implementation of Posix */
/* threads for Linux. */
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
/* */
/* This program is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Library General Public License */
/* as published by the Free Software Foundation; either version 2 */
/* of the License, or (at your option) any later version. */
/* */
/* This program 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 Library General Public License for more details. */
/* Thread creation, initialization, and basic low-level routines */
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <shlib-compat.h>
#include "pthread.h"
#include "internals.h"
#include "spinlock.h"
#include "restart.h"
#include "smp.h"
#include <ldsodefs.h>
#include <tls.h>
#include <version.h>
#include <not-cancel.h>
/* Sanity check. */
#if !defined __SIGRTMIN || (__SIGRTMAX - __SIGRTMIN) < 3
# error "This must not happen"
#endif
#if !(USE_TLS && HAVE___THREAD)
/* These variables are used by the setup code. */
extern int _errno;
extern int _h_errno;
/* We need the global/static resolver state here. */
# include <resolv.h>
# undef _res
extern struct __res_state _res;
#endif
#ifdef USE_TLS
/* We need only a few variables. */
#define manager_thread __pthread_manager_threadp
pthread_descr __pthread_manager_threadp attribute_hidden;
#else
/* Descriptor of the initial thread */
struct _pthread_descr_struct __pthread_initial_thread = {
.p_header.data.self = &__pthread_initial_thread,
.p_nextlive = &__pthread_initial_thread,
.p_prevlive = &__pthread_initial_thread,
.p_tid = PTHREAD_THREADS_MAX,
.p_lock = &__pthread_handles[0].h_lock,
.p_start_args = PTHREAD_START_ARGS_INITIALIZER(NULL),
#if !(USE_TLS && HAVE___THREAD)
.p_errnop = &_errno,
.p_h_errnop = &_h_errno,
.p_resp = &_res,
#endif
.p_userstack = 1,
.p_resume_count = __ATOMIC_INITIALIZER,
.p_alloca_cutoff = __MAX_ALLOCA_CUTOFF
};
/* Descriptor of the manager thread; none of this is used but the error
variables, the p_pid and p_priority fields,
and the address for identification. */
#define manager_thread (&__pthread_manager_thread)
struct _pthread_descr_struct __pthread_manager_thread = {
.p_header.data.self = &__pthread_manager_thread,
.p_header.data.multiple_threads = 1,
.p_lock = &__pthread_handles[1].h_lock,
.p_start_args = PTHREAD_START_ARGS_INITIALIZER(__pthread_manager),
#if !(USE_TLS && HAVE___THREAD)
.p_errnop = &__pthread_manager_thread.p_errno,
#endif
.p_nr = 1,
.p_resume_count = __ATOMIC_INITIALIZER,
.p_alloca_cutoff = PTHREAD_STACK_MIN / 4
};
#endif
/* Pointer to the main thread (the father of the thread manager thread) */
/* Originally, this is the initial thread, but this changes after fork() */
#ifdef USE_TLS
pthread_descr __pthread_main_thread;
#else
pthread_descr __pthread_main_thread = &__pthread_initial_thread;
#endif
/* Limit between the stack of the initial thread (above) and the
stacks of other threads (below). Aligned on a STACK_SIZE boundary. */
char *__pthread_initial_thread_bos;
/* File descriptor for sending requests to the thread manager. */
/* Initially -1, meaning that the thread manager is not running. */
int __pthread_manager_request = -1;
int __pthread_multiple_threads attribute_hidden;
/* Other end of the pipe for sending requests to the thread manager. */
int __pthread_manager_reader;
/* Limits of the thread manager stack */
char *__pthread_manager_thread_bos;
char *__pthread_manager_thread_tos;
/* For process-wide exit() */
int __pthread_exit_requested;
int __pthread_exit_code;
/* Maximum stack size. */
size_t __pthread_max_stacksize;
/* Nozero if the machine has more than one processor. */
int __pthread_smp_kernel;
#if !__ASSUME_REALTIME_SIGNALS
/* Pointers that select new or old suspend/resume functions
based on availability of rt signals. */
void (*__pthread_restart)(pthread_descr) = __pthread_restart_old;
void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old;
int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_old;
#endif /* __ASSUME_REALTIME_SIGNALS */
/* Communicate relevant LinuxThreads constants to gdb */
const int __pthread_threads_max = PTHREAD_THREADS_MAX;
const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct);
const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct,
h_descr);
const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct,
p_pid);
const int __linuxthreads_pthread_sizeof_descr
= sizeof(struct _pthread_descr_struct);
const int __linuxthreads_initial_report_events;
const char __linuxthreads_version[] = VERSION;
/* Forward declarations */
static void pthread_onexit_process(int retcode, void *arg);
#ifndef HAVE_Z_NODELETE
static void pthread_atexit_process(void *arg, int retcode);
static void pthread_atexit_retcode(void *arg, int retcode);
#endif
static void pthread_handle_sigcancel(int sig);
static void pthread_handle_sigrestart(int sig);
static void pthread_handle_sigdebug(int sig);
/* Signal numbers used for the communication.
In these variables we keep track of the used variables. If the
platform does not support any real-time signals we will define the
values to some unreasonable value which will signal failing of all
the functions below. */
int __pthread_sig_restart = __SIGRTMIN;
int __pthread_sig_cancel = __SIGRTMIN + 1;
int __pthread_sig_debug = __SIGRTMIN + 2;
extern int __libc_current_sigrtmin_private (void);
#if !__ASSUME_REALTIME_SIGNALS
static int rtsigs_initialized;
static void
init_rtsigs (void)
{
if (rtsigs_initialized)
return;
if (__libc_current_sigrtmin_private () == -1)
{
__pthread_sig_restart = SIGUSR1;
__pthread_sig_cancel = SIGUSR2;
__pthread_sig_debug = 0;
}
else
{
__pthread_restart = __pthread_restart_new;
__pthread_suspend = __pthread_wait_for_restart_signal;
__pthread_timedsuspend = __pthread_timedsuspend_new;
}
rtsigs_initialized = 1;
}
#endif
/* Initialize the pthread library.
Initialization is split in two functions:
- a constructor function that blocks the __pthread_sig_restart signal
(must do this very early, since the program could capture the signal
mask with e.g. sigsetjmp before creating the first thread);
- a regular function called from pthread_create when needed. */
static void pthread_initialize(void) __attribute__((constructor));
#ifndef HAVE_Z_NODELETE
extern void *__dso_handle __attribute__ ((weak));
#endif
#if defined USE_TLS && !defined SHARED
extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
#endif
struct pthread_functions __pthread_functions =
{
#if !(USE_TLS && HAVE___THREAD)
.ptr_pthread_internal_tsd_set = __pthread_internal_tsd_set,
.ptr_pthread_internal_tsd_get = __pthread_internal_tsd_get,
.ptr_pthread_internal_tsd_address = __pthread_internal_tsd_address,
#endif
.ptr_pthread_fork = __pthread_fork,
.ptr_pthread_attr_destroy = __pthread_attr_destroy,
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
.ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0,
#endif
.ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1,
.ptr_pthread_a