From b92ad8d61f18a3e9a61434e2e3252efd862bd7f4 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 7 Jan 1999 11:53:05 +0000 Subject: 1999-01-07 Xavier Leroy * pthread.c: Use a third signal __pthread_sig_debug distinct from __pthread_sig_cancel to notify gdb when a thread is created * manager.c: Likewise. * internals.h: Likewise. * signals.c: The implementation of sigwait(s) assumed that all signals in s have signal handlers already attached. This is not required by the standard, so make it work also if some of the signals have no handlers. --- linuxthreads/ChangeLog | 12 ++++++++++++ linuxthreads/internals.h | 4 ++++ linuxthreads/manager.c | 5 +++-- linuxthreads/pthread.c | 49 +++++++++++++++++++++++++++++++++--------------- linuxthreads/signals.c | 37 +++++++++++++++++++++++++++++++----- 5 files changed, 85 insertions(+), 22 deletions(-) diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index e890df90cc..e390dc6a94 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,15 @@ +1999-01-07 Xavier Leroy + + * pthread.c: Use a third signal __pthread_sig_debug distinct + from __pthread_sig_cancel to notify gdb when a thread is + created + * manager.c: Likewise. + * internals.h: Likewise. + * signals.c: The implementation of sigwait(s) assumed that + all signals in s have signal handlers already attached. + This is not required by the standard, so make it work + also if some of the signals have no handlers. + 1999-01-05 Andreas Schwab * linuxthreads.texi: Remove pointers from first @node. Move old diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h index 1557789a7c..0654c32758 100644 --- a/linuxthreads/internals.h +++ b/linuxthreads/internals.h @@ -148,6 +148,10 @@ struct pthread_request { extern int __pthread_sig_restart; extern int __pthread_sig_cancel; +/* Signal used for interfacing with gdb */ + +extern int __pthread_sig_debug; + /* Default signals used if we don't have realtime signals */ #define DEFAULT_SIG_RESTART SIGUSR1 diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c index 5a5420d9a9..cf9796ac2e 100644 --- a/linuxthreads/manager.c +++ b/linuxthreads/manager.c @@ -161,7 +161,8 @@ int __pthread_manager(void *arg) break; case REQ_DEBUG: /* Make gdb aware of new thread */ - if (__pthread_threads_debug) raise(__pthread_sig_cancel); + if (__pthread_threads_debug && __pthread_sig_debug > 0) + raise(__pthread_sig_debug); restart(request.req_thread); break; } @@ -554,7 +555,7 @@ static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode) _exit(0); } -/* Handler for __pthread_sig_restart in thread manager thread */ +/* Handler for __pthread_sig_cancel in thread manager thread */ void __pthread_manager_sighandler(int sig) { diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c index 8d892b7bb5..29e7682105 100644 --- a/linuxthreads/pthread.c +++ b/linuxthreads/pthread.c @@ -150,9 +150,11 @@ const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct, #ifdef SIGRTMIN int __pthread_sig_restart; int __pthread_sig_cancel; +int __pthread_sig_debug; #else int __pthread_sig_restart = DEFAULT_SIG_RESTART; int __pthread_sig_cancel = DEFAULT_SIG_CANCEL; +int __pthread_sig_debug = 0; /* disabled */ #endif /* These variables are used by the setup code. */ @@ -169,6 +171,7 @@ static void pthread_handle_sigrestart(int sig); static void pthread_handle_sigcancel(int sig, struct sigcontext ctx); static void pthread_handle_sigrestart(int sig, struct sigcontext ctx); #endif +static void pthread_handle_sigdebug(int sig); /* Initialize the pthread library. Initialization is split in two functions: @@ -220,12 +223,17 @@ static void pthread_initialize(void) /* Allocate the signals used. */ __pthread_sig_restart = __libc_allocate_rtsig (1); __pthread_sig_cancel = __libc_allocate_rtsig (1); - if (__pthread_sig_restart < 0 || __pthread_sig_cancel < 0) + __pthread_sig_debug = __libc_allocate_rtsig (2); + if (__pthread_sig_restart < 0 || + __pthread_sig_cancel < 0 || + __pthread_sig_debug < 0) { /* The kernel does not support real-time signals. Use as before - the available signals in the fixed set. */ + the available signals in the fixed set. + Debugging is not supported in this case. */ __pthread_sig_restart = DEFAULT_SIG_RESTART; __pthread_sig_cancel = DEFAULT_SIG_CANCEL; + __pthread_sig_debug = 0; } #endif /* Setup signal handlers for the initial thread. @@ -237,8 +245,7 @@ static void pthread_initialize(void) sa.sa_handler = (__sighandler_t) pthread_handle_sigrestart; #endif sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; /* does not matter for regular threads, but - better for the thread manager */ + sa.sa_flags = 0; __sigaction(__pthread_sig_restart, &sa, NULL); #ifndef __i386__ sa.sa_handler = pthread_handle_sigcancel; @@ -247,7 +254,12 @@ static void pthread_initialize(void) #endif sa.sa_flags = 0; __sigaction(__pthread_sig_cancel, &sa, NULL); - + if (__pthread_sig_debug > 0) { + sa.sa_handler = pthread_handle_sigdebug; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + __sigaction(__pthread_sig_debug, &sa, NULL); + } /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ sigemptyset(&mask); sigaddset(&mask, __pthread_sig_restart); @@ -479,16 +491,8 @@ static void pthread_handle_sigrestart(int sig, struct sigcontext ctx) /* 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 - __pthread_sig_cancel to itself. The debugger (if active) intercepts - this signal, takes into account new threads and continue execution - of the thread manager by propagating the signal because it doesn't - know what it is specifically done for. In the current implementation, - the thread manager simply discards it. */ + For the thread manager thread, redirect the signal to + __pthread_manager_sighandler. */ #ifndef __i386__ static void pthread_handle_sigcancel(int sig) @@ -528,6 +532,21 @@ static void pthread_handle_sigcancel(int sig, struct sigcontext ctx) } } +/* Handler for the DEBUG 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 + __pthread_sig_cancel to itself. The debugger (if active) intercepts + this signal, takes into account new threads and continue execution + of the thread manager by propagating the signal because it doesn't + know what it is specifically done for. In the current implementation, + the thread manager simply discards it. */ + +static void pthread_handle_sigdebug(int sig) +{ + /* Nothing */ +} + /* Reset the state of the thread machinery after a fork(). Close the pipe used for requests and set the main thread to the forked thread. diff --git a/linuxthreads/signals.c b/linuxthreads/signals.c index e833778d53..a352eb951d 100644 --- a/linuxthreads/signals.c +++ b/linuxthreads/signals.c @@ -91,19 +91,23 @@ static void pthread_sighandler(int signo) THREAD_SETMEM(self, p_in_sighandler, NULL); } +/* The wrapper around sigaction. Install our own signal handler + around the signal. */ int sigaction(int sig, const struct sigaction * act, struct sigaction * oact) { struct sigaction newact; struct sigaction *newactp; - if (sig == __pthread_sig_restart || sig == __pthread_sig_cancel) + if (sig == __pthread_sig_restart || + sig == __pthread_sig_cancel || + (sig == __pthread_sig_debug && __pthread_sig_debug > 0)) return EINVAL; if (act) { newact = *act; if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL - && sig < NSIG) + && sig > 0 && sig < NSIG) newact.sa_handler = pthread_sighandler; newactp = &newact; } @@ -111,7 +115,7 @@ int sigaction(int sig, const struct sigaction * act, newactp = NULL; if (__sigaction(sig, newactp, oact) == -1) return -1; - if (sig < NSIG) + if (sig > 0 && sig < NSIG) { if (oact != NULL) oact->sa_handler = sighandler[sig]; @@ -121,20 +125,41 @@ int sigaction(int sig, const struct sigaction * act, return 0; } +/* A signal handler that does nothing */ +static void pthread_null_sighandler(int sig) { } + +/* sigwait -- synchronously wait for a signal */ int sigwait(const sigset_t * set, int * sig) { volatile pthread_descr self = thread_self(); sigset_t mask; int s; sigjmp_buf jmpbuf; + struct sigaction sa; /* Get ready to block all signals except those in set - and the cancellation signal */ + and the cancellation signal. + Also check that handlers are installed on all signals in set, + and if not, install our dummy handler. This is conformant to + POSIX: "The effect of sigwait() on the signal actions for the + signals in set is unspecified." */ sigfillset(&mask); sigdelset(&mask, __pthread_sig_cancel); for (s = 1; s <= NSIG; s++) { - if (sigismember(set, s) && s != __pthread_sig_cancel) + if (sigismember(set, s) && + s != __pthread_sig_restart && + s != __pthread_sig_cancel && + s != __pthread_sig_debug) { sigdelset(&mask, s); + if (sighandler[s] == NULL || + sighandler[s] == SIG_DFL || + sighandler[s] == SIG_IGN) { + sa.sa_handler = pthread_null_sighandler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(s, &sa, NULL); + } + } } /* Test for cancellation */ if (sigsetjmp(jmpbuf, 1) == 0) { @@ -157,6 +182,8 @@ int sigwait(const sigset_t * set, int * sig) return 0; } +/* Redefine raise() to send signal to calling thread only, + as per POSIX 1003.1c */ int raise (int sig) { int retcode = pthread_kill(pthread_self(), sig); -- cgit 1.4.1