This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [gdbserver/win32] (5/11) New interrupting method : elevating the priority


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

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.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]