aboutsummaryrefslogtreecommitdiff
path: root/linuxthreads
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads')
-rw-r--r--linuxthreads/ChangeLog12
-rw-r--r--linuxthreads/internals.h4
-rw-r--r--linuxthreads/manager.c5
-rw-r--r--linuxthreads/pthread.c49
-rw-r--r--linuxthreads/signals.c37
5 files changed, 85 insertions, 22 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index e890df9..e390dc6 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -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
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index 1557789..0654c32 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 5a5420d..cf9796a 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 8d892b7..29e7682 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 e833778..a352eb9 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);