https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=5fe1f223efc6919e550ce1650d57957b6851ff41

commit 5fe1f223efc6919e550ce1650d57957b6851ff41
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Mon Jun 23 20:25:25 2025 +0900

    Cygwin: signal: Do not suspend myself and use VEH
    
    After the commit f305ca916ad2, some stress-ng tests fail in arm64
    windows. There seems to be two causes for this issue. One is that
    calling SuspendThread(GetCurrentThread()) may suspend myself in
    the kernel. Branching to sigdelayed in the kernel code does not
    work as expected as the original _cygtls::interrup_now() intended.
    The other cause is, single step exception sometimes does not trigger
    exception::handle() for some reason. Therefore, register vectored
    exception handler (VEH) and use it for single step exception instead.
    
    Addresses: https://cygwin.com/pipermail/cygwin/2025-June/258332.html
    Fixes: f305ca916ad2 ("Cygwin: signal: Prevent unexpected crash on frequent 
SIGSEGV")
    Reported-by: Jeremy Drake <cyg...@jdrake.com>
    Reviewed-by: Corinna Vinschen <cori...@vinschen.de>
    Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp>
    (cherry picked from commit b0a9b628aad8dd35892b9da3511c434d9a61d37f)

Diff:
---
 winsup/cygwin/exceptions.cc           | 55 +++++++++++++++++++++++------------
 winsup/cygwin/local_includes/cygtls.h |  1 +
 winsup/cygwin/local_includes/ntdll.h  |  2 ++
 winsup/cygwin/release/3.6.4           |  3 ++
 4 files changed, 43 insertions(+), 18 deletions(-)

diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index a4699b172..f79978f73 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -653,13 +653,6 @@ exception::handle (EXCEPTION_RECORD *e, exception_list 
*frame, CONTEXT *in,
   static int NO_COPY debugging = 0;
   _cygtls& me = _my_tls;
 
-  if (me.suspend_on_exception)
-    {
-      SuspendThread (GetCurrentThread ());
-      if (e->ExceptionCode == (DWORD) STATUS_SINGLE_STEP)
-       return ExceptionContinueExecution;
-    }
-
   if (debugging && ++debugging < 500000)
     {
       SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
@@ -923,6 +916,24 @@ sig_handle_tty_stop (int sig, siginfo_t *, void *)
 }
 } /* end extern "C" */
 
+#ifdef __x86_64__
+static LONG CALLBACK
+singlestep_handler (EXCEPTION_POINTERS *ep)
+{
+  if (_my_tls.suspend_on_exception)
+    {
+      _my_tls.in_singlestep_handler = true;
+      RtlWakeAddressSingle ((void *) &_my_tls.in_singlestep_handler);
+      while (_my_tls.suspend_on_exception)
+       ; /* Don't call yield() to prevent the thread
+            from being suspended in the kernel. */
+      if (ep->ExceptionRecord->ExceptionCode == (DWORD) STATUS_SINGLE_STEP)
+       return EXCEPTION_CONTINUE_EXECUTION;
+    }
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif
+
 bool
 _cygtls::interrupt_now (CONTEXT *cx, siginfo_t& si, void *handler,
                        struct sigaction& siga)
@@ -942,28 +953,36 @@ _cygtls::interrupt_now (CONTEXT *cx, siginfo_t& si, void 
*handler,
         a crash. To prevent this, advance execution by a single instruction
         by setting the trap flag (TF) before calling ResumeThread(). This
         will trigger either STATUS_SINGLE_STEP or the exception caused by
-        the instruction that Rip originally pointed to.  By suspending the
-        targeted thread within exception::handle(), Rip no longer points
+        the instruction that Rip originally pointed to. By suspending the
+        targeted thread within singlestep_handler(), Rip no longer points
         to the problematic instruction, allowing safe handling of the
-        interrupt. As a result, Rip can be adjusted appropriately, and the
-        thread can resume execution without unexpected crashes.  */
+        interrupt.  As a result, Rip can be adjusted appropriately,
+        and the thread can resume execution without unexpected crashes. */
       if (!inside_kernel (cx, true))
        {
+         HANDLE h_veh = AddVectoredExceptionHandler (0, singlestep_handler);
          cx->EFlags |= 0x100; /* Set TF (setup single step execution) */
          SetThreadContext (*this, cx);
          suspend_on_exception = true;
+         in_singlestep_handler = false;
+         bool bool_false = false;
+         NTSTATUS status = STATUS_SUCCESS;
          ResumeThread (*this);
-         ULONG cnt = 0;
-         NTSTATUS status;
-         do
+         while (!in_singlestep_handler && NT_SUCCESS (status))
            {
-             yield ();
-             status = NtQueryInformationThread (*this, ThreadSuspendCount,
-                                                &cnt, sizeof (cnt), NULL);
+             LARGE_INTEGER timeout;
+             timeout.QuadPart = -100000ULL; /* 10ms */
+             status = RtlWaitOnAddress (&in_singlestep_handler, &bool_false,
+                                        sizeof (bool), &timeout);
+             if (status == STATUS_TIMEOUT)
+               break;
            }
-         while (NT_SUCCESS (status) && cnt == 0);
+         SuspendThread (*this);
          GetThreadContext (*this, cx);
+         RemoveVectoredExceptionHandler (h_veh);
          suspend_on_exception = false;
+         if (!NT_SUCCESS (status) || status == STATUS_TIMEOUT)
+           return false; /* Not interrupted */
        }
 #endif
       DWORD64 &ip = cx->_CX_instPtr;
diff --git a/winsup/cygwin/local_includes/cygtls.h 
b/winsup/cygwin/local_includes/cygtls.h
index 615361d3f..306497a33 100644
--- a/winsup/cygwin/local_includes/cygtls.h
+++ b/winsup/cygwin/local_includes/cygtls.h
@@ -204,6 +204,7 @@ public: /* Do NOT remove this public: line, it's a marker 
for gentls_offsets. */
   __tlsstack_t stack[TLS_STACK_SIZE];
   unsigned initialized;
   volatile bool suspend_on_exception;
+  volatile bool in_singlestep_handler;
 
 public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. 
*/
   void init_thread (void *, DWORD (*) (void *, void *));
diff --git a/winsup/cygwin/local_includes/ntdll.h 
b/winsup/cygwin/local_includes/ntdll.h
index 242a6a64b..29e33b197 100644
--- a/winsup/cygwin/local_includes/ntdll.h
+++ b/winsup/cygwin/local_includes/ntdll.h
@@ -1659,6 +1659,8 @@ extern "C"
                                         BOOLEAN);
   WCHAR RtlUpcaseUnicodeChar (WCHAR);
   NTSTATUS RtlUpcaseUnicodeString (PUNICODE_STRING, PUNICODE_STRING, BOOLEAN);
+  VOID RtlWakeAddressSingle (PVOID);
+  NTSTATUS RtlWaitOnAddress (volatile void *, PVOID, SIZE_T, PLARGE_INTEGER);
   NTSTATUS RtlWriteRegistryValue (ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG);
 
 #ifdef __cplusplus
diff --git a/winsup/cygwin/release/3.6.4 b/winsup/cygwin/release/3.6.4
index c80a29ea4..31e6c6392 100644
--- a/winsup/cygwin/release/3.6.4
+++ b/winsup/cygwin/release/3.6.4
@@ -9,3 +9,6 @@ Fixes:
 
 - Fix creating native symlinks to `..` (it used to target `../../<dir>`
   instead).
+
+- Fix CI (stress-ng) for arm64 windows failure.
+  Addresses: https://cygwin.com/pipermail/cygwin/2025-June/258332.html

Reply via email to