This is the mail archive of the gdb-patches@sourceware.org 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]

[gdbserver/win32] (4/11) New interrupting method


Hi,

Here is the new method to stop the inferior, based on a mix of
Leo's and mine patches.  The idea is simple.  Loop through all
the inferior threads suspending them.

This version doesn't contain the gdbserver priority handling,
which means that there is a higher chance of the inferior
breaking the method, since the operation is not atomic.  For
example by tweaking its own thread's priorities or if the
inferior is calling ResumeThread in its own threads while
gdbserver is stopping them.

The next patch will minimize those chances, by elevating
gdbserver's priority while stopping the inferior with
this method.

Leo, did I miss anything?

Regtested on a local i686-pc-cygwin gdbserver.

Cheers,
Pedro Alves




2007-11-12  Leo Zayas  <lerele@champenstudios@com>
	    Pedro Alves  <pedro_alves@portugalmail.pt>

	* win32-low.c (soft_interrupt_requested, faked_breakpoint): New
	global variables.
	(child_add_thread): Minor cleanup.
	(child_continue): Resume artificially suspended threads before
	calling ContinueDebugEvent.
	(suspend_one_thread): New.
	(fake_breakpoint_event): New.
	(get_child_debug_event): Change return type to int.  Check here if
	gdb sent an interrupt request.  If a soft interrupt was
	requested, fake a breakpoint event.  Return 0 if there is no event
	to handle, and 1 otherwise.
	(win32_wait): Don't check here if gdb sent an interrupt request.
	Ensure there is a valid event to handle.
	(win32_request_interrupt): Add soft interruption method as last resort.

---
 gdb/gdbserver/win32-low.c |  100 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 79 insertions(+), 21 deletions(-)

Index: src/gdb/gdbserver/win32-low.c
===================================================================
--- src.orig/gdb/gdbserver/win32-low.c	2007-11-11 23:15:40.000000000 +0000
+++ src/gdb/gdbserver/win32-low.c	2007-11-11 23:15:44.000000000 +0000
@@ -72,6 +72,14 @@ static enum target_signal last_sig = TAR
 /* The current debug event from WaitForDebugEvent.  */
 static DEBUG_EVENT current_event;
 
+/* Non zero if an interrupt request is to be satisfied by suspending
+   all threads.  */
+static int soft_interrupt_requested = 0;
+
+/* Non zero if the inferior is stopped in a simulated breakpoint done
+   by suspending all the threads.  */
+static int faked_breakpoint = 0;
+
 #define NUM_REGS (the_low_target.num_regs)
 
 typedef BOOL WINAPI (*winapi_DebugActiveProcessStop) (DWORD dwProcessId);
@@ -134,8 +142,7 @@ child_add_thread (DWORD tid, HANDLE h)
   if ((th = thread_rec (tid, FALSE)))
     return th;
 
-  th = (win32_thread_info *) malloc (sizeof (*th));
-  memset (th, 0, sizeof (*th));
+  th = calloc (1, sizeof (*th));
   th->tid = tid;
   th->h = h;
 
@@ -293,14 +300,17 @@ continue_one_thread (struct inferior_lis
 static BOOL
 child_continue (DWORD continue_status, int thread_id)
 {
-  BOOL res;
-
-  res = ContinueDebugEvent (current_event.dwProcessId,
-			    current_event.dwThreadId, continue_status);
-  if (res)
-    find_inferior (&all_threads, continue_one_thread, &thread_id);
+  /* The inferior will only continue after the ContinueDebugEvent
+     call.  */
+  find_inferior (&all_threads, continue_one_thread, &thread_id);
+  faked_breakpoint = 0;
+
+  if (!ContinueDebugEvent (current_event.dwProcessId,
+			   current_event.dwThreadId,
+			   continue_status))
+    return FALSE;
 
-  return res;
+  return TRUE;
 }
 
 /* Fetch register(s) from the current thread context.  */
@@ -1247,19 +1257,67 @@ handle_exception (struct target_waitstat
   last_sig = ourstatus->value.sig;
 }
 
-/* Get the next event from the child.  */
+
 static void
-get_child_debug_event (struct target_waitstatus *ourstatus)
+suspend_one_thread (struct inferior_list_entry *entry)
+{
+  struct thread_info *thread = (struct thread_info *) entry;
+  win32_thread_info *th = inferior_target_data (thread);
+
+  if (!th->suspended)
+    {
+      if (SuspendThread (th->h) == (DWORD) -1)
+	{
+	  DWORD err = GetLastError ();
+	  OUTMSG (("warning: SuspendThread failed in suspend_one_thread, "
+		   "(error %d): %s\n", (int) err, strwinerror (err)));
+	}
+      else
+	th->suspended = 1;
+    }
+}
+
+static void
+fake_breakpoint_event (void)
 {
-  BOOL debug_event;
+  OUTMSG2(("fake_breakpoint_event\n"));
 
+  faked_breakpoint = 1;
+
+  memset (&current_event, 0, sizeof (current_event));
+  current_event.dwThreadId = main_thread_id;
+  current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
+  current_event.u.Exception.ExceptionRecord.ExceptionCode =
+    EXCEPTION_BREAKPOINT;
+
+  for_each_inferior (&all_threads, suspend_one_thread);
+}
+
+/* Get the next event from the child.  */
+
+static int
+get_child_debug_event (struct target_waitstatus *ourstatus)
+{
   last_sig = TARGET_SIGNAL_0;
   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
 
-  /* Keep the wait time low enough for confortable remote interruption,
-     but high enough so gdbserver doesn't become a bottleneck.  */
-  if (!(debug_event = WaitForDebugEvent (&current_event, 250)))
-    return;
+  /* Check if GDB sent us an interrupt request.  */
+  check_remote_input_interrupt_request ();
+
+  if (soft_interrupt_requested)
+    {
+      soft_interrupt_requested = 0;
+      fake_breakpoint_event ();
+      goto gotevent;
+    }
+
+  /* Keep the wait time low enough for confortable remote
+     interruption, but high enough so gdbserver doesn't become a
+     bottleneck.  */
+  if (!WaitForDebugEvent (&current_event, 250))
+    return 0;
+
+ gotevent:
 
   current_inferior =
     (struct thread_info *) find_inferior_id (&all_threads,
@@ -1376,6 +1434,7 @@ get_child_debug_event (struct target_wai
   current_inferior =
     (struct thread_info *) find_inferior_id (&all_threads,
 					     current_event.dwThreadId);
+  return 1;
 }
 
 /* Wait for the inferior process to change state.
@@ -1390,10 +1449,8 @@ win32_wait (char *status)
 
   while (1)
     {
-      /* Check if GDB sent us an interrupt request.  */
-      check_remote_input_interrupt_request ();
-
-      get_child_debug_event (&our_status);
+      if (!get_child_debug_event (&our_status))
+	continue;
 
       switch (our_status.kind)
 	{
@@ -1500,7 +1557,8 @@ win32_request_interrupt (void)
       && DebugBreakProcess (current_process_handle))
     return;
 
-  OUTMSG (("Could not interrupt process.\n"));
+  /* Last resort, suspend all threads manually.  */
+  soft_interrupt_requested = 1;
 }
 
 static const char *





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