This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] lin-lwp.c fix


The attached patch (checked in) fixes a fairly critical bug in the new
Linux threads code (debugging threaded code might cause GDB to
terminate with one of the real-time signals).  I reorganized the
signal handling stuff a bit so that now the SIGCHLD signal is no
longer automatically blocked in the inferior.  This makes the failures
in gdb.base/sigall.exp disappear :-).

Mark


2000-09-06  Mark Kettenis  <kettenis@gnu.org>

	* lin-lwp.c (normal_mask, blocked_mask): New variables.
	(lin_lwp_wait): Block SIGCHLD here if it isn't already blocked.
	(lin_lwp_mourn_inferior): Restore the origional signal mask, and
	reset the mask of blocked signals.
	(_initialize_lin_lwp): Don't block SIGCHLD here, but do initialize
	suspend_mask and blocked_mask.  This makes us pass
	gdb.base/sigall.exp for Linux/x86 now.
	(lin_thread_get_thread_signals): Treat the LinuxThreads "cancel"
	signal similarly to SIGCHLD in the generic code.  Avoids GDB being
	terminated by a Real-time signal.


Index: lin-lwp.c
===================================================================
RCS file: /cvs/src/src/gdb/lin-lwp.c,v
retrieving revision 1.1
diff -u -p -r1.1 lin-lwp.c
--- lin-lwp.c	2000/09/03 18:41:28	1.1
+++ lin-lwp.c	2000/09/07 20:05:28
@@ -55,9 +55,11 @@ extern const char *strsignal (int sig);
    code:
 
    - In general one should specify the __WCLONE flag to waitpid in
-     order to make it report events for any of the cloned processes.
-     However, if a cloned process has exited the exit status is only
-     reported if the __WCLONE flag is absent.
+     order to make it report events for any of the cloned processes
+     (and leave it out for the initial process).  However, if a cloned
+     process has exited the exit status is only reported if the
+     __WCLONE flag is absent.  Linux 2.4 has a __WALL flag, but we
+     cannot use it since GDB must work on older systems too.
 
    - When a traced, cloned process exits and is waited for by the
      debugger, the kernel reassigns it to the origional parent and
@@ -126,9 +128,26 @@ static struct target_ops lin_lwp_ops;
 /* The standard child operations.  */
 extern struct target_ops child_ops;
 
+/* Since we cannot wait (in lin_lwp_wait) for the initial process and
+   any cloned processes with a single call to waitpid, we have to use
+   use the WNOHANG flag and call waitpid in a loop.  To optimize
+   things a bit we use `sigsuspend' to wake us up when a process has
+   something to report (it will send us a SIGCHLD if it has).  To make
+   this work we have to juggle with the signal mask.  We save the
+   origional signal mask such that we can restore it before creating a
+   new process in order to avoid blocking certain signals in the
+   inferior.  We then block SIGCHLD during the waitpid/sigsuspend
+   loop.  */
+
+/* Origional signal mask.  */
+static sigset_t normal_mask;
+
 /* Signal mask for use with sigsuspend in lin_lwp_wait, initialized in
    _initialize_lin_lwp.  */
 static sigset_t suspend_mask;
+
+/* Signals to block to make that sigsuspend work.  */
+static sigset_t blocked_mask;
 
 
 /* Prototypes for local functions.  */
@@ -479,7 +498,7 @@ stop_wait_callback (struct lwp_info *lp,
 		     is_cloned (lp->pid) ? __WCLONE : 0);
       if (pid == -1 && errno == ECHILD)
 	/* OK, the proccess has disappeared.  We'll catch the actual
-           exit event in lin_lwp_wait.  */
+	   exit event in lin_lwp_wait.  */
 	return 0;
 
       gdb_assert (pid == GET_LWP (lp->pid));
@@ -575,6 +594,13 @@ lin_lwp_wait (int pid, struct target_wai
   int options = 0;
   int status = 0;
 
+  /* Make sure SIGCHLD is blocked.  */
+  if (! sigismember (&blocked_mask, SIGCHLD))
+    {
+      sigaddset (&blocked_mask, SIGCHLD);
+      sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
+    }
+
  retry:
 
   /* First check if there is a LWP with a wait status pending.  */
@@ -659,7 +685,8 @@ lin_lwp_wait (int pid, struct target_wai
 	      lp = add_lwp (BUILD_LWP (lwpid, inferior_pid));
 	      if (threaded)
 		{
-		  gdb_assert (WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
+		  gdb_assert (WIFSTOPPED (status)
+			      && WSTOPSIG (status) == SIGSTOP);
 		  lp->signalled = 1;
 
 		  if (! in_thread_list (inferior_pid))
@@ -863,6 +890,10 @@ lin_lwp_mourn_inferior (void)
 
   trap_pid = 0;
 
+  /* Restore the origional signal mask.  */
+  sigprocmask (SIG_SETMASK, &normal_mask, NULL);
+  sigemptyset (&blocked_mask);
+
 #if 0
   target_beneath = find_target_beneath (&lin_lwp_ops);
 #else
@@ -978,7 +1009,6 @@ void
 _initialize_lin_lwp (void)
 {
   struct sigaction action;
-  sigset_t mask;
 
   extern void thread_db_init (struct target_ops *);
 
@@ -986,18 +1016,19 @@ _initialize_lin_lwp (void)
   add_target (&lin_lwp_ops);
   thread_db_init (&lin_lwp_ops);
 
+  /* Save the origional signal mask.  */
+  sigprocmask (SIG_SETMASK, NULL, &normal_mask);
+
   action.sa_handler = sigchld_handler;
   sigemptyset (&action.sa_mask);
   action.sa_flags = 0;
   sigaction (SIGCHLD, &action, NULL);
 
-  /* We block SIGCHLD throughout this code ...  */
-  sigemptyset (&mask);
-  sigaddset (&mask, SIGCHLD);
-  sigprocmask (SIG_BLOCK, &mask, &suspend_mask);
-
-  /* ... except during a sigsuspend.  */
+  /* Make sure we don't block SIGCHLD during a sigsuspend.  */
+  sigprocmask (SIG_SETMASK, NULL, &suspend_mask);
   sigdelset (&suspend_mask, SIGCHLD);
+
+  sigemptyset (&blocked_mask);
 }
 
 
@@ -1030,8 +1061,8 @@ get_signo (const char *name)
 void
 lin_thread_get_thread_signals (sigset_t *set)
 {
-  int restart;
-  int cancel;
+  struct sigaction action;
+  int restart, cancel;
 
   sigemptyset (set);
 
@@ -1045,4 +1076,21 @@ lin_thread_get_thread_signals (sigset_t 
 
   sigaddset (set, restart);
   sigaddset (set, cancel);
+
+  /* The LinuxThreads library makes terminating threads send a special
+     "cancel" signal instead of SIGCHLD.  Make sure we catch those (to
+     prevent them from terminating GDB itself, which is likely to be
+     their default action) and treat them the same way as SIGCHLD.  */
+
+  action.sa_handler = sigchld_handler;
+  sigemptyset (&action.sa_mask);
+  action.sa_flags = 0;
+  sigaction (cancel, &action, NULL);
+
+  /* We block the "cancel" signal throughout this code ...  */
+  sigaddset (&blocked_mask, cancel);
+  sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
+
+  /* ... except during a sigsuspend.  */
+  sigdelset (&suspend_mask, cancel);
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]