This is the mail archive of the
libc-hacker@sourceware.cygnus.com
mailing list for the glibc project.
Re: gdb and linuxthreads (A deadlock in linuxthreads.)
- To: "H.J. Lu" <hjl@lucon.org>
- Subject: Re: gdb and linuxthreads (A deadlock in linuxthreads.)
- From: Xavier Leroy <Xavier.Leroy@inria.fr>
- Date: Sun, 20 Dec 1998 12:19:16 +0100
- Cc: GNU C Library <libc-hacker@cygnus.com>, Ulrich Drepper <drepper@cygnus.com>
- References: <19981219224253.44971@pauillac.inria.fr> <m0zrX0x-00038dC@ocean.lucon.org>
> I have verified that there was no third thread at all. There were only
> 2 threads, the manager and the thread just sent a request to the
> manager. It may be a race condition which can only happen on a SMP
> machine.
Hmph. That's interesting. I'll try to think of a scenario that
explains this. Sometimes, I fear the memory subsystem doesn't
implement strong ordering on memory accesses like it's supposed to do
according to the docs...
At any rate, you'll find below the patches that change the signal used
to report dead children. The patches are against the current working
sources on anoncvs@glibc.cygnus.com. I haven't been able to test them
on my home machine, but will test them tomorrow at work. I'll also
test what happens with gdb. Maybe the extra signals don't break
anything, just causing gdb to rescan the set of running threads
unnecessarily.
All the best,
- Xavier Leroy
Index: manager.c
===================================================================
RCS file: /glibc/cvsfiles/libc/linuxthreads/manager.c,v
retrieving revision 1.18
diff -c -r1.18 manager.c
*** manager.c 1998/10/29 14:34:19 1.18
--- manager.c 1998/12/20 09:22:02
***************
*** 101,111 ****
/* 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;
! /* Block all signals except __pthread_sig_restart, __pthread_sig_cancel
! and SIGTRAP */
sigfillset(&mask);
! sigdelset(&mask, __pthread_sig_restart);
! sigdelset(&mask, __pthread_sig_cancel); /* for debugging new threads */
sigdelset(&mask, SIGTRAP); /* for debugging purposes */
sigprocmask(SIG_SETMASK, &mask, NULL);
/* Raise our priority to match that of main thread */
--- 101,109 ----
/* 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;
! /* Block all signals except __pthread_sig_cancel and SIGTRAP */
sigfillset(&mask);
! sigdelset(&mask, __pthread_sig_cancel); /* for thread termination */
sigdelset(&mask, SIGTRAP); /* for debugging purposes */
sigprocmask(SIG_SETMASK, &mask, NULL);
/* Raise our priority to match that of main thread */
***************
*** 378,384 ****
#ifdef CLONE_PTRACE
CLONE_PTRACE |
#endif
! __pthread_sig_restart, new_thread);
/* Check if cloning succeeded */
if (pid == -1) {
/* Free the stack if we allocated it */
--- 376,382 ----
#ifdef CLONE_PTRACE
CLONE_PTRACE |
#endif
! __pthread_sig_cancel, new_thread);
/* Check if cloning succeeded */
if (pid == -1) {
/* Free the stack if we allocated it */
Index: pthread.c
===================================================================
RCS file: /glibc/cvsfiles/libc/linuxthreads/pthread.c,v
retrieving revision 1.12
diff -c -r1.12 pthread.c
*** pthread.c 1998/12/04 20:55:31 1.12
--- pthread.c 1998/12/20 09:22:04
***************
*** 459,467 ****
/* The handler for the RESTART signal just records the signal received
in the thread descriptor, and optionally performs a siglongjmp
! (for pthread_cond_timedwait).
! For the thread manager thread, redirect the signal to
! __pthread_manager_sighandler. */
#ifndef __i386__
static void pthread_handle_sigrestart(int sig)
--- 459,465 ----
/* The handler for the RESTART signal just records the signal received
in the thread descriptor, and optionally performs a siglongjmp
! (for pthread_cond_timedwait). */
#ifndef __i386__
static void pthread_handle_sigrestart(int sig)
***************
*** 474,491 ****
asm volatile ("movw %w0,%%gs" : : "r" (ctx.gs));
self = thread_self();
#endif
! if (self == &__pthread_manager_thread) {
! __pthread_manager_sighandler(sig);
! } else {
! THREAD_SETMEM(self, p_signal, sig);
! if (THREAD_GETMEM(self, p_signal_jmp) != NULL)
! siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1);
! }
}
/* The handler for the CANCEL signal checks for cancellation
(in asynchronous mode), for process-wide exit and exec requests.
! For the thread manager thread, we ignore the signal.
The debugging strategy is as follows:
On reception of a REQ_DEBUG request (sent by new threads created to
the thread manager under debugging mode), the thread manager throws
--- 472,486 ----
asm volatile ("movw %w0,%%gs" : : "r" (ctx.gs));
self = thread_self();
#endif
! THREAD_SETMEM(self, p_signal, sig);
! if (THREAD_GETMEM(self, p_signal_jmp) != NULL)
! siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1);
}
/* The handler for the CANCEL signal checks for cancellation
(in asynchronous mode), for process-wide exit and exec requests.
! For the thread manager thread, redirect the signal to
! __pthread_manager_sighandler.
The debugging strategy is as follows:
On reception of a REQ_DEBUG request (sent by new threads created to
the thread manager under debugging mode), the thread manager throws
***************
*** 510,516 ****
#endif
if (self == &__pthread_manager_thread)
! return;
if (__pthread_exit_requested) {
/* Main thread should accumulate times for thread manager and its
children, so that timings for main thread account for all threads. */
--- 505,511 ----
#endif
if (self == &__pthread_manager_thread)
! __pthread_manager_sighandler(sig);
if (__pthread_exit_requested) {
/* Main thread should accumulate times for thread manager and its
children, so that timings for main thread account for all threads. */