about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2002-02-23 08:47:54 +0000
committerUlrich Drepper <drepper@redhat.com>2002-02-23 08:47:54 +0000
commit557fab43bd3cf75f87ba7efb65c9f4884e261a6c (patch)
treea45a8e10024f1cd566da25113e7dc2f45b8bd9e3
parente413826144bcd0a910e8a6f942ec34a368f65613 (diff)
downloadglibc-557fab43bd3cf75f87ba7efb65c9f4884e261a6c.tar.gz
glibc-557fab43bd3cf75f87ba7efb65c9f4884e261a6c.tar.xz
glibc-557fab43bd3cf75f87ba7efb65c9f4884e261a6c.zip
Update.
2002-02-23  Ulrich Drepper  <drepper@redhat.com>

	* csu/set-init.c: Moved to...
	* sysdeps/mach/hurd/set-init.c: ...here.  New file.
	* csu/Makefile: Don't compile set-init.
	* sysdeps/mach/hurd/Makefile: Compile set-init for subdir csu.
	* sysdeps/mach/hurd/i386/init-first.c: Call __init_misc in addition
	to __libc_init.
	* sysdeps/mach/hurd/mips/init-first.c: Likewise.
	* sysdeps/mach/hurd/powerpc/init-first.c: Likewise.
	* sysdeps/unix/sysv/linux/init-first.c: Call __init_misc instead of
	__libc_init.
	* misc/init-misc.c: Always export __init_misc.  Don't define hooks for
	__libc_subinit.
-rw-r--r--ChangeLog15
-rw-r--r--csu/Makefile4
-rw-r--r--linuxthreads/ChangeLog13
-rw-r--r--linuxthreads/descr.h7
-rw-r--r--linuxthreads/internals.h1
-rw-r--r--linuxthreads/manager.c130
-rw-r--r--linuxthreads/pthread.c157
-rw-r--r--linuxthreads/sysdeps/i386/tls.h18
-rw-r--r--misc/init-misc.c16
-rw-r--r--sysdeps/mach/hurd/Makefile1
-rw-r--r--sysdeps/mach/hurd/i386/init-first.c2
-rw-r--r--sysdeps/mach/hurd/mips/init-first.c4
-rw-r--r--sysdeps/mach/hurd/powerpc/init-first.c4
-rw-r--r--sysdeps/mach/hurd/set-init.c (renamed from csu/set-init.c)0
-rw-r--r--sysdeps/unix/sysv/linux/init-first.c4
15 files changed, 291 insertions, 85 deletions
diff --git a/ChangeLog b/ChangeLog
index 41d839c8b4..dbe013ef48 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2002-02-23  Ulrich Drepper  <drepper@redhat.com>
+
+	* csu/set-init.c: Moved to...
+	* sysdeps/mach/hurd/set-init.c: ...here.  New file.
+	* csu/Makefile: Don't compile set-init.
+	* sysdeps/mach/hurd/Makefile: Compile set-init for subdir csu.
+	* sysdeps/mach/hurd/i386/init-first.c: Call __init_misc in addition
+	to __libc_init.
+	* sysdeps/mach/hurd/mips/init-first.c: Likewise.
+	* sysdeps/mach/hurd/powerpc/init-first.c: Likewise.
+	* sysdeps/unix/sysv/linux/init-first.c: Call __init_misc instead of
+	__libc_init.
+	* misc/init-misc.c: Always export __init_misc.  Don't define hooks for
+	__libc_subinit.
+
 2002-02-22  Ulrich Drepper  <drepper@redhat.com>
 
 	* elf/Versions: Add _dl_allocate_tls and _dl_deallocate_tls.
diff --git a/csu/Makefile b/csu/Makefile
index 012cbbe209..994e2b29de 100644
--- a/csu/Makefile
+++ b/csu/Makefile
@@ -59,9 +59,7 @@ before-compile += $(objpfx)abi-tag.h
 generated += abi-tag.h
 endif
 
-ifeq (yes,$(gnu-ld))
-libc-init = set-init
-else
+ifneq (yes,$(gnu-ld))
 libc-init = munch-init
 $(objpfx)munch-init.c: munch.awk munch-tmpl.c $(+subdir_inits)
 	$(AWK) -f $< subdirs='$(+init_subdirs)' $(word 2,$^) > $@-t
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 762b29e2c7..2fc0a623d1 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,16 @@
+2002-02-23  Ulrich Drepper  <drepper@redhat.com>
+
+	* descr.h (struct _pthread_descr_struct): Update p_header for TLS.
+	Add p_stackaddr element #if USE_TLS.
+	* internals.c: Include <tls.h>.
+	* manager.c: Integrate creating and handling of thread descriptor
+	for TLS.
+	* pthread.c: Likewise.
+	* sysdeps/i386/tls.h (tcbhead_t): Add self pointer.
+	Include <linuxthreads/descr.h> only if TLS is really used.
+	(GET_DTV): New macro.
+	(TLS_INIT_TP): Initialize self pointer.
+
 2002-02-17  Andreas Schwab  <schwab@suse.de>
 
 	* signals.c (sigwait): Check for old sighandler being SIG_ERR,
diff --git a/linuxthreads/descr.h b/linuxthreads/descr.h
index a2cddb1212..d0c31da9b2 100644
--- a/linuxthreads/descr.h
+++ b/linuxthreads/descr.h
@@ -102,8 +102,10 @@ struct _pthread_descr_struct {
   /* XXX Remove this union for IA-64 style TLS module */
   union {
     struct {
-      pthread_descr self;	/* Pointer to this structure */
+      void *tcb;		/* Pointer to the TCB.  This is not always
+				   the address of this thread descriptor.  */
       union dtv *dtvp;
+      pthread_descr self;	/* Pointer to this structure */
     } data;
     void *__padding[16];
   } p_header;
@@ -158,6 +160,9 @@ struct _pthread_descr_struct {
 #if HP_TIMING_AVAIL
   hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread.  */
 #endif
+#ifdef USE_TLS
+  char *p_stackaddr;		/* Stack address.  */
+#endif
   /* New elements must be added at the end.  */
 } __attribute__ ((aligned(32))); /* We need to align the structure so that
 				    doubles are aligned properly.  This is 8
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index 056e36d885..209812c3da 100644
--- a/linuxthreads/internals.h
+++ b/linuxthreads/internals.h
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <stackinfo.h>
 
+#include <tls.h>
 #include "descr.h"
 
 extern long int testandset (int *spinlock);
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index 9e4fcacb48..efbbf51b41 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -14,6 +14,7 @@
 
 /* The "thread manager" thread: manages creation and termination of threads */
 
+#include <assert.h>
 #include <errno.h>
 #include <sched.h>
 #include <stddef.h>
@@ -27,6 +28,7 @@
 #include <sys/time.h>
 #include <sys/wait.h>           /* for waitpid macros */
 
+#include <ldsodefs.h>
 #include "pthread.h"
 #include "internals.h"
 #include "spinlock.h"
@@ -34,9 +36,23 @@
 #include "semaphore.h"
 
 /* Array of active threads. Entry 0 is reserved for the initial thread. */
-struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
-{ { __LOCK_INITIALIZER, &__pthread_initial_thread, 0},
-  { __LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ };
+struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]
+#ifdef USE_TLS
+# if __LT_SPINLOCK_INIT != 0
+= {
+  { __LOCK_INITIALIZER, NULL, 0},
+  { __LOCK_INITIALIZER, NULL, 0},
+  /* All NULLs */
+}
+# endif
+#else
+= {
+  { __LOCK_INITIALIZER, &__pthread_initial_thread, 0},
+  { __LOCK_INITIALIZER, &__pthread_manager_thread, 0},
+  /* All NULLs */
+}
+#endif
+;
 
 /* For debugging purposes put the maximum number of threads in a variable.  */
 const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX;
@@ -60,6 +76,8 @@ volatile td_thr_events_t __pthread_threads_events;
 /* Pointer to thread descriptor with last event.  */
 volatile pthread_descr __pthread_last_event;
 
+static pthread_descr manager_thread;
+
 /* Mapping from stack segment to thread descriptor. */
 /* Stack segment numbers are also indices into the __pthread_handles array. */
 /* Stack segment number 0 is reserved for the initial thread. */
@@ -100,7 +118,7 @@ static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
      __attribute__ ((noreturn));
 static void pthread_reap_children(void);
 static void pthread_kill_all_threads(int sig, int main_thread_also);
-static void pthread_for_each_thread(void *arg, 
+static void pthread_for_each_thread(void *arg,
     void (*fn)(void *, pthread_descr));
 
 /* The server thread managing requests for thread creation and termination */
@@ -109,7 +127,8 @@ int
 __attribute__ ((noreturn))
 __pthread_manager(void *arg)
 {
-  int reqfd = (int) (long int) arg;
+  pthread_descr self = manager_thread = arg;
+  int reqfd = __pthread_manager_reader;
   struct pollfd ufd;
   sigset_t manager_mask;
   int n;
@@ -117,11 +136,11 @@ __pthread_manager(void *arg)
 
   /* If we have special thread_self processing, initialize it.  */
 #ifdef INIT_THREAD_SELF
-  INIT_THREAD_SELF(&__pthread_manager_thread, 1);
+  INIT_THREAD_SELF(self, 1);
 #endif
   /* Set the error variable.  */
-  __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno;
-  __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;
+  self->p_errnop = &self->p_errno;
+  self->p_h_errnop = &self->p_h_errno;
   /* Block all signals except __pthread_sig_cancel and SIGTRAP */
   sigfillset(&manager_mask);
   sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */
@@ -227,13 +246,13 @@ int __pthread_manager_event(void *arg)
 {
   /* If we have special thread_self processing, initialize it.  */
 #ifdef INIT_THREAD_SELF
-  INIT_THREAD_SELF(&__pthread_manager_thread, 1);
+  INIT_THREAD_SELF(arg, 1);
 #endif
 
   /* Get the lock the manager will free once all is correctly set up.  */
-  __pthread_lock (THREAD_GETMEM((&__pthread_manager_thread), p_lock), NULL);
+  __pthread_lock (THREAD_GETMEM(((pthread_descr) arg), p_lock), NULL);
   /* Free it immediately.  */
-  __pthread_unlock (THREAD_GETMEM((&__pthread_manager_thread), p_lock));
+  __pthread_unlock (THREAD_GETMEM(((pthread_descr) arg), p_lock));
 
   return __pthread_manager(arg);
 }
@@ -270,7 +289,7 @@ pthread_start_thread(void *arg)
     __sched_setscheduler(THREAD_GETMEM(self, p_pid),
 			 THREAD_GETMEM(self, p_start_args.schedpolicy),
                          &self->p_start_args.schedparam);
-  else if (__pthread_manager_thread.p_priority > 0)
+  else if (manager_thread->p_priority > 0)
     /* Default scheduling required, but thread manager runs in realtime
        scheduling: switch new thread to SCHED_OTHER policy */
     {
@@ -315,10 +334,14 @@ pthread_start_thread_event(void *arg)
   pthread_start_thread (arg);
 }
 
+#if defined USE_TLS && !FLOATING_STACKS
+# error "TLS can only work with floating stacks"
+#endif
+
 static int pthread_allocate_stack(const pthread_attr_t *attr,
                                   pthread_descr default_new_thread,
                                   int pagesize,
-                                  pthread_descr * out_new_thread,
+                                  char ** out_new_thread,
                                   char ** out_new_thread_bottom,
                                   char ** out_guardaddr,
                                   size_t * out_guardsize)
@@ -328,12 +351,23 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
   char * guardaddr;
   size_t stacksize, guardsize;
 
+#ifdef USE_TLS
+  /* TLS cannot work with fixed thread descriptor addresses.  */
+  assert (default_new_thread == NULL);
+#endif
+
   if (attr != NULL && attr->__stackaddr_set)
     {
 #ifdef _STACK_GROWS_UP
       /* The user provided a stack. */
+# ifdef USE_TLS
+      /* This value is not needed.  */
+      new_thread = (pthread_descr) attr->__stackaddr;
+      new_thread_bottom = (char *) new_thread;
+# else
       new_thread = (pthread_descr) attr->__stackaddr;
       new_thread_bottom = (char *) (new_thread + 1);
+# endif
       guardaddr = attr->__stackaddr + attr->__stacksize;
       guardsize = 0;
 #else
@@ -347,8 +381,12 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
 	 addresses, stackaddr would be the lowest address in the stack
 	 segment, so that it is consistently close to the initial sp
 	 value. */
+# ifdef USE_TLS
+      new_thread = (pthread_descr) attr->__stackaddr;
+# else
       new_thread =
         (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;
+# endif
       new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;
       guardaddr = new_thread_bottom;
       guardsize = 0;
@@ -356,16 +394,18 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
 #ifndef THREAD_SELF
       __pthread_nonstandard_stacks = 1;
 #endif
+#ifndef USE_TLS
       /* Clear the thread data structure.  */
       memset (new_thread, '\0', sizeof (*new_thread));
+#endif
     }
   else
     {
 #ifdef NEED_SEPARATE_REGISTER_STACK
-      size_t granularity = 2 * pagesize;
+      const size_t granularity = 2 * pagesize;
       /* Try to make stacksize/2 a multiple of pagesize */
 #else
-      size_t granularity = pagesize;
+      const size_t granularity = pagesize;
 #endif
       void *map_addr;
 
@@ -397,22 +437,35 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
 	mprotect (guardaddr, guardsize, PROT_NONE);
 
       new_thread_bottom = (char *) map_addr;
+#  ifdef USE_TLS
+      new_thread = ((pthread_descr) (new_thread_bottom + stacksize
+				     + guardsize));
+#  else
       new_thread = ((pthread_descr) (new_thread_bottom + stacksize
 				     + guardsize)) - 1;
+#  endif
 # elif _STACK_GROWS_DOWN
       guardaddr = map_addr;
       if (guardsize > 0)
 	mprotect (guardaddr, guardsize, PROT_NONE);
 
       new_thread_bottom = (char *) map_addr + guardsize;
+#  ifdef USE_TLS
+      new_thread = ((pthread_descr) (new_thread_bottom + stacksize));
+#  else
       new_thread = ((pthread_descr) (new_thread_bottom + stacksize)) - 1;
+#  endif
 # elif _STACK_GROWS_UP
       guardaddr = map_addr + stacksize;
       if (guardsize > 0)
 	mprotect (guardaddr, guardsize, PROT_NONE);
 
       new_thread = (pthread_descr) map_addr;
+#  ifdef USE_TLS
+      new_thread_bottom = (char *) new_thread;
+#  else
       new_thread_bottom = (char *) (new_thread + 1);
+#  endif
 # else
 #  error You must define a stack direction
 # endif /* Stack direction */
@@ -512,7 +565,7 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
 # endif  /* !NEED_SEPARATE_REGISTER_STACK */
 #endif   /* !FLOATING_STACKS */
     }
-  *out_new_thread = new_thread;
+  *out_new_thread = (char *) new_thread;
   *out_new_thread_bottom = new_thread_bottom;
   *out_guardaddr = guardaddr;
   *out_guardsize = guardsize;
@@ -528,12 +581,19 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   size_t sseg;
   int pid;
   pthread_descr new_thread;
+  char *stack_addr;
   char * new_thread_bottom;
   pthread_t new_thread_id;
   char *guardaddr = NULL;
   size_t guardsize = 0;
   int pagesize = __getpagesize();
-  int saved_errno;
+  int saved_errno = 0;
+
+#ifdef USE_TLS
+  new_thread = _dl_allocate_tls ();
+  if (new_thread == NULL)
+    return EAGAIN;
+#endif
 
   /* First check whether we have to change the policy and if yes, whether
      we can  do this.  Normally this should be done by examining the
@@ -549,10 +609,16 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
       if (__pthread_handles[sseg].h_descr != NULL)
 	continue;
       if (pthread_allocate_stack(attr, thread_segment(sseg),
-				 pagesize,
-                                 &new_thread, &new_thread_bottom,
+				 pagesize, &stack_addr, &new_thread_bottom,
                                  &guardaddr, &guardsize) == 0)
-        break;
+	{
+#ifdef USE_TLS
+	  new_thread->p_stackaddr = stack_addr;
+#else
+	  new_thread = (pthread_descr) stack_addr;
+#endif
+	  break;
+	}
     }
   __pthread_handles_num++;
   /* Allocate new thread identifier */
@@ -768,20 +834,32 @@ static void pthread_free(pthread_descr th)
       /* Free the stack and thread descriptor area */
       char *guardaddr = th->p_guardaddr;
 #ifdef _STACK_GROWS_UP
+# ifdef USE_TLS
+      size_t stacksize = guardaddr - th->p_stackaddr;
+# else
       size_t stacksize = guardaddr - (char *)th;
+# endif
       guardaddr = (char *)th;
 #else
       /* Guardaddr is always set, even if guardsize is 0.  This allows
 	 us to compute everything else.  */
+# ifdef USE_TLS
+      size_t stacksize = th->p_stackaddr - guardaddr - guardsize;
+# else
       size_t stacksize = (char *)(th+1) - guardaddr - guardsize;
-#ifdef NEED_SEPARATE_REGISTER_STACK
+# endif
+# ifdef NEED_SEPARATE_REGISTER_STACK
       /* Take account of the register stack, which is below guardaddr.  */
       guardaddr -= stacksize;
       stacksize *= 2;
-#endif
+# endif
 #endif
       /* Unmap the stack.  */
       munmap(guardaddr, stacksize + guardsize);
+
+#ifdef USE_TLS
+      _dl_deallocate_tls (th);
+#endif
     }
 }
 
@@ -896,7 +974,7 @@ static void pthread_kill_all_threads(int sig, int main_thread_also)
   }
 }
 
-static void pthread_for_each_thread(void *arg, 
+static void pthread_for_each_thread(void *arg,
     void (*fn)(void *, pthread_descr))
 {
   pthread_descr th;
@@ -974,10 +1052,10 @@ void __pthread_manager_adjust_prio(int thread_prio)
 {
   struct sched_param param;
 
-  if (thread_prio <= __pthread_manager_thread.p_priority) return;
+  if (thread_prio <= manager_thread->p_priority) return;
   param.sched_priority =
     thread_prio < __sched_get_priority_max(SCHED_FIFO)
     ? thread_prio + 1 : thread_prio;
-  __sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, &param);
-  __pthread_manager_thread.p_priority = thread_prio;
+  __sched_setscheduler(manager_thread->p_pid, SCHED_FIFO, &param);
+  manager_thread->p_priority = thread_prio;
 }
diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c
index 2901d9c24f..314360d477 100644
--- a/linuxthreads/pthread.c
+++ b/linuxthreads/pthread.c
@@ -31,6 +31,7 @@
 #include "spinlock.h"
 #include "restart.h"
 #include <ldsodefs.h>
+#include <tls.h>
 
 /* We need the global/static resolver state here.  */
 #include <resolv.h>
@@ -47,12 +48,18 @@ extern struct __res_state _res;
 extern int _errno;
 extern int _h_errno;
 
+#ifdef USE_TLS
+
+/* We need only a few variables.  */
+static pthread_descr manager_thread;
+
+#else
 /* Descriptor of the initial thread */
 
 struct _pthread_descr_struct __pthread_initial_thread = {
   {
     {
-      &__pthread_initial_thread /* pthread_descr self */
+      .self = &__pthread_initial_thread /* pthread_descr self */
     }
   },
   &__pthread_initial_thread,  /* pthread_descr p_nextlive */
@@ -106,10 +113,11 @@ struct _pthread_descr_struct __pthread_initial_thread = {
    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 = {
   {
     {
-      &__pthread_manager_thread /* pthread_descr self */
+      .self = &__pthread_manager_thread /* pthread_descr self */
     }
   },
   NULL,                       /* pthread_descr p_nextlive */
@@ -158,11 +166,16 @@ struct _pthread_descr_struct __pthread_manager_thread = {
   NULL,                       /* pthread_readlock_info *p_readlock_free; */
   0                           /* int p_untracked_readlock_count; */
 };
+#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. */
@@ -386,13 +399,44 @@ extern void *__dso_handle __attribute__ ((weak));
 void
 __pthread_initialize_minimal(void)
 {
+#ifdef USE_TLS
+  pthread_descr self = THREAD_SELF;
+
+  /* The memory for the thread descriptor was allocated elsewhere as
+     part of the TLS allocation.  We have to initialize the data
+     structure by hand.  This initialization must mirror the struct
+     definition above.  */
+  self->p_header.data.self = self;
+  self->p_nextlive = self->p_prevlive = self;
+  self->p_tid = PTHREAD_THREADS_MAX;
+  self->p_lock = &__pthread_handles[0].h_lock;
+  self->p_errnop = &_errno;
+  self->p_h_errnop = &_h_errno;
+  /* self->p_start_args need not be initialized, it's all zero.  */
+  self->p_userstack = 1;
+# if __LT_SPINLOCK_INIT != 0
+  self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER;
+# endif
+
+  /* Another variable which points to the thread descriptor.  */
+  __pthread_main_thread = self;
+
+  /* And fill in the pointer the the thread __pthread_handles array.  */
+  __pthread_handles[0].h_descr = self;
+#else
   /* If we have special thread_self processing, initialize that for the
      main thread now.  */
-#ifdef INIT_THREAD_SELF
+# ifdef INIT_THREAD_SELF
   INIT_THREAD_SELF(&__pthread_initial_thread, 0);
+# endif
 #endif
+
 #if HP_TIMING_AVAIL
+# ifdef USE_TLS
+  self->p_cpuclock_offset = GL(dl_cpuclock_offset);
+# else
   __pthread_initial_thread.p_cpuclock_offset = GL(dl_cpuclock_offset);
+# endif
 #endif
 }
 
@@ -461,10 +505,17 @@ static void pthread_initialize(void)
     (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
 # endif
 #endif
+#ifdef USE_TLS
+  /* Update the descriptor for the initial thread. */
+  THREAD_SETMEM (((pthread_descr) NULL), p_pid, __getpid());
+  /* Likewise for the resolver state _res.  */
+  THREAD_SETMEM (((pthread_descr) NULL), p_resp, &_res);
+#else
   /* Update the descriptor for the initial thread. */
   __pthread_initial_thread.p_pid = __getpid();
   /* Likewise for the resolver state _res.  */
   __pthread_initial_thread.p_resp = &_res;
+#endif
 #ifdef __SIGRTMIN
   /* Initialize real-time signals. */
   init_rtsigs ();
@@ -513,6 +564,8 @@ int __pthread_initialize_manager(void)
   int manager_pipe[2];
   int pid;
   struct pthread_request request;
+  int report_events;
+  pthread_descr tcb;
 
 #ifndef HAVE_Z_NODELETE
   if (__builtin_expect (&__dso_handle != NULL, 1))
@@ -535,37 +588,76 @@ int __pthread_initialize_manager(void)
     free(__pthread_manager_thread_bos);
     return -1;
   }
+
+#ifdef USE_TLS
+  /* Allocate memory for the thread descriptor and the dtv.  */
+  manager_thread = tcb = _dl_allocate_tls ();
+  if (tcb == NULL) {
+    free(__pthread_manager_thread_bos);
+    __libc_close(manager_pipe[0]);
+    __libc_close(manager_pipe[1]);
+    return -1;
+  }
+
+  /* Initialize the descriptor.  */
+  tcb->p_header.data.self = tcb;
+  tcb->p_lock = &__pthread_handles[1].h_lock;
+  tcb->p_errnop = &tcb->p_errno;
+  tcb->p_start_args = (struct pthread_start_args) PTHREAD_START_ARGS_INITIALIZER(__pthread_manager);
+  tcb->p_nr = 1;
+# if __LT_SPINLOCK_INIT != 0
+  self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER;
+# endif
+#else
+  tcb = &__pthread_manager_thread;
+#endif
+
+  __pthread_manager_request = manager_pipe[1]; /* writing end */
+  __pthread_manager_reader = manager_pipe[0]; /* reading end */
+
   /* Start the thread manager */
   pid = 0;
-  if (__builtin_expect (__pthread_initial_thread.p_report_events, 0))
+#ifdef USE_TLS
+  report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events);
+#else
+  report_events = __pthread_initial_thread.p_report_events;
+#endif
+  if (__builtin_expect (report_events, 0))
     {
       /* It's a bit more complicated.  We have to report the creation of
 	 the manager thread.  */
       int idx = __td_eventword (TD_CREATE);
       uint32_t mask = __td_eventmask (TD_CREATE);
+      uint32_t event_bits;
 
-      if ((mask & (__pthread_threads_events.event_bits[idx]
-		   | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx]))
+#ifdef USE_TLS
+      event_bits = THREAD_GETMEM_NC (((pthread_descr) NULL),
+				     p_eventbuf.eventmask.event_bits[idx]);
+#else
+      event_bits = __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx];
+#endif
+
+      if ((mask & (__pthread_threads_events.event_bits[idx] | event_bits))
 	  != 0)
 	{
-	  __pthread_lock(__pthread_manager_thread.p_lock, NULL);
+	  __pthread_lock(tcb->p_lock, NULL);
 
 #ifdef NEED_SEPARATE_REGISTER_STACK
 	  pid = __clone2(__pthread_manager_event,
 			 (void **) __pthread_manager_thread_bos,
 			 THREAD_MANAGER_STACK_SIZE,
 			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-			 (void *)(long)manager_pipe[0]);
+			 tcb);
 #elif _STACK_GROWS_UP
 	  pid = __clone(__pthread_manager_event,
 			(void **) __pthread_manager_thread_bos,
 			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-			(void *)(long)manager_pipe[0]);
+			tcb);
 #else
 	  pid = __clone(__pthread_manager_event,
 			(void **) __pthread_manager_thread_tos,
 			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-			(void *)(long)manager_pipe[0]);
+			tcb);
 #endif
 
 	  if (pid != -1)
@@ -574,19 +666,18 @@ int __pthread_initialize_manager(void)
 	         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.  */
-	      __pthread_manager_thread.p_eventbuf.eventdata =
-		&__pthread_manager_thread;
-	      __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE;
-	      __pthread_last_event = &__pthread_manager_thread;
-	      __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
-	      __pthread_manager_thread.p_pid = pid;
+	      tcb->p_eventbuf.eventdata = tcb;
+	      tcb->p_eventbuf.eventnum = TD_CREATE;
+	      __pthread_last_event = tcb;
+	      tcb->p_tid = 2* PTHREAD_THREADS_MAX + 1;
+	      tcb->p_pid = pid;
 
 	      /* Now call the function which signals the event.  */
 	      __linuxthreads_create_event ();
 	    }
 
 	  /* Now restart the thread.  */
-	  __pthread_unlock(__pthread_manager_thread.p_lock);
+	  __pthread_unlock(tcb->p_lock);
 	}
     }
 
@@ -595,16 +686,13 @@ int __pthread_initialize_manager(void)
 #ifdef NEED_SEPARATE_REGISTER_STACK
       pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos,
 		     THREAD_MANAGER_STACK_SIZE,
-		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-		     (void *)(long)manager_pipe[0]);
+		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb);
 #elif _STACK_GROWS_UP
       pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-		    (void *)(long)manager_pipe[0]);
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb);
 #else
       pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
-		    (void *)(long)manager_pipe[0]);
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, tcb);
 #endif
     }
   if (__builtin_expect (pid, 0) == -1) {
@@ -613,10 +701,8 @@ int __pthread_initialize_manager(void)
     __libc_close(manager_pipe[1]);
     return -1;
   }
-  __pthread_manager_request = manager_pipe[1]; /* writing end */
-  __pthread_manager_reader = manager_pipe[0]; /* reading end */
-  __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
-  __pthread_manager_thread.p_pid = pid;
+  tcb->p_tid = 2* PTHREAD_THREADS_MAX + 1;
+  tcb->p_pid = pid;
   /* Make gdb aware of new thread manager */
   if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0)
     {
@@ -725,7 +811,7 @@ static pthread_descr thread_self_stack(void)
   pthread_handle h;
 
   if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos)
-    return &__pthread_manager_thread;
+    return manager_thread;
   h = __pthread_handles + 2;
   while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom))
     h++;
@@ -805,7 +891,11 @@ static void pthread_onexit_process(int retcode, void *arg)
        children, so that timings for main thread account for all threads. */
     if (self == __pthread_main_thread)
       {
+#ifdef USE_TLS
+	waitpid(manager_thread->p_pid, NULL, __WCLONE);
+#else
 	waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+#endif
 	/* Since all threads have been asynchronously terminated
            (possibly holding locks), free cannot be used any more.  */
 	/*free (__pthread_manager_thread_bos);*/
@@ -850,7 +940,7 @@ static void pthread_handle_sigcancel(int sig)
   pthread_descr self = thread_self();
   sigjmp_buf * jmpbuf;
 
-  if (self == &__pthread_manager_thread)
+  if (self == manager_thread)
     {
 #ifdef THREAD_SELF
       /* A new thread might get a cancel signal before it is fully
@@ -858,7 +948,7 @@ static void pthread_handle_sigcancel(int sig)
 	 manager thread.  Double check that this is really the manager
 	 thread.  */
       pthread_descr real_self = thread_self_stack();
-      if (real_self == &__pthread_manager_thread)
+      if (real_self == manager_thread)
 	{
 	  __pthread_manager_sighandler(sig);
 	  return;
@@ -876,8 +966,13 @@ static void pthread_handle_sigcancel(int sig)
   if (__builtin_expect (__pthread_exit_requested, 0)) {
     /* Main thread should accumulate times for thread manager and its
        children, so that timings for main thread account for all threads. */
-    if (self == __pthread_main_thread)
+    if (self == __pthread_main_thread) {
+#ifdef USE_TLS
+      waitpid(manager_thread->p_pid, NULL, __WCLONE);
+#else
       waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+#endif
+    }
     _exit(__pthread_exit_code);
   }
   if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0)
diff --git a/linuxthreads/sysdeps/i386/tls.h b/linuxthreads/sysdeps/i386/tls.h
index 8e1d4698b0..d1975b2017 100644
--- a/linuxthreads/sysdeps/i386/tls.h
+++ b/linuxthreads/sysdeps/i386/tls.h
@@ -32,15 +32,13 @@ typedef union dtv
 
 typedef struct
 {
-  void *tcb;
+  void *tcb;		/* Pointer to the TCB.  Not necessary the
+			   thread descriptor used by libpthread.  */
   dtv_t *dtv;
+  void *self;		/* Pointer to the thread descriptor.  */
 } tcbhead_t;
 
 
-/* Get the thread descriptor definition.  */
-#include <linuxthreads/descr.h>
-
-
 /* We can support TLS only if the floating-stack support is available.  */
 #if defined FLOATING_STACKS && defined HAVE_TLS_SUPPORT
 
@@ -50,6 +48,10 @@ typedef struct
 /* Signal that TLS support is available.  */
 # define USE_TLS	1
 
+
+/* Get the thread descriptor definition.  */
+# include <linuxthreads/descr.h>
+
 /* This is the size of the initial TCB.  */
 # define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
 
@@ -77,6 +79,10 @@ typedef struct
   ({ struct _pthread_descr_struct *__descr;				      \
      THREAD_SETMEM (__descr, p_header.data.dtvp, dtv); })
 
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(descr) \
+  (((tcbhead_t *) descr)->dtv)
+
 /* Code to initially initialize the thread pointer.  This might need
    special attention since 'errno' is not yet available and if the
    operation can cause a failure 'errno' must not be touched.  */
@@ -89,6 +95,8 @@ typedef struct
     tcbhead_t *head = _descr;						      \
 									      \
     head->tcb = _descr;							      \
+    /* For now the thread descriptor isat the same address.  */		      \
+    head->self = _descr;						      \
 									      \
     asm ("pushl %%ebx\n\t"						      \
 	 "movl $1, %%ebx\n\t"						      \
diff --git a/misc/init-misc.c b/misc/init-misc.c
index 8091e8f478..8b877c3c43 100644
--- a/misc/init-misc.c
+++ b/misc/init-misc.c
@@ -1,5 +1,5 @@
 /* Define and initialize `__progname' et. al.
-   Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1994,1995,1996,1997,1998,2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -25,16 +25,6 @@ weak_alias (__progname_full, program_invocation_name)
 weak_alias (__progname, program_invocation_short_name)
 
 
-#ifdef HAVE_GNU_LD
-static
-#endif /* HAVE_GNU_LD */
-void __init_misc (int argc, char **argv, char **envp)
-  __attribute__ ((unused));
-
-
-#ifdef HAVE_GNU_LD
-static
-#endif /* HAVE_GNU_LD */
 void
 __init_misc (int argc, char **argv, char **envp)
 {
@@ -48,7 +38,3 @@ __init_misc (int argc, char **argv, char **envp)
       __progname_full = argv[0];
     }
 }
-
-#ifdef HAVE_GNU_LD
-text_set_element (__libc_subinit, __init_misc);
-#endif
diff --git a/sysdeps/mach/hurd/Makefile b/sysdeps/mach/hurd/Makefile
index f34a577c49..e12874f055 100644
--- a/sysdeps/mach/hurd/Makefile
+++ b/sysdeps/mach/hurd/Makefile
@@ -186,6 +186,7 @@ endif
 
 ifeq ($(subdir),csu)
 
+sysdep_routines += set-init
 extra-objs += static-start.o
 
 # We need special startup code for statically linked binaries.
diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c
index e16a5cdfd9..f8149da4a2 100644
--- a/sysdeps/mach/hurd/i386/init-first.c
+++ b/sysdeps/mach/hurd/i386/init-first.c
@@ -29,6 +29,7 @@
 
 extern void __mach_init (void);
 extern void __libc_init (int, char **, char **);
+extern void __init_misc (int, char **, char **);
 #ifdef USE_NONOPTION_FLAGS
 extern void __getopt_clean_environment (char **);
 #endif
@@ -64,6 +65,7 @@ posixland_init (int argc, char **argv, char **envp)
   __libc_argv = argv;
   __environ = envp;
 
+  __init_misc (argc, argv, envp);
   __libc_init (argc, argv, envp);
 
 #ifdef USE_NONOPTION_FLAGS
diff --git a/sysdeps/mach/hurd/mips/init-first.c b/sysdeps/mach/hurd/mips/init-first.c
index d0ab593404..525f510cc1 100644
--- a/sysdeps/mach/hurd/mips/init-first.c
+++ b/sysdeps/mach/hurd/mips/init-first.c
@@ -1,5 +1,5 @@
 /* Initialization code run first thing by the ELF startup code.  For Mips/Hurd.
-   Copyright (C) 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1996,1997,1998,2000,2001,2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
 
 extern void __mach_init (void);
 extern void __libc_init (int, char **, char **);
+extern void __init_misc (int, char **, char **);
 #ifdef USE_NONOPTION_FLAGS
 extern void __getopt_clean_environment (char **);
 #endif
@@ -106,6 +107,7 @@ init1 (int argc, char *arg0, ...)
 		d->portarray, d->portarraysize,
 		d->intarray, d->intarraysize);
 
+  __init_misc (argc, argv, __environ);
   __libc_init (argc, argv, __environ);
 
 #ifdef USE_NONOPTION_FLAGS
diff --git a/sysdeps/mach/hurd/powerpc/init-first.c b/sysdeps/mach/hurd/powerpc/init-first.c
index 25f5c53716..c9ad66096b 100644
--- a/sysdeps/mach/hurd/powerpc/init-first.c
+++ b/sysdeps/mach/hurd/powerpc/init-first.c
@@ -1,5 +1,5 @@
 /* Initialization code run first thing by the ELF startup code.  PowerPC/Hurd.
-   Copyright (C) 1995,96,97,98,99,2000,01 Free Software Foundation, Inc.
+   Copyright (C) 1995-2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -29,6 +29,7 @@
 
 extern void __mach_init (void);
 extern void __libc_init (int, char **, char **);
+extern void __init_misc (int, char **, char **);
 #ifdef USE_NONOPTION_FLAGS
 extern void __getopt_clean_environment (char **);
 #endif
@@ -69,6 +70,7 @@ posixland_init (int argc, char **argv, char **envp)
   __libc_argv = argv;
   __environ = envp;
 
+  __init_misc (argc, argv, envp);
   __libc_init (argc, argv, envp);
 
 #ifdef USE_NONOPTION_FLAGS
diff --git a/csu/set-init.c b/sysdeps/mach/hurd/set-init.c
index f89a4697ac..f89a4697ac 100644
--- a/csu/set-init.c
+++ b/sysdeps/mach/hurd/set-init.c
diff --git a/sysdeps/unix/sysv/linux/init-first.c b/sysdeps/unix/sysv/linux/init-first.c
index bffb0fa642..1fb04bbda1 100644
--- a/sysdeps/unix/sysv/linux/init-first.c
+++ b/sysdeps/unix/sysv/linux/init-first.c
@@ -33,7 +33,7 @@
 # include "dl-osinfo.h"
 #endif
 
-extern void __libc_init (int, char **, char **);
+extern void __init_misc (int, char **, char **);
 
 /* The function is called from assembly stubs the compiler can't see.  */
 static void init (int, char **, char **) __attribute__ ((unused));
@@ -89,7 +89,7 @@ init (int argc, char **argv, char **envp)
   __libc_init_secure ();
 #endif
 
-  __libc_init (argc, argv, envp);
+  __init_misc (argc, argv, envp);
 
 #ifdef USE_NONOPTION_FLAGS
   /* This is a hack to make the special getopt in GNU libc working.  */