From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15662 invoked by alias); 3 Dec 2007 03:54:17 -0000 Received: (qmail 15652 invoked by uid 22791); 3 Dec 2007 03:54:16 -0000 X-Spam-Check-By: sourceware.org Received: from ug-out-1314.google.com (HELO ug-out-1314.google.com) (66.249.92.174) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 03 Dec 2007 03:54:09 +0000 Received: by ug-out-1314.google.com with SMTP id h2so2011803ugf for ; Sun, 02 Dec 2007 19:54:09 -0800 (PST) Received: by 10.67.116.2 with SMTP id t2mr3183017ugm.1196654048206; Sun, 02 Dec 2007 19:54:08 -0800 (PST) Received: from ?78.130.100.26? ( [78.130.100.26]) by mx.google.com with ESMTPS id 24sm6756146ugf.2007.12.02.19.54.05 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sun, 02 Dec 2007 19:54:07 -0800 (PST) Message-ID: <47536DE2.7040802@portugalmail.pt> Date: Mon, 03 Dec 2007 03:54:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.8.1.9) Gecko/20071031 Thunderbird/2.0.0.9 Mnenhy/0.7.5.0 MIME-Version: 1.0 To: gdb-patches@sourceware.org, Lerele Subject: Re: [gdbserver/win32] (5/11) New interrupting method : elevating the priority References: <4737B563.4070909@portugalmail.pt> <20071201185809.GD24231@caradoc.them.org> In-Reply-To: <20071201185809.GD24231@caradoc.them.org> Content-Type: multipart/mixed; boundary="------------050604090605020106040802" 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-12/txt/msg00042.txt.bz2 This is a multi-part message in MIME format. --------------050604090605020106040802 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1297 Daniel Jacobowitz wrote: > On Mon, Nov 12, 2007 at 02:07:31AM +0000, Pedro Alves wrote: >> 2007-11-12 Leo Zayas >> Pedro Alves >> >> * 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 --------------050604090605020106040802 Content-Type: text/x-diff; name="gdbserver_priority.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gdbserver_priority.diff" Content-length: 8433 2007-12-03 Leo Zayas Pedro Alves * 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. */ --------------050604090605020106040802--