From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29244 invoked by alias); 12 Nov 2007 02:07:21 -0000 Received: (qmail 28337 invoked by uid 22791); 12 Nov 2007 02:07:19 -0000 X-Spam-Check-By: sourceware.org Received: from nf-out-0910.google.com (HELO nf-out-0910.google.com) (64.233.182.190) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 12 Nov 2007 02:07:16 +0000 Received: by nf-out-0910.google.com with SMTP id b11so888416nfh for ; Sun, 11 Nov 2007 18:07:15 -0800 (PST) Received: by 10.86.60.7 with SMTP id i7mr4104893fga.1194833235362; Sun, 11 Nov 2007 18:07:15 -0800 (PST) Received: from ?192.168.0.4? ( [62.169.107.97]) by mx.google.com with ESMTPS id h4sm5845471nfh.2007.11.11.18.07.12 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sun, 11 Nov 2007 18:07:14 -0800 (PST) Message-ID: <4737B553.2040302@portugalmail.pt> Date: Mon, 12 Nov 2007 02:07:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.1.6) Gecko/20070728 Thunderbird/2.0.0.6 Mnenhy/0.7.5.0 MIME-Version: 1.0 To: gdb-patches@sourceware.org, Lerele Subject: [gdbserver/win32] (4/11) New interrupting method Content-Type: multipart/mixed; boundary="------------030904050801030603020401" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2007-11/txt/msg00217.txt.bz2 This is a multi-part message in MIME format. --------------030904050801030603020401 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 720 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 --------------030904050801030603020401 Content-Type: text/x-diff; name="soft_interrupt.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="soft_interrupt.diff" Content-length: 5704 2007-11-12 Leo Zayas Pedro Alves * 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 * --------------030904050801030603020401--