From: Pedro Alves <pedro_alves@portugalmail.pt>
To: gdb-patches@sourceware.org
Subject: [win32] Fix suspend count handling
Date: Wed, 21 Nov 2007 00:35:00 -0000 [thread overview]
Message-ID: <47437D3A.3000107@portugalmail.pt> (raw)
[-- Attachment #1: Type: text/plain, Size: 2945 bytes --]
Hi,
This patch fixes a problem that was originally reported against
gdbserver/win32, which is also present on a native win32 debugger.
The gdbserver patch is here:
[gdbserver/win32] (3/11) Fix suspend count handling
http://sourceware.org/ml/gdb-patches/2007-11/msg00216.html
Let me re-describe the problem:
The current suspend_count handling breaks applications that use
SuspendThread on their own threads. The SuspendThread function
suspends a thread and returns its previous suspend count.
If a thread was already suspended by the debuggee, say, 3
times, gdb will do one SuspendThread call more (in thread_rec),
bringing the suspend_count to 4. Later, when the inferior
is being resumed, gdb will call ResumeThread suspend_count
times, in this case 4 times, which will leave a thread
running, while the debuggee wanted it to be suspended (with
a suspend count of 3).
This patch fixes it by turning the suspend_count counter
into a suspended flag that records if gdb itself has
suspended the thread. Gdb will then only call SuspendThread
on a thread if it hasn't already, and will only call Resume
thread if it has called SuspendThread itself.
Here is a test that shows the problem:
>cat ~/suspendfix/main.c
#include <windows.h>
HANDLE started;
HANDLE stop;
DWORD WINAPI
thread_start (void *arg)
{
SetEvent (started);
WaitForSingleObject (stop, INFINITE);
return 0;
}
int
main (int argc, char **argv)
{
int i;
DWORD suspend_count;
started = CreateEvent (NULL, TRUE, FALSE, NULL);
stop = CreateEvent (NULL, TRUE, FALSE, NULL);
HANDLE h = CreateThread (NULL, 0, thread_start, NULL,
0, NULL);
WaitForSingleObject (started, INFINITE);
for (i = 0; i < 3; i++)
if (SuspendThread (h) == (DWORD) -1)
{
printf ("SuspendThreadFailed\n");
return 1;
}
suspend_count = ResumeThread (h); /* set breakpoint here */
printf ("%lu\n", suspend_count); /* should be 3 */
while ((suspend_count = ResumeThread (h)) != 0
&& suspend_count != -1)
;
SetEvent (stop);
WaitForSingleObject (h, INFINITE);
CloseHandle (h);
CloseHandle (started);
CloseHandle (stop);
return 0;
}
Set a breakpoint where it reads "set breakpoint here", switch to the
other thread with "thread 2", effectivelly forcing a thread_rec
call, which calls SuspendThread, and sets suspend_count. Go back to
thread 1, and advance to the printf call. The suspend_count will be
0, instead of the expected 3.
I've asked this on the gdbserver mail, but let me re-ask it,
because I haven't done that work yet :-):
I have yet to turn this into a proper gdb test. Is that
wanted? Where shall I put it? gdb.base? gdb.thread? other?
No regressions on i686-pc-cygwin.
Cheers,
Pedro Alves
[-- Attachment #2: nat_suspend_count_fix.diff --]
[-- Type: text/x-diff, Size: 2936 bytes --]
2007-11-21 Pedro Alves <pedro_alves@portugalmail.pt>
* win32-nat.c (thread_info_struct): Rename suspend_count to
suspended, to be used as a flag.
(thread_rec): Only suspend the thread if it wasn't suspended by
gdb before. Warn if suspending failed.
(win32_continue): Update usage of the `suspended' flag.
---
gdb/win32-nat.c | 33 +++++++++++++++++++++------------
1 file changed, 21 insertions(+), 12 deletions(-)
Index: src/gdb/win32-nat.c
===================================================================
--- src.orig/gdb/win32-nat.c 2007-11-11 23:13:04.000000000 +0000
+++ src/gdb/win32-nat.c 2007-11-12 22:35:26.000000000 +0000
@@ -112,14 +112,14 @@ static enum target_signal last_sig = TAR
/* Set if a signal was received from the debugged process */
/* Thread information structure used to track information that is
- not available in gdb's thread structure. */
+ not available in gdb's thread structure. */
typedef struct thread_info_struct
{
struct thread_info_struct *next;
DWORD id;
HANDLE h;
char *name;
- int suspend_count;
+ int suspended;
int reload_context;
CONTEXT context;
STACKFRAME sf;
@@ -244,9 +244,10 @@ check (BOOL ok, const char *file, int li
GetLastError ());
}
-/* Find a thread record given a thread id.
- If get_context then also retrieve the context for this
- thread. */
+/* Find a thread record given a thread id passed in ID. If
+ GET_CONTEXT is not 0, then also retrieve the context for this
+ thread. If GET_CONTEXT is negative, then don't suspend the
+ thread. */
static thread_info *
thread_rec (DWORD id, int get_context)
{
@@ -255,12 +256,21 @@ thread_rec (DWORD id, int get_context)
for (th = &thread_head; (th = th->next) != NULL;)
if (th->id == id)
{
- if (!th->suspend_count && get_context)
+ if (!th->suspended && get_context)
{
if (get_context > 0 && id != current_event.dwThreadId)
- th->suspend_count = SuspendThread (th->h) + 1;
+ {
+ if (SuspendThread (th->h) == (DWORD) -1)
+ {
+ DWORD err = GetLastError ();
+ warning (_("SuspendThread failed. (winerr %d)"),
+ (int) err);
+ return NULL;
+ }
+ th->suspended = 1;
+ }
else if (get_context < 0)
- th->suspend_count = -1;
+ th->suspended = -1;
th->reload_context = 1;
}
return th;
@@ -1127,12 +1137,11 @@ win32_continue (DWORD continue_status, i
continue_status);
if (res)
for (th = &thread_head; (th = th->next) != NULL;)
- if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
+ if (((id == -1) || (id == (int) th->id)) && th->suspended)
{
-
- for (i = 0; i < th->suspend_count; i++)
+ if (th->suspended > 0)
(void) ResumeThread (th->h);
- th->suspend_count = 0;
+ th->suspended = 0;
if (debug_registers_changed)
{
/* Only change the value of the debug registers */
next reply other threads:[~2007-11-21 0:35 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-21 0:35 Pedro Alves [this message]
2007-11-21 11:25 ` Pierre Muller
2007-11-21 13:43 ` Pedro Alves
2007-11-21 14:13 ` Pierre Muller
2007-11-21 15:08 ` Pedro Alves
2007-11-21 15:32 ` Pierre Muller
2007-11-21 18:19 ` Pedro Alves
2007-11-21 23:33 ` Pedro Alves
2007-11-22 9:19 ` Pierre Muller
2007-11-23 1:07 ` Christopher Faylor
2007-11-23 10:19 ` Lerele
2007-11-23 18:30 ` Lerele
2007-11-24 12:43 ` Pedro Alves
2007-11-24 14:21 ` Lerele
2007-11-24 5:33 ` Christopher Faylor
2007-11-24 14:18 ` Lerele
2007-11-24 15:49 ` Pedro Alves
2007-11-24 17:50 ` Lerele
2007-11-24 20:49 ` Christopher Faylor
2007-11-24 20:48 ` Christopher Faylor
2007-11-25 14:44 ` Lerele
2007-11-25 18:13 ` Christopher Faylor
2007-11-25 18:56 ` Pedro Alves
2007-11-25 22:05 ` Christopher Faylor
2007-11-25 22:13 ` Lerele
2007-11-25 20:34 ` Lerele
2007-11-24 12:16 ` Pedro Alves
2007-11-24 20:51 ` Christopher Faylor
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=47437D3A.3000107@portugalmail.pt \
--to=pedro_alves@portugalmail.pt \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox