Previously, the sig thread ran in THREAD_PRIORITY_HIGHEST priority.
This causes a critical delay in the signal handling in the main thread
if too many signals are received rapidly and the CPU is very busy.
In this case, most of the CPU time is allocated to the 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 as the main thread
to avoid such a situation. Furthermore, if the signal is alerted to
the main thread, but the main thread does not handle it yet, in order
to increase the chance of handling it in the main thread, reduce the
sig thread priority 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