From fe2e94200cfb6a88e82b9261f2d8a05a6fae0cbe Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 21:58:37 -0500
Subject: [PATCH 19/83] ntdll: Try again if poll() returns EINTR.

I originally had this return STATUS_USER_APC, but that isn't correct. The
server code here is a bit confusing, but only the thread that waits *during*
the suspend should receive STATUS_USER_APC (and I imagine that it really
should receive STATUS_KERNEL_APC instead). The thread that is suspended
should just keep on waiting.

Besides, we could be suspended for reasons other than to deliver a system
APC.

---
 dlls/ntdll/esync.c | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 23b03b23b..0655ab779 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -423,22 +423,32 @@ static LONGLONG update_timeout( ULONGLONG end )
 
 static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end )
 {
-    if (end)
+    int ret;
+
+    do
     {
-        LONGLONG timeleft = update_timeout( *end );
+        if (end)
+        {
+            LONGLONG timeleft = update_timeout( *end );
 
 #ifdef HAVE_PPOLL
-        /* We use ppoll() if available since the time granularity is better. */
-        struct timespec tmo_p;
-        tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
-        tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100;
-        return ppoll( fds, nfds, &tmo_p, NULL );
+            /* We use ppoll() if available since the time granularity is better. */
+            struct timespec tmo_p;
+            tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
+            tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100;
+            ret = ppoll( fds, nfds, &tmo_p, NULL );
 #else
-        return poll( fds, nfds, timeleft / TICKSPERMSEC );
+            ret = poll( fds, nfds, timeleft / TICKSPERMSEC );
 #endif
-    }
-    else
-        return poll( fds, nfds, -1 );
+        }
+        else
+            ret = poll( fds, nfds, -1 );
+
+    /* If we receive EINTR we were probably suspended (SIGUSR1), possibly for a
+     * system APC. The right thing to do is just try again. */
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
 }
 
 /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we
-- 
2.20.1

