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]
Other format: [Raw text]

[commit] Handle back-to-back signals


Hello,

The attached patch adds a new test - sigrepeat.exp - which checks what happens when a program is swamped with signals (no soon has the previous been handled when the next is delivered). In fact there are so many signals that the inferior makes no real progress and that leads to an internal error in infrun.c.

I've also fixed the internal error.

The testsuite fails before, passes after on i386 and PPC GNU/Linux.

committed,
Andrew
Index: ChangeLog
2005-01-24  Andrew Cagney  <cagney@gnu.org>

	* infrun.c (handle_inferior_event): Handle back-to-back and nested
	signals where the step_resume_breakpoint may have already been
	inserted.

Index: testsuite/ChangeLog
2005-01-24  Andrew Cagney  <cagney@gnu.org>

	* gdb.base/sigrepeat.exp, gdb.base/sigrepeat.c: New test.

Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.188
diff -p -u -r1.188 infrun.c
--- infrun.c	19 Jan 2005 16:09:46 -0000	1.188
+++ infrun.c	24 Jan 2005 21:54:23 -0000
@@ -1933,12 +1933,16 @@ process_event_stop_test:
 	     breakpoint.  */
 	  insert_step_resume_breakpoint_at_frame (get_current_frame ());
 	  ecs->step_after_step_resume_breakpoint = 1;
+	  keep_going (ecs);
+	  return;
 	}
-      else if (step_range_end != 0
-	       && stop_signal != TARGET_SIGNAL_0
-	       && stop_pc >= step_range_start && stop_pc < step_range_end
-	       && frame_id_eq (get_frame_id (get_current_frame ()),
-			       step_frame_id))
+
+      if (step_range_end != 0
+	  && stop_signal != TARGET_SIGNAL_0
+	  && stop_pc >= step_range_start && stop_pc < step_range_end
+	  && frame_id_eq (get_frame_id (get_current_frame ()),
+			  step_frame_id)
+	  && step_resume_breakpoint == NULL)
 	{
 	  /* The inferior is about to take a signal that will take it
 	     out of the single step range.  Set a breakpoint at the
@@ -1950,7 +1954,16 @@ process_event_stop_test:
 	     while in the single-step range.  Nested signals aren't a
 	     problem as they eventually all return.  */
 	  insert_step_resume_breakpoint_at_frame (get_current_frame ());
+	  keep_going (ecs);
+	  return;
 	}
+
+      /* Note: step_resume_breakpoint may be non-NULL.  This occures
+	 when either there's a nested signal, or when there's a
+	 pending signal enabled just as the signal handler returns
+	 (leaving the inferior at the step-resume-breakpoint without
+	 actually executing it).  Either way continue until the
+	 breakpoint is really hit.  */
       keep_going (ecs);
       return;
     }
Index: testsuite/gdb.base/sigrepeat.c
===================================================================
RCS file: testsuite/gdb.base/sigrepeat.c
diff -N testsuite/gdb.base/sigrepeat.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/sigrepeat.c	24 Jan 2005 21:54:24 -0000
@@ -0,0 +1,104 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2004, 2005 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+ 
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+
+static volatile int done[2];
+static volatile int repeats[2];
+static int itimer[2] = { ITIMER_REAL, ITIMER_VIRTUAL };
+static int alarm[2] = { SIGALRM, SIGVTALRM };
+
+static void
+handler (int sig)
+{
+  int sigi;
+  switch (sig)
+    {
+    case SIGALRM: sigi = 0; break;
+    case SIGVTALRM: sigi = 1; break;
+    default: abort ();
+    }
+  if (repeats[sigi]++ > 3)
+    {
+      /* Hit with enough signals, cancel everything and get out.  */
+      {
+	struct itimerval itime;
+	memset (&itime, 0, sizeof (itime));
+	setitimer (itimer[sigi], &itime, NULL);
+      }
+      {
+	struct sigaction action;
+	memset (&action, 0, sizeof (action));
+	action.sa_handler = SIG_IGN;
+	sigaction (sig, &action, NULL);
+      }
+      done[sigi] = 1;
+      return;
+    }
+  /* Set up a nested virtual timer.  */
+  while (1)
+    {
+      /* Wait until a signal has become pending, that way when this
+	 handler returns it will be immediatly delivered leading to
+	 back-to-back signals.  */
+      sigset_t set;
+      sigemptyset (&set);
+      if (sigpending (&set) < 0)
+	{
+	  perror ("sigrepeat");
+	  abort ();
+	}
+      if (sigismember (&set, sig))
+	break;
+    }
+} /* handler */
+
+main ()
+{
+  int i;
+  /* Set up the signal handler.  */
+  for (i = 0; i < 2; i++)
+    {
+      struct sigaction action;
+      memset (&action, 0, sizeof (action));
+      action.sa_handler = handler;
+      sigaction (alarm[i], &action, NULL);
+    }
+
+  /* Set up a rapidly repeating timers.  A timer, rather than SIGSEGV,
+     is used as after a timer handler returns the interrupted code can
+     safely resume.  The intent is for the program to swamp GDB with a
+     backlog of pending signals.  */
+  for (i = 0; i < 2; i++)
+    {
+      struct itimerval itime;
+      memset (&itime, 0, sizeof (itime));
+      itime.it_interval.tv_usec = 1;
+      itime.it_value.tv_usec = 250 * 1000;
+      setitimer (itimer[i], &itime, NULL);
+    }
+
+  /* Wait.  */
+  while (!done[0] && !done[1]); /* infinite loop */
+  return 0;
+}
Index: testsuite/gdb.base/sigrepeat.exp
===================================================================
RCS file: testsuite/gdb.base/sigrepeat.exp
diff -N testsuite/gdb.base/sigrepeat.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/sigrepeat.exp	24 Jan 2005 21:54:24 -0000
@@ -0,0 +1,62 @@
+# Copyright 2004, 2005 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+
+# The program sigrepeat.c creates a repeating timer and then waits for
+# it to fire multiple times.  The objective is to create a backlog if
+# sigalrm signals and hence cause repeated signal delivery without any
+# cpu advancment.
+
+if [target_info exists gdb,nosignals] {
+    verbose "Skipping sigstep.exp because of nosignals."
+    continue
+}
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile sigrepeat
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    untested "Couldn't compile ${module}.c"
+    return -1
+}
+
+# get things started
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Advance to main
+if { ![runto_main] } then {
+    gdb_suppress_tests;
+}
+
+# Run to the signal handler wait loop.
+set infinite_loop [gdb_get_line_number {infinite loop}]
+gdb_test "advance $infinite_loop" "" "advance to infinite loop"
+
+# Make the first of many signals come pending
+sleep 1
+
+# Try to step off this line
+gdb_test "next" "return 0;.*"

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