about summary refs log tree commit diff
path: root/nptl
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2007-05-19 07:08:23 +0000
committerUlrich Drepper <drepper@redhat.com>2007-05-19 07:08:23 +0000
commitdf94b6412e0628cd577da0ce5626358a3967ee44 (patch)
tree3b969d3e4175fe3a72f824c482d8c9f9a3b3bf3e /nptl
parent2acd01acb10d0c0113f87bf7e787e0854498269d (diff)
downloadglibc-df94b6412e0628cd577da0ce5626358a3967ee44.tar.gz
glibc-df94b6412e0628cd577da0ce5626358a3967ee44.tar.xz
glibc-df94b6412e0628cd577da0ce5626358a3967ee44.zip
* elf/dl-close.c (_dl_close_worker): When removing object from
	global scope, wait for all lookups to finish afterwards.
	* elf/dl-open.c (add_to_global): When global scope array must
	grow, allocate a new one and free old array only after all
	lookups finish.
	* elf/dl-runtime.c (_dl_fixup): Protect using global scope.
	(_dl_lookup_symbol_x): Likewise.
	* elf/dl-support.c: Define _dl_wait_lookup_done.
	* sysdeps/generic/ldsodefs.h (struct rtld_global): Add
	_dl_wait_lookup_done.
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog13
-rw-r--r--nptl/allocatestack.c57
-rw-r--r--nptl/init.c26
-rw-r--r--nptl/pthreadP.h4
-rw-r--r--nptl/sysdeps/i386/tls.h33
-rw-r--r--nptl/sysdeps/pthread/pthread-functions.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c7
-rw-r--r--nptl/sysdeps/x86_64/tls.h26
8 files changed, 142 insertions, 26 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 894a9bd9fb..db7b86f2fb 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,16 @@
+2007-05-19  Ulrich Drepper  <drepper@redhat.com>
+
+	* allocatestack.c (__wait_lookup_done): New function.
+	* sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+	Add ptr_wait_lookup_done.
+	* init.c (pthread_functions): Initialize .ptr_wait_lookup_done.
+	* pthreadP.h: Declare __wait_lookup_done.
+	* sysdeps/i386/tls.h (tcbhead_t): Add gscope_flag.
+	Define macros to implement reference handling of global scope.
+	* sysdeps/x86_64/tls.h: Likewise.
+	* sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+	Initialize GL(dl_wait_lookup_done).
+
 2007-05-17  Ulrich Drepper  <drepper@redhat.com>
 
 	[BZ #4512]
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 6b60642042..e556dbac08 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -996,3 +996,60 @@ __pthread_init_static_tls (struct link_map *map)
 
   lll_unlock (stack_cache_lock);
 }
+
+
+void
+attribute_hidden
+__wait_lookup_done (void)
+{
+  lll_lock (stack_cache_lock);
+
+  struct pthread *self = THREAD_SELF;
+
+  /* Iterate over the list with system-allocated threads first.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+	continue;
+
+      int *const gscope_flagp = &t->header.gscope_flag;
+
+      /* We have to wait until this thread is done with the global
+	 scope.  First tell the thread that we are waiting and
+	 possibly have to be woken.  */
+      if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
+						THREAD_GSCOPE_FLAG_WAIT,
+						THREAD_GSCOPE_FLAG_USED))
+	continue;
+
+      do
+	lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT);
+      while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
+    }
+
+  /* Now the list with threads using user-allocated stacks.  */
+  list_for_each (runp, &__stack_user)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+	continue;
+
+      int *const gscope_flagp = &t->header.gscope_flag;
+
+      /* We have to wait until this thread is done with the global
+	 scope.  First tell the thread that we are waiting and
+	 possibly have to be woken.  */
+      if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
+						THREAD_GSCOPE_FLAG_WAIT,
+						THREAD_GSCOPE_FLAG_USED))
+	continue;
+
+      do
+	lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT);
+      while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
+    }
+
+  lll_unlock (stack_cache_lock);
+}
diff --git a/nptl/init.c b/nptl/init.c
index dddc975a5e..fb4030e249 100644
--- a/nptl/init.c
+++ b/nptl/init.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -35,27 +35,6 @@
 #include <lowlevellock.h>
 
 
-#ifndef __NR_set_tid_address
-/* XXX For the time being...  Once we can rely on the kernel headers
-   having the definition remove these lines.  */
-#if defined __s390__
-# define __NR_set_tid_address	252
-#elif defined __ia64__
-# define __NR_set_tid_address	1233
-#elif defined __i386__
-# define __NR_set_tid_address	258
-#elif defined __x86_64__
-# define __NR_set_tid_address	218
-#elif defined __powerpc__
-# define __NR_set_tid_address	232
-#elif defined __sparc__
-# define __NR_set_tid_address	166
-#else
-# error "define __NR_set_tid_address"
-#endif
-#endif
-
-
 /* Size and alignment of static TLS block.  */
 size_t __static_tls_size;
 size_t __static_tls_align_m1;
@@ -138,7 +117,8 @@ static const struct pthread_functions pthread_functions =
     .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
     .ptr__nptl_setxid = __nptl_setxid,
     /* For now only the stack cache needs to be freed.  */
-    .ptr_freeres = __free_stack_cache
+    .ptr_freeres = __free_stack_cache,
+    .ptr_wait_lookup_done = __wait_lookup_done
   };
 # define ptr_pthread_functions &pthread_functions
 #else
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index f9634ab0ff..21ce6fe0b7 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -545,6 +545,8 @@ extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden;
 
 extern void __free_stack_cache (void) attribute_hidden;
 
+extern void __wait_lookup_done (void) attribute_hidden;
+
 #ifdef SHARED
 # define PTHREAD_STATIC_FN_REQUIRE(name)
 #else
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
index d5b3797e69..d9044f3fde 100644
--- a/nptl/sysdeps/i386/tls.h
+++ b/nptl/sysdeps/i386/tls.h
@@ -1,5 +1,5 @@
 /* Definition for thread-local data handling.  nptl/i386 version.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2002,2003,2004,2005,2006,2007 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 @@
 # include <stdint.h>
 # include <stdlib.h>
 # include <list.h>
+# include <sysdep.h>
 
 
 /* Type for the dtv.  */
@@ -51,6 +52,7 @@ typedef struct
   uintptr_t sysinfo;
   uintptr_t stack_guard;
   uintptr_t pointer_guard;
+  int gscope_flag;
 } tcbhead_t;
 
 # define TLS_MULTIPLE_THREADS_IN_TCB 1
@@ -431,6 +433,35 @@ union user_desc_init
    = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
 
 
+/* Get and set the global scope generation counter in the TCB head.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do									      \
+    { int __res;							      \
+      asm volatile ("xchg %0, %%gs:%P1"					      \
+		    : "=r" (__res)					      \
+		    : "i" (offsetof (struct pthread, header.gscope_flag)),    \
+		      "0" (THREAD_GSCOPE_FLAG_UNUSED));			      \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				      \
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1);		      \
+    }									      \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
+#ifdef PTR_DEMANGLE
+# define THREAD_GSCOPE_WAIT() \
+  do { void (*ptr) (void) = GL(dl_wait_lookup_done);			      \
+       PTR_DEMANGLE (ptr);						      \
+       ptr ();								      \
+  } while (0)
+#else
+# define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+#endif
+
+
 #endif /* __ASSEMBLER__ */
 
 #endif	/* tls.h */
diff --git a/nptl/sysdeps/pthread/pthread-functions.h b/nptl/sysdeps/pthread/pthread-functions.h
index a13b937032..f0eddd3053 100644
--- a/nptl/sysdeps/pthread/pthread-functions.h
+++ b/nptl/sysdeps/pthread/pthread-functions.h
@@ -97,7 +97,7 @@ struct pthread_functions
   void (*ptr__nptl_deallocate_tsd) (void);
   int (*ptr__nptl_setxid) (struct xid_command *);
   void (*ptr_freeres) (void);
-  void (*ptr_wait_lookup_done) (int);
+  void (*ptr_wait_lookup_done) (void);
 };
 
 /* Variable in libc.so.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c b/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
index 92a188a2f3..25509eb3d6 100644
--- a/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
+++ b/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
@@ -26,6 +26,7 @@
 #include <pthreadP.h>
 #include <bits/libc-lock.h>
 #include <sysdep.h>
+#include <ldsodefs.h>
 
 
 #ifdef TLS_MULTIPLE_THREADS_IN_TCB
@@ -70,6 +71,12 @@ __libc_pthread_init (ptr, reclaim, functions)
       dest->parr[cnt] = p;
     }
   __libc_pthread_functions_init = 1;
+
+# ifdef RTLD_NOT_MANGLED
+  GL(dl_wait_lookup_done) = functions->ptr_wait_lookup_done;
+# else
+  GL(dl_wait_lookup_done) = __libc_pthread_functions.ptr_wait_lookup_done;
+# endif
 #endif
 
 #ifndef TLS_MULTIPLE_THREADS_IN_TCB
diff --git a/nptl/sysdeps/x86_64/tls.h b/nptl/sysdeps/x86_64/tls.h
index 0b5aeb00ff..00c9abbfcb 100644
--- a/nptl/sysdeps/x86_64/tls.h
+++ b/nptl/sysdeps/x86_64/tls.h
@@ -26,6 +26,7 @@
 # include <stddef.h>
 # include <stdint.h>
 # include <stdlib.h>
+# include <sysdep.h>
 
 
 /* Type for the dtv.  */
@@ -47,6 +48,7 @@ typedef struct
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
   int multiple_threads;
+  int gscope_flag;
   uintptr_t sysinfo;
   uintptr_t stack_guard;
   uintptr_t pointer_guard;
@@ -337,6 +339,30 @@ typedef struct
    = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
 
 
+/* Get and set the global scope generation counter in the TCB head.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do									      \
+    { int __res;							      \
+      asm volatile ("xchgl %0, %%fs:%P1"				      \
+		    : "=r" (__res)					      \
+		    : "i" (offsetof (struct pthread, header.gscope_flag)),    \
+		      "0" (THREAD_GSCOPE_FLAG_UNUSED));			      \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				      \
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1);		      \
+    }									      \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
+#define THREAD_GSCOPE_WAIT() \
+  do { void (*ptr) (void) = GL(dl_wait_lookup_done);			      \
+       PTR_DEMANGLE (ptr);						      \
+       ptr ();								      \
+  } while (0)
+
+
 #endif /* __ASSEMBLER__ */
 
 #endif	/* tls.h */