From 13af9a149da1a97fc7845466ce652427a0765944 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Fri, 22 Nov 2002 04:43:47 +0000 Subject: * exceptions.cc (sigthread::get_winapi_lock): Just do standard 'give up timeslice' wait. (setup_handler): Revamp YA to attempt to deliver signal multiple times on failure rather than punting to wait_sig. * miscfuncs.cc (low_priority_sleep): Accept INFINITE sleep to mean "don't reset the priority after setting it to idle". Return previous priority. * winsup.h (SLEEP_0_STAY_LOW): Define. (low_priority_sleep): Return an int. * sigproc.h: Define WAIT_SIG_PRIORITY here. * sigproc.cc: Remove WAIT_SIG_PRIORITY definition. --- winsup/cygwin/ChangeLog | 14 ++++++ winsup/cygwin/exceptions.cc | 116 +++++++++++++++++++++++--------------------- winsup/cygwin/miscfuncs.cc | 19 +++++++- winsup/cygwin/signal.cc | 2 +- winsup/cygwin/sigproc.cc | 2 - winsup/cygwin/sigproc.h | 2 +- winsup/cygwin/winsup.h | 3 +- 7 files changed, 97 insertions(+), 61 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index e87d8c909..b0672ee00 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,17 @@ +2002-11-21 Christopher Faylor + + * exceptions.cc (sigthread::get_winapi_lock): Just do standard 'give up + timeslice' wait. + (setup_handler): Revamp YA to attempt to deliver signal multiple times + on failure rather than punting to wait_sig. + * miscfuncs.cc (low_priority_sleep): Accept INFINITE sleep to mean + "don't reset the priority after setting it to idle". Return previous + priority. + * winsup.h (SLEEP_0_STAY_LOW): Define. + (low_priority_sleep): Return an int. + * sigproc.h: Define WAIT_SIG_PRIORITY here. + * sigproc.cc: Remove WAIT_SIG_PRIORITY definition. + 2002-11-20 Pierre Humblet * security.h: Declare internal_getpwsid and internal_getgrsid. diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index ae868cc7c..b18c61f24 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -666,7 +666,7 @@ sigthread::get_winapi_lock (int test) /* Need to do a busy loop because we can't block or a potential SuspendThread will hang. */ while (InterlockedExchange (&winapi_lock, 1)) - low_priority_sleep (1); + low_priority_sleep (0); return 1; } @@ -782,26 +782,33 @@ static int setup_handler (int sig, void *handler, struct sigaction& siga) { CONTEXT cx; - bool interrupted = 0; - HANDLE hth = NULL; - int res; + bool interrupted = false; sigthread *th = NULL; // Initialization needed to shut up gcc + int prio = INFINITE; if (sigsave.sig) goto set_pending; - for (int i = 0; !interrupted && i < CALL_HANDLER_RETRY; i++) + for (int i = 0; i < CALL_HANDLER_RETRY; i++) { + DWORD res; + HANDLE hth; + EnterCriticalSection (&mainthread.lock); if (mainthread.frame) - th = &mainthread; + { + hth = NULL; + th = &mainthread; + } else { LeaveCriticalSection (&mainthread.lock); - th = NULL; + if (!mainthread.get_winapi_lock (1)) + continue; hth = myself->getthread2signal (); + th = NULL; /* Suspend the thread which will receive the signal. But first ensure that this thread doesn't have any mutos. (FIXME: Someday we should just grab @@ -811,20 +818,29 @@ setup_handler (int sig, void *handler, struct sigaction& siga) If one of these conditions is not true we loop for a fixed number of times since we don't want to stall the signal handler. FIXME: Will this result in noticeable delays? - If the thread is already suspended (which can occur when a program is stopped) then - just queue the signal. */ + If the thread is already suspended (which can occur when a program has called + SuspendThread on itself then just queue the signal. */ - if (!mainthread.get_winapi_lock (1)) - continue; + EnterCriticalSection (&mainthread.lock); sigproc_printf ("suspending mainthread"); res = SuspendThread (hth); - mainthread.release_winapi_lock (); - if (mainthread.frame) - goto resume_thread; /* In case the main thread *just* set the frame */ + /* Just release the lock now since we hav suspended the main thread and it + definitely can't be grabbing it now. This will have to change, of course, + if/when we can send signals to other than the main thread. */ + LeaveCriticalSection (&mainthread.lock); /* Just set pending if thread is already suspended */ if (res) - goto set_pending; + { + (void) ResumeThread (hth); + break; + } + + mainthread.release_winapi_lock (); + if (mainthread.frame) + goto resume_thread; /* We just got the frame. What are the odds? + Just loop and we'll hopefully pick it up on + the next pass through. */ muto *m; /* FIXME: Make multi-thread aware */ @@ -835,71 +851,63 @@ setup_handler (int sig, void *handler, struct sigaction& siga) goto resume_thread; } - EnterCriticalSection (&mainthread.lock); if (mainthread.frame) + th = &mainthread; + else { - th = &mainthread; - goto try_to_interrupt; + cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext (hth, &cx)) + { + system_printf ("couldn't get context of main thread, %E"); + goto resume_thread; + } } + } - LeaveCriticalSection (&mainthread.lock); - - cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - if (!GetThreadContext (hth, &cx)) - system_printf ("couldn't get context of main thread, %E"); - else if (!interruptible (cx.Eip, 1)) - sigproc_printf ("suspended thread in a strange state pc %p, sp %p", - cx.Eip, cx.Esp); - else - goto try_to_interrupt; - - resume_thread: - ResumeThread (hth); - low_priority_sleep (0); - continue; + if ((DWORD) prio != INFINITE) + { + /* Reset the priority so we can finish this off quickly. */ + SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); + prio = INFINITE; } - try_to_interrupt: if (th) { interrupted = interrupt_on_return (th, sig, handler, siga); LeaveCriticalSection (&th->lock); } else if (interruptible (cx.Eip)) - { - interrupted = interrupt_now (&cx, sig, handler, siga); -#ifdef DEBUGGING - if (!interrupted) - sigproc_printf ("couldn't deliver signal %d via %p", sig, cx.Eip); -#endif - } - else + interrupted = interrupt_now (&cx, sig, handler, siga); + + resume_thread: + if (hth) + res = ResumeThread (hth); + + if (interrupted) break; + + if ((DWORD) prio != INFINITE && !mainthread.frame) + prio = low_priority_sleep (SLEEP_0_STAY_LOW); + sigproc_printf ("couldn't interrupt. trying again."); } set_pending: if (interrupted) - res = 1; + { + if ((DWORD) prio != INFINITE) + SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); + sigproc_printf ("signal successfully delivered"); + } else { pending_signals = 1; /* FIXME: Probably need to be more tricky here */ sig_set_pending (sig); sig_dispatch_pending (1); - low_priority_sleep (0); /* Hopefully, other process will be waking up soon. */ + low_priority_sleep (SLEEP_0_STAY_LOW); /* Hopefully, other process will be waking up soon. */ sigproc_printf ("couldn't send signal %d", sig); } - if (!hth) - sigproc_printf ("good. Didn't suspend main thread, th %p", th); - else - { - res = ResumeThread (hth); - sigproc_printf ("ResumeThread returned %d", res); - } - sigproc_printf ("returning %d", interrupted); - if (pending_signals) - SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE); return interrupted; } #endif /* i386 */ diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 9c7ab5434..e58565942 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -292,12 +292,27 @@ sys_mbstowcs (WCHAR *tgt, const char *src, int len) return MultiByteToWideChar (get_cp (), 0, src, -1, tgt, len); } -void __stdcall +int __stdcall low_priority_sleep (DWORD secs) { HANDLE thisthread = GetCurrentThread (); int curr_prio = GetThreadPriority (thisthread); + bool staylow; + if (secs != INFINITE) + staylow = false; + else + { + secs = 0; + staylow = true; + } + + /* Force any threads in normal priority to be scheduled */ + SetThreadPriority (thisthread, THREAD_PRIORITY_NORMAL); + Sleep (0); + SetThreadPriority (thisthread, THREAD_PRIORITY_IDLE); Sleep (secs); - SetThreadPriority (thisthread, curr_prio); + if (!staylow) + SetThreadPriority (thisthread, curr_prio); + return curr_prio; } diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 9c807f4ef..010df9bf9 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -57,7 +57,7 @@ signal (int sig, _sig_func_ptr func) myself->getsig (sig).sa_handler = func; myself->getsig (sig).sa_mask = 0; /* SA_RESTART is set to maintain BSD compatible signal behaviour by default. - This is also compatible to the behaviour of signal(2) in Linux. */ + This is also compatible with the behaviour of signal(2) in Linux. */ myself->getsig (sig).sa_flags |= SA_RESTART; set_sigcatchers (prev, func); diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 5f4d4c07a..aeb51f264 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -41,8 +41,6 @@ details. */ #define WSPX 20000 // Wait for wait_sig to terminate #define WWSP 20000 // Wait for wait_subproc to terminate -#define WAIT_SIG_PRIORITY THREAD_PRIORITY_TIME_CRITICAL - #define TOTSIGS (NSIG + __SIGOFFSET) #define wake_wait_subproc() SetEvent (events[0]) diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index a461efdd6..c8c208e13 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -124,7 +124,7 @@ void __stdcall wait_for_sigthread (); extern char myself_nowait_dummy[]; extern char myself_nowait_nonmain_dummy[]; -#define WAIT_SIG_EXITING (WAIT_OBJECT_0 + 1) +#define WAIT_SIG_PRIORITY THREAD_PRIORITY_TIME_CRITICAL #define myself_nowait ((_pinfo *)myself_nowait_dummy) #define myself_nowait_nonmain ((_pinfo *)myself_nowait_nonmain_dummy) diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 9b7e04075..e46c0721a 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -242,7 +242,8 @@ extern void multiple_cygwin_problem (const char *, unsigned, unsigned); class path_conv; int __stdcall stat_worker (const char *name, struct __stat64 *buf, int nofollow, path_conv *pc = NULL) __attribute__ ((regparm (3))); -void __stdcall low_priority_sleep (DWORD) __attribute__ ((regparm (1))); +int __stdcall low_priority_sleep (DWORD) __attribute__ ((regparm (1))); +#define SLEEP_0_STAY_LOW INFINITE /**************************** Exports ******************************/ -- cgit v1.2.3