[PATCH] Fix linuxthreads race
Jakub Jelinek
jakub@redhat.com
Tue Sep 16 23:17:00 GMT 2003
Hi!
If a signal other than __pthread_sig_cancel is sent to a newly
created thread before it INIT_THREAD_SELF in pthread_start_thread,
it will have wrong thread_self ().
The following patch should fix this (tested
on i386 --without-tls --without-__thread non-FS, i686 --with-tls
--without-__thread non-FS and i686 --with-tls --without-__thread FS).
2003-09-17 Jakub Jelinek <jakub@redhat.com>
* pthread.c (manager_thread): Remove static, add attribute_hidden.
(thread_self_stack): Rename to...
(__pthread_self_stack): ... this. Remove static.
(pthread_handle_sigcancel): Adjust caller.
(pthread_handle_sigrestart): Do INIT_THREAD_SELF if signal is received
before INIT_THREAD_SELF in pthread_start_thread.
* sighandler.c (manager_thread): Define.
(CHECK_THREAD_SELF): Define.
(__pthread_sighandler, __pthread_sighandler_rt): Use it.
* descr.h (manager_thread): Declare.
* internals.h (__pthread_self_stack): New prototype.
--- libc/linuxthreads/pthread.c.jj 2003-09-02 03:08:54.000000000 -0400
+++ libc/linuxthreads/pthread.c 2003-09-16 16:29:56.000000000 -0400
@@ -55,7 +55,7 @@ extern struct __res_state _res;
#ifdef USE_TLS
/* We need only a few variables. */
-static pthread_descr manager_thread;
+pthread_descr manager_thread attribute_hidden;
#else
@@ -896,7 +896,7 @@ pthread_descr __pthread_find_self(void)
#else
-static pthread_descr thread_self_stack(void)
+pthread_descr __pthread_self_stack(void)
{
char *sp = CURRENT_STACK_FRAME;
pthread_handle h;
@@ -1024,6 +1024,22 @@ static void pthread_atexit_retcode(void
static void pthread_handle_sigrestart(int sig)
{
pthread_descr self = thread_self();
+#if defined THREAD_SELF && defined INIT_THREAD_SELF
+ if (self == manager_thread)
+ {
+ /* A new thread might get a cancel signal before it is fully
+ initialized, so that the thread register might still point to the
+ manager thread. Double check that this is really the manager
+ thread. */
+ pthread_descr real_self = __pthread_self_stack();
+ if (real_self != manager_thread)
+ {
+ /* Oops, thread_self() isn't working yet.. */
+ self = real_self;
+ INIT_THREAD_SELF(self, self->p_nr);
+ }
+ }
+#endif
THREAD_SETMEM(self, p_signal, sig);
if (THREAD_GETMEM(self, p_signal_jmp) != NULL)
siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1);
@@ -1046,7 +1062,7 @@ static void pthread_handle_sigcancel(int
initialized, so that the thread register might still point to the
manager thread. Double check that this is really the manager
thread. */
- pthread_descr real_self = thread_self_stack();
+ pthread_descr real_self = __pthread_self_stack();
if (real_self == manager_thread)
{
__pthread_manager_sighandler(sig);
--- libc/linuxthreads/internals.h.jj 2003-09-02 03:08:54.000000000 -0400
+++ libc/linuxthreads/internals.h 2003-09-16 16:29:00.000000000 -0400
@@ -363,6 +363,7 @@ extern int __pthread_condattr_init (pthr
extern int __pthread_condattr_destroy (pthread_condattr_t *attr);
extern pthread_t __pthread_self (void);
extern pthread_descr __pthread_thread_self (void);
+extern pthread_descr __pthread_self_stack (void) attribute_hidden;
extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
extern void __pthread_exit (void *retval);
extern int __pthread_getschedparam (pthread_t thread, int *policy,
--- libc/linuxthreads/descr.h.jj 2003-07-23 03:56:17.000000000 -0400
+++ libc/linuxthreads/descr.h 2003-09-16 16:26:35.000000000 -0400
@@ -217,6 +217,7 @@ extern char *__pthread_manager_thread_to
/* Descriptor of the manager thread */
extern struct _pthread_descr_struct __pthread_manager_thread;
+extern pthread_descr manager_thread attribute_hidden;
/* Indicate whether at least one thread has a user-defined stack (if 1),
or all threads have stacks supplied by LinuxThreads (if 0). */
--- libc/linuxthreads/sighandler.c.jj 2002-05-03 03:36:37.000000000 -0400
+++ libc/linuxthreads/sighandler.c 2003-09-16 16:35:48.000000000 -0400
@@ -16,6 +16,31 @@
#include "internals.h"
+#if defined THREAD_SELF && defined INIT_THREAD_SELF
+# ifndef USE_TLS
+# define manager_thread (&__pthread_manager_thread)
+# endif
+# define CHECK_THREAD_SELF(self) \
+do { \
+ if (self == manager_thread) \
+ { \
+ /* A new thread might get a cancel signal before it is fully \
+ initialized, so that the thread register might still point to the \
+ manager thread. Double check that this is really the manager \
+ thread. */ \
+ pthread_descr real_self = __pthread_self_stack(); \
+ if (real_self != manager_thread) \
+ { \
+ /* Oops, thread_self() isn't working yet.. */ \
+ self = real_self; \
+ INIT_THREAD_SELF(self, self->p_nr); \
+ } \
+ } \
+} while (0)
+#else
+# define CHECK_THREAD_SELF(self) do { } while (0)
+#endif
+
/* The wrapper around user-provided signal handlers */
void __pthread_sighandler(int signo, SIGCONTEXT ctx)
@@ -23,6 +48,7 @@ void __pthread_sighandler(int signo, SIG
pthread_descr self;
char * in_sighandler;
self = thread_self();
+ CHECK_THREAD_SELF(self);
/* If we're in a sigwait operation, just record the signal received
and return without calling the user's handler */
if (THREAD_GETMEM(self, p_sigwaiting)) {
@@ -47,6 +73,7 @@ void __pthread_sighandler_rt(int signo,
pthread_descr self;
char * in_sighandler;
self = thread_self();
+ CHECK_THREAD_SELF(self);
/* If we're in a sigwait operation, just record the signal received
and return without calling the user's handler */
if (THREAD_GETMEM(self, p_sigwaiting)) {
Jakub
More information about the Libc-hacker
mailing list