From: Pedro Alves <pedro_alves@portugalmail.pt>
To: gdb-patches@sourceware.org, Lerele <lerele@champenstudios.com>
Subject: Re: [gdbserver/win32] (5/11) New interrupting method : elevating the priority
Date: Mon, 03 Dec 2007 03:54:00 -0000 [thread overview]
Message-ID: <47536DE2.7040802@portugalmail.pt> (raw)
In-Reply-To: <20071201185809.GD24231@caradoc.them.org>
[-- Attachment #1: Type: text/plain, Size: 1297 bytes --]
Daniel Jacobowitz wrote:
> On Mon, Nov 12, 2007 at 02:07:31AM +0000, Pedro Alves wrote:
>> 2007-11-12 Leo Zayas
>> Pedro Alves <pedro_alves@portugalmail.pt>
>>
>> * win32-low.c (winapi_SetProcessPriorityBoost)
>> (winapi_GetProcessPriorityBoost, winapi_SetProcessAffinityMask)
>> [!_WIN32_WCE]: New typedefs.
>> (interrupt_thread_event) [!_WIN32_WCE]: New global.
>> (consume_cpu_interrupt_thread) [!_WIN32_WCE]: New.
>> (realtime_execute) [!_WIN32_WCE]: New.
>> (winapi_CeSetThreadPriority, winapi_CeGetThreadPriority)
>> [_WIN32_WCE]: New typedefs.
>> (realtime_execute) [_WIN32_WCE]: New.
>> (do_continue_one_thread): New.
>> (child_continue): If continuing with a faked breakpoint, do the
>> thread resuming with higher priority, and don't call
>> ContinueDebugEvent.
>> (suspend_all_threads): New.
>> (fake_breakpoint_event): Do the thread suspending with higher
>> priority.
>
> I'm just going to have to trust you on this one. It looks fine.
>
Thank you.
I've checked the whole series in, except for this one and the next (6).
Leo, could you take a look at the attached patch? It's a
refresh against current cvs, with a minor tweak to minimize a
race in the previous version -- we were creating the threads
but not waiting for them to start.
--
Pedro Alves
[-- Attachment #2: gdbserver_priority.diff --]
[-- Type: text/x-diff, Size: 8433 bytes --]
2007-12-03 Leo Zayas
Pedro Alves <pedro_alves@portugalmail.pt>
* win32-low.c (winapi_SetProcessPriorityBoost)
(winapi_GetProcessPriorityBoost, winapi_SetProcessAffinityMask)
[!_WIN32_WCE]: New typedefs.
(interrupt_thread_event) [!_WIN32_WCE]: New global.
(consume_cpu_interrupt_thread) [!_WIN32_WCE]: New.
(realtime_execute) [!_WIN32_WCE]: New.
(winapi_CeSetThreadPriority, winapi_CeGetThreadPriority)
[_WIN32_WCE]: New typedefs.
(realtime_execute) [_WIN32_WCE]: New.
(do_continue_one_thread): New.
(child_continue): If continuing with a faked breakpoint, do the
thread resuming with higher priority, and don't call
ContinueDebugEvent.
(suspend_all_threads): New.
(fake_breakpoint_event): Do the thread suspending with higher
priority.
---
gdb/gdbserver/win32-low.c | 214 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 204 insertions(+), 10 deletions(-)
Index: src/gdb/gdbserver/win32-low.c
===================================================================
--- src.orig/gdb/gdbserver/win32-low.c 2007-12-03 01:42:20.000000000 +0000
+++ src/gdb/gdbserver/win32-low.c 2007-12-03 01:42:32.000000000 +0000
@@ -300,6 +300,175 @@ do_initial_child_stuff (DWORD pid)
(*the_low_target.initial_stuff) ();
}
+#ifndef _WIN32_WCE
+
+typedef BOOL WINAPI (*winapi_SetProcessPriorityBoost) (HANDLE, BOOL);
+typedef BOOL WINAPI (*winapi_GetProcessPriorityBoost) (HANDLE, PBOOL);
+typedef BOOL WINAPI (*winapi_SetProcessAffinityMask) (HANDLE, DWORD_PTR);
+
+static HANDLE interrupt_thread_event;
+
+/* Thread function that consumes cpu while interrupt code pauses child
+ threads. */
+static DWORD WINAPI
+consume_cpu_interrupt_thread (LPVOID data)
+{
+ HANDLE* ran = data;
+ SetEvent (*ran);
+ while (WaitForSingleObject (interrupt_thread_event, 0) != WAIT_OBJECT_0)
+ ;
+ return 0;
+}
+
+static void
+realtime_execute (void (*func) (void*), void *args)
+{
+ DWORD old_process_priority_class;
+ DWORD old_process_affinity_mask;
+ BOOL old_process_priority_boost;
+ DWORD system_affinity_mask;
+ HANDLE h;
+ SYSTEM_INFO sys_info;
+ HANDLE *threads = NULL;
+ HANDLE *events = NULL;
+ HMODULE dll;
+
+ winapi_SetProcessPriorityBoost SetProcessPriorityBoost;
+ winapi_GetProcessPriorityBoost GetProcessPriorityBoost;
+ winapi_SetProcessAffinityMask SetProcessAffinityMask;
+
+ dll = GetModuleHandle (_T("KERNEL32.DLL"));
+ SetProcessPriorityBoost = GETPROCADDRESS (dll, SetProcessPriorityBoost);
+ GetProcessPriorityBoost = GETPROCADDRESS (dll, GetProcessPriorityBoost);
+ SetProcessAffinityMask = GETPROCADDRESS (dll, SetProcessAffinityMask);
+
+ h = GetCurrentProcess ();
+
+ old_process_priority_class = GetPriorityClass (h);
+
+ /* Go real-time so we can pause child as atomically as possible. */
+ SetPriorityClass (h, REALTIME_PRIORITY_CLASS);
+
+ if (GetProcessPriorityBoost != NULL)
+ GetProcessPriorityBoost (h, &old_process_priority_boost);
+ if (SetProcessPriorityBoost != NULL)
+ SetProcessPriorityBoost (h, FALSE);
+
+ GetSystemInfo (&sys_info);
+
+ if (sys_info.dwNumberOfProcessors > 1)
+ {
+ int i;
+
+ GetProcessAffinityMask (h,
+ &old_process_affinity_mask,
+ &system_affinity_mask);
+
+ /* Set gdbserver to run on all CPUs. */
+ if (SetProcessAffinityMask != NULL)
+ SetProcessAffinityMask (h, system_affinity_mask);
+
+ /* manual reset */
+ interrupt_thread_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+
+ threads = alloca (sizeof (HANDLE) * (sys_info.dwNumberOfProcessors - 1));
+ events = alloca (sizeof (HANDLE) * (sys_info.dwNumberOfProcessors - 1));
+ for (i = 0; i < sys_info.dwNumberOfProcessors - 1; i++)
+ {
+ events[i] = CreateEvent (NULL, FALSE, FALSE, NULL);
+ threads[i] = CreateThread (NULL, 0, consume_cpu_interrupt_thread,
+ &events[i], 0, NULL);
+ }
+
+ /* wait all */
+ WaitForMultipleObjects(sys_info.dwNumberOfProcessors - 1,
+ events, TRUE, INFINITE);
+
+ for (i = 0; i < sys_info.dwNumberOfProcessors - 1; i++)
+ CloseHandle (events[i]);
+ }
+
+ /* Do the work. */
+ (*func) (args);
+
+ /* Revert the priorities. */
+ if (sys_info.dwNumberOfProcessors > 1)
+ {
+ int i;
+
+ /* Once paused, signal gdbserver secondary cpu-consumption threads
+ to terminate, wait for them to do so, and gracefully free all
+ synchronization objects. */
+ SetEvent (interrupt_thread_event);
+ WaitForMultipleObjects (sys_info.dwNumberOfProcessors - 1,
+ threads, TRUE, INFINITE);
+ for (i = 0; i < sys_info.dwNumberOfProcessors - 1; i++)
+ CloseHandle (threads[i]);
+ CloseHandle (interrupt_thread_event);
+
+ if (SetProcessAffinityMask != NULL)
+ SetProcessAffinityMask (h, old_process_affinity_mask);
+ }
+
+ /* Restore gdbserver Windows scheduling state. */
+ if (SetProcessPriorityBoost != NULL)
+ SetProcessPriorityBoost (h, old_process_priority_boost);
+ SetPriorityClass (h, old_process_priority_class);
+}
+
+#else
+
+typedef BOOL WINAPI (*winapi_CeSetThreadPriority) (HANDLE, int);
+typedef int WINAPI (*winapi_CeGetThreadPriority) (HANDLE);
+
+static void
+realtime_execute (void (*func) (void*), void *args)
+{
+ /* Windows CE (at least up to 6) does not support multi-processor.
+ Windows CE is a real-time operating system, with a fixed priority
+ scheduler. Each thread runs at particular priority level, and
+ the highest priority runnable thread is always the one that is
+ run. If there is more than one thread at that priority level,
+ they are run round-robin. */
+
+ HANDLE h = GetCurrentThread ();
+ int prio;
+
+ static HMODULE dll = NULL;
+ static winapi_CeSetThreadPriority CeSetThreadPriority = NULL;
+ static winapi_CeGetThreadPriority CeGetThreadPriority = NULL;
+
+ if (dll == NULL)
+ {
+ dll = GetModuleHandle (L"COREDLL.DLL");
+ CeSetThreadPriority = GETPROCADDRESS (dll, CeSetThreadPriority);
+ CeGetThreadPriority = GETPROCADDRESS (dll, CeGetThreadPriority);
+ }
+
+ if (CeSetThreadPriority != NULL)
+ {
+ prio = CeGetThreadPriority (h);
+ /* Highest priority below drivers. */
+ CeSetThreadPriority (h, 153);
+ }
+ else
+ {
+ prio = GetThreadPriority (h);
+ SetThreadPriority (h, THREAD_PRIORITY_TIME_CRITICAL);
+ }
+
+ /* Do the work. */
+ (*func) (args);
+
+ /* Revert the priority. */
+ if (CeSetThreadPriority != NULL)
+ CeSetThreadPriority (h, prio);
+ else
+ SetThreadPriority (h, prio);
+}
+
+#endif
+
/* Resume all artificially suspended threads if we are continuing
execution. */
static int
@@ -330,18 +499,37 @@ continue_one_thread (struct inferior_lis
return 0;
}
+static void
+do_continue_one_thread (void *args)
+{
+ int *thread_id_ptr = args;
+ find_inferior (&all_threads, continue_one_thread, thread_id_ptr);
+}
+
static BOOL
child_continue (DWORD continue_status, int 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;
+ if (faked_breakpoint)
+ {
+ realtime_execute (do_continue_one_thread, &thread_id);
+ faked_breakpoint = 0;
+ }
+ else
+ {
+ /* The inferior will only continue after the ContinueDebugEvent
+ call. */
+ find_inferior (&all_threads, continue_one_thread, &thread_id);
+
+ if (!ContinueDebugEvent (current_event.dwProcessId,
+ current_event.dwThreadId,
+ continue_status))
+ {
+ DWORD err = GetLastError ();
+ OUTMSG (("warning: ContinueDebugEvent failed in child_continue, "
+ "(error %d): %s\n", (int) err, strwinerror (err)));
+ return FALSE;
+ }
+ }
return TRUE;
}
@@ -1313,6 +1501,12 @@ suspend_one_thread (struct inferior_list
}
static void
+suspend_all_threads (void *data)
+{
+ for_each_inferior (&all_threads, suspend_one_thread);
+}
+
+static void
fake_breakpoint_event (void)
{
OUTMSG2(("fake_breakpoint_event\n"));
@@ -1325,7 +1519,7 @@ fake_breakpoint_event (void)
current_event.u.Exception.ExceptionRecord.ExceptionCode
= EXCEPTION_BREAKPOINT;
- for_each_inferior (&all_threads, suspend_one_thread);
+ realtime_execute (suspend_all_threads, NULL);
}
/* Get the next event from the child. */
next prev parent reply other threads:[~2007-12-03 3:54 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-12 2:07 Pedro Alves
2007-12-01 18:58 ` Daniel Jacobowitz
2007-12-03 3:54 ` Pedro Alves [this message]
2008-01-29 17:00 ` Daniel Jacobowitz
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=47536DE2.7040802@portugalmail.pt \
--to=pedro_alves@portugalmail.pt \
--cc=gdb-patches@sourceware.org \
--cc=lerele@champenstudios.com \
/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