mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-10 07:10:06 +00:00
1999-01-07 Xavier Leroy <Xavier.Leroy@inria.fr>
* 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.
This commit is contained in:
parent
3499233817
commit
b92ad8d61f
@ -1,3 +1,15 @@
|
||||
1999-01-07 Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
* 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 <schwab@issan.cs.uni-dortmund.de>
|
||||
|
||||
* linuxthreads.texi: Remove pointers from first @node. Move old
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user