Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
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.  */

  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