Index: ChangeLog
authorAndrew Cagney <cagney@redhat.com>
Mon, 24 Jan 2005 22:00:59 +0000 (22:00 +0000)
committerAndrew Cagney <cagney@redhat.com>
Mon, 24 Jan 2005 22:00:59 +0000 (22:00 +0000)
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.

gdb/ChangeLog
gdb/infrun.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/sigrepeat.c [new file with mode: 0644]
gdb/testsuite/gdb.base/sigrepeat.exp [new file with mode: 0644]

index a861d2dcc093443bb841af178708bb8bf6f539a4..31f5253d5521ee461aab00090f1bfa6fe6fa58a7 100644 (file)
@@ -1,3 +1,9 @@
+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.
+
 2005-01-24  Andrew Cagney  <cagney@gnu.org>
 
        * configure: Regenerate, ../gettext.m4 was updated.
index 1f188df388f37448dac8fa0e92ecf5f51a4a008e..dd32590f785e6c35984e0da569ae1ae987f8315c 100644 (file)
@@ -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 4f0ca7c63544e7ecbf0ee82721b83d9463c28838..465dcd1db4cc432ea1ccc7a072b368d1bf6b46b0 100644 (file)
@@ -1,3 +1,7 @@
+2005-01-24  Andrew Cagney  <cagney@gnu.org>
+
+       * gdb.base/sigrepeat.exp, gdb.base/sigrepeat.c: New test.
+
 2005-01-19  Andrew Cagney  <cagney@gnu.org>
 
        * gdb.stabs/Makefile.in (Makefile): Update dependencies -
diff --git a/gdb/testsuite/gdb.base/sigrepeat.c b/gdb/testsuite/gdb.base/sigrepeat.c
new file mode 100644 (file)
index 0000000..a21486d
--- /dev/null
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.base/sigrepeat.exp b/gdb/testsuite/gdb.base/sigrepeat.exp
new file mode 100644 (file)
index 0000000..7abe68f
--- /dev/null
@@ -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;.*"