diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index e822c1994..c1cfa4324 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,13 @@ +2011-07-06 Christopher Faylor + + * exceptions.cc (CALL_HANDLER_RETRY_INNER): Rename to reflect different + functionality. + (CALL_HANDLER_RETRY_OUTER): New define. + (setup_handler): Add outer loop to signal handler to try harder to + deliver the signal. + * miscfuncs.cc (yield): Drop priority and use SleepEx() to force thread + rescheduling rather than relying on SwitchToThread(). + 2011-07-06 Corinna Vinschen * sigproc.cc (wait_sig): Fix debug output. diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 5d4acf033..638c6e3b8 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -32,7 +32,8 @@ details. */ #include "ntdll.h" #include "exception.h" -#define CALL_HANDLER_RETRY 20 +#define CALL_HANDLER_RETRY_OUTER 10 +#define CALL_HANDLER_RETRY_INNER 10 char debugger_command[2 * NT_MAX_PATH + 20]; @@ -848,52 +849,54 @@ setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls) goto out; } - for (int i = 0; i < CALL_HANDLER_RETRY; i++) + for (int n = 0; n < CALL_HANDLER_RETRY_OUTER; n++) { - tls->lock (); - if (tls->incyg) + for (int i = 0; i < CALL_HANDLER_RETRY_INNER; i++) { - sigproc_printf ("controlled interrupt. stackptr %p, stack %p, stackptr[-1] %p", - tls->stackptr, tls->stack, tls->stackptr[-1]); - tls->interrupt_setup (sig, handler, siga); - interrupted = true; + tls->lock (); + if (tls->incyg) + { + sigproc_printf ("controlled interrupt. stackptr %p, stack %p, stackptr[-1] %p", + tls->stackptr, tls->stack, tls->stackptr[-1]); + tls->interrupt_setup (sig, handler, siga); + interrupted = true; + tls->unlock (); + break; + } + + DWORD res; + HANDLE hth = (HANDLE) *tls; + + /* Suspend the thread which will receive the signal. + If one of these conditions is not true we loop. + If the thread is already suspended (which can occur when a program + has called SuspendThread on itself) then just queue the signal. */ + + sigproc_printf ("suspending thread"); + res = SuspendThread (hth); + /* Just set pending if thread is already suspended */ + if (res) + { + ResumeThread (hth); + goto out; + } + cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext (hth, &cx)) + system_printf ("couldn't get context of thread, %E"); + else + interrupted = tls->interrupt_now (&cx, sig, handler, siga); + tls->unlock (); - break; + res = ResumeThread (hth); + if (interrupted) + goto out; + + sigproc_printf ("couldn't interrupt. trying again."); + yield (); } - - DWORD res; - HANDLE hth = (HANDLE) *tls; - - /* Suspend the thread which will receive the signal. - For Windows 95, we also have to ensure that the addresses returned by - GetThreadContext are valid. - 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 has called - SuspendThread on itself) then just queue the signal. */ - - sigproc_printf ("suspending thread"); - res = SuspendThread (hth); - /* Just set pending if thread is already suspended */ - if (res) - { - ResumeThread (hth); - break; - } - cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - if (!GetThreadContext (hth, &cx)) - system_printf ("couldn't get context of thread, %E"); - else - interrupted = tls->interrupt_now (&cx, sig, handler, siga); - - tls->unlock (); - res = ResumeThread (hth); - if (interrupted) - break; - - sigproc_printf ("couldn't interrupt. trying again."); - yield (); + /* Hit here if we couldn't deliver the signal. Take a more drastic + action before trying again. */ + Sleep (1); } out: diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 0ac25f4c3..d293edea9 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -235,11 +235,21 @@ check_iovec (const struct iovec *iov, int iovcnt, bool forwrite) return (ssize_t) tot; } +/* Try hard to schedule another thread. */ void yield () { - for (int i = 0; i < 3; i++) - SwitchToThread (); + for (int i = 0; i < 2; i++) + { + int prio = GetThreadPriority (GetCurrentThread ()); + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE); + /* MSDN implies that SleepEx(0,...) will force scheduling of other + threads. Unlike SwitchToThread() the documentation does not mention + other cpus so, presumably (hah!), this + using a lower priority will + stall this thread temporarily and cause another to run. */ + SleepEx (0, false); + SetThreadPriority (GetCurrentThread (), prio); + } } /* Get a default value for the nice factor. When changing these values,