Previously, sig thread ran in THREAD_PRIORITY_HIGHEST priority.
This caused critical delay in signal handling in the main thread
if the too many signales are received rapidly and CPU is very busy.
I this case, most of CPU time is allocated to sig thread, so the
main thread cannot have a chance to handle signals. With this patch,
the sig thread priority is set to the same priority with main thread
to avoid such situation. Furthermore, if the signal is alarted to
the main thread, but main thread does not handle it yet, in order to
increase the chance to handle it in the main thread, reduce the sig
thread priority is to THREAD_PRIORITY_LOWEST temporarily.

Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html
Fixes: 53ad6f1394aa ("(cygthread::cygthread): Use three only arguments for 
detached threads, and start the thread via QueueUserAPC/async_create.")
Reported-by: Christian Franke <christian.fra...@t-online.de>
Reviewed-by:
Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp>
---
 winsup/cygwin/sigproc.cc | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index b8d961a07..fc4360951 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -1319,6 +1319,23 @@ wait_sig (VOID *)
     {
       DWORD nb;
       sigpacket pack = {};
+      /* Follow to the main thread priority */
+      int prio = THREAD_PRIORITY_NORMAL;
+      if (cygwin_finished_initializing)
+       {
+         HANDLE h_main_thread = NULL;
+         threadlist_t *tl_entry = cygheap->find_tls (_main_tls);
+         if (_main_tls->thread_id)
+           h_main_thread = OpenThread (THREAD_QUERY_INFORMATION,
+                                       FALSE, _main_tls->thread_id);
+         cygheap->unlock_tls (tl_entry);
+         if (h_main_thread)
+           {
+             prio = GetThreadPriority (h_main_thread);
+             CloseHandle (h_main_thread);
+           }
+       }
+      SetThreadPriority (GetCurrentThread (), prio);
       if (sigq.retry)
        pack.si.si_signo = __SIGFLUSH;
       else if (sigq.start.next
@@ -1331,6 +1348,15 @@ wait_sig (VOID *)
          system_printf ("garbled signal pipe data nb %u, sig %d", nb, 
pack.si.si_signo);
          continue;
        }
+      if (cygwin_finished_initializing)
+       {
+         threadlist_t *tl_entry = cygheap->find_tls (_main_tls);
+         if (_main_tls->current_sig)
+           /* Decrease the priority in order to make main thread process
+              this signal. */
+           SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_LOWEST);
+         cygheap->unlock_tls (tl_entry);
+       }
 
       sigq.retry = false;
       /* Don't process signals when we start exiting */
-- 
2.45.1

Reply via email to