Allow user to choose whether to use SIGSTOP or SIGINT to interrupt inferior process

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Allow user to choose whether to use SIGSTOP or SIGINT to interrupt inferior process

Kevin Buettner
The patch below restores SIGINT as the default signal used to (attempt
to) interrupt an inferior process.  It also adds a pair of monitor
commands for switching from the use of SIGINT to SIGSTOP and vice
versa.  On the first attempt to interrupt with either type of signal,
a brief message is displayed explaining the shortcomings of using that
particular signal.

In a nutshell, SIGINT can be friendlier in that it allows you to
continue by simply using GDB's "continue" command from GDB.  However, it
can be blocked or ignored by the process.  SIGSTOP can't be blocked or
ignored, but you must continue by either using "signal 0" or via "continue"
with the SIGSTOP behavior set ahead of time.

Kevin

2009-11-30  Kevin Buettner  <[hidden email]>

        * diagnostics.h, diagnostics.c (print_sigint_message): New function.
        * linux-target.c (linux_process_rcmd): Add monitor commands
        "interrupt-with-SIGSTOP and interrupt-with-SIGINT".
        * server.h (struct child_process): Add new field
        interrupt_with_SIGSTOP.
        * thread-db.c (thread_db_break_program): Interrupt using either
        SIGSTOP or SIGINT depending upon user's preference.

Index: unix/diagnostics.c
===================================================================
RCS file: /cvs/src/src/rda/unix/diagnostics.c,v
retrieving revision 1.1
diff -u -p -r1.1 diagnostics.c
--- unix/diagnostics.c 7 Dec 2005 17:51:48 -0000 1.1
+++ unix/diagnostics.c 30 Nov 2009 23:23:01 -0000
@@ -54,3 +54,21 @@ print_sigstop_message (struct gdbserv *s
     }
 }
 
+/* Print out a helpful message regarding SIGINT to the GDB console using
+   an "O" packet.  This message will be printed at most once per session.  */
+void
+print_sigint_message (struct gdbserv *serv)
+{
+  static int once = 0;
+
+  if (!once)
+    {
+      output_O_packet (serv, "\n"
+      "RDA has sent SIGINT to the inferior process.  If the process does not\n"
+      "stop in a timely fashion, it is possible that SIGINT is being blocked.\n"
+      "If that's the case, consider using SIGSTOP to interrupt the process\n"
+      "instead.  The monitor command \"monitor interrupt-with-SIGSTOP\" may\n"
+      "be used to turn on RDA's internal flag for effecting this behavior.\n");
+      once = 1;
+    }
+}
Index: unix/diagnostics.h
===================================================================
RCS file: /cvs/src/src/rda/unix/diagnostics.h,v
retrieving revision 1.2
diff -u -p -r1.2 diagnostics.h
--- unix/diagnostics.h 7 Dec 2005 17:51:48 -0000 1.2
+++ unix/diagnostics.h 30 Nov 2009 23:23:01 -0000
@@ -39,3 +39,8 @@ void output_O_packet (struct gdbserv *se
    an "O" packet.  This message will only be printed at most once per
    session.  */
 void print_sigstop_message (struct gdbserv *serv);
+
+/* Print out a helpful message regarding SIGINT to the GDB console using
+   an "O" packet.  This message will only be printed at most once per
+   session.  */
+void print_sigint_message (struct gdbserv *serv);
Index: unix/linux-target.c
===================================================================
RCS file: /cvs/src/src/rda/unix/linux-target.c,v
retrieving revision 1.24
diff -u -p -r1.24 linux-target.c
--- unix/linux-target.c 9 Apr 2007 22:39:03 -0000 1.24
+++ unix/linux-target.c 30 Nov 2009 23:23:01 -0000
@@ -3151,6 +3151,18 @@ linux_process_rcmd (struct gdbserv *serv
       debug_lwp_pool = 0;
       gdbserv_output_string_as_bytes (serv, "All RDA diagnostics disabled.\n");
     }
+  else if (strcmp (cmd, "interrupt-with-SIGSTOP") == 0)
+    {
+      process->interrupt_with_SIGSTOP = 1;
+      gdbserv_output_string_as_bytes (serv,
+        "RDA will use SIGSTOP to perform user requested interrupts.\n");
+    }
+  else if (strcmp (cmd, "interrupt-with-SIGINT") == 0)
+    {
+      process->interrupt_with_SIGSTOP = 0;
+      gdbserv_output_string_as_bytes (serv,
+        "RDA will use SIGINT to perform user requested interrupts.\n");
+    }
   else
     gdbserv_output_string_as_bytes (serv,
       "Unrecognized monitor command.\n"
@@ -3162,7 +3174,9 @@ linux_process_rcmd (struct gdbserv *serv
       "  monitor thread-db-noisy\n"
       "  monitor thread-db-quiet\n"
       "  monitor lwp-pool-noisy\n"
-      "  monitor lwp-pool-quiet\n");
+      "  monitor lwp-pool-quiet\n"
+      "  monitor interrupt-with-SIGSTOP\n"
+      "  monitor interrupt-with-SIGINT\n");
 }
 
 /* This function is called from gdbloop_poll when a new incoming
Index: unix/server.h
===================================================================
RCS file: /cvs/src/src/rda/unix/server.h,v
retrieving revision 1.5
diff -u -p -r1.5 server.h
--- unix/server.h 3 Oct 2006 22:49:05 -0000 1.5
+++ unix/server.h 30 Nov 2009 23:23:01 -0000
@@ -69,6 +69,7 @@ struct child_process {
   long signal_to_send;
   int  debug_backend;
   int  debug_informational;
+  int  interrupt_with_SIGSTOP;
   int  running;
   
 #if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET)
Index: unix/thread-db.c
===================================================================
RCS file: /cvs/src/src/rda/unix/thread-db.c,v
retrieving revision 1.19
diff -u -p -r1.19 thread-db.c
--- unix/thread-db.c 7 Dec 2005 17:51:48 -0000 1.19
+++ unix/thread-db.c 30 Nov 2009 23:23:01 -0000
@@ -2074,18 +2074,35 @@ thread_db_break_program (struct gdbserv
   /* We always send the signal to the main thread.  It's not correct
      to use process->pid; that's whatever thread last reported a
      status, and it may well have been exiting.
+    
+     We send either SIGSTOP or SIGINT depending upon user preference -
+     a GDB monitor command may be used to change the signal used.  SIGINT
+     has the advantage of allowing the user to continue in the usual
+     manner via GDB's continue command.  SIGSTOP may be preferred in some
+     settings because it cannot be blocked or ignored.  When SIGSTOP is
+     used, it is slightly more difficult to continue without sending
+     another SISSTOP.  */
+
+  if (process->interrupt_with_SIGSTOP)
+    {
+      if (process->debug_backend)
+ fprintf (stderr, " -- send SIGSTOP to child %d\n", proc_handle.pid);
+
+      /* Tell the GDB user that SIGSTOP has been sent to the inferior.  */
+      print_sigstop_message (serv);
 
-     We send SIGSTOP, rather than some other signal such as SIGINT,
-     because SIGSTOP cannot be blocked or ignored.  On Linux, using
-     a signal that can be blocked means that the process never gets
-     interrupted, since it's the kernel which does the blocking.  */
-  if (process->debug_backend)
-    fprintf (stderr, " -- send SIGSTOP to child %d\n", proc_handle.pid);
+      kill (proc_handle.pid, SIGSTOP);
+    }
+  else
+    {
+      if (process->debug_backend)
+ fprintf (stderr, " -- send SIGINT to child %d\n", proc_handle.pid);
 
-  /* Tell the GDB user that SIGSTOP has been sent to the inferior.  */
-  print_sigstop_message (serv);
+      /* Tell the GDB user that SIGINT has been sent to the inferior.  */
+      print_sigint_message (serv);
 
-  kill (proc_handle.pid, SIGSTOP);
+      kill (proc_handle.pid, SIGINT);
+    }
 }
 
 /* Function: check_child_state