1999-01-07 Xavier Leroy <Xavier.Leroy@inria.fr>
authorUlrich Drepper <drepper@redhat.com>
Thu, 7 Jan 1999 11:53:05 +0000 (11:53 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 7 Jan 1999 11:53:05 +0000 (11:53 +0000)
* 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
linuxthreads/internals.h
linuxthreads/manager.c
linuxthreads/pthread.c
linuxthreads/signals.c

index e890df9..e390dc6 100644 (file)
@@ -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
index 1557789..0654c32 100644 (file)
@@ -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
index 5a5420d..cf9796a 100644 (file)
@@ -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)
 {
index 8d892b7..29e7682 100644 (file)
@@ -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.
index e833778..a352eb9 100644 (file)
@@ -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);