This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[gdbserver/win32] (4/11) New interrupting method
- From: Pedro Alves <pedro_alves at portugalmail dot pt>
- To: gdb-patches at sourceware dot org, Lerele <lerele at champenstudios dot com>
- Date: Mon, 12 Nov 2007 02:07:15 +0000
- Subject: [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 (¤t_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 (¤t_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 (¤t_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 *