#endif
 
 #include "miscadmin.h"
+#include "portability/instr_time.h"
 #include "postmaster/postmaster.h"
 #include "storage/latch.h"
 #include "storage/pmsignal.h"
  * function returns immediately.
  *
  * The 'timeout' is given in milliseconds. It must be >= 0 if WL_TIMEOUT flag
- * is given.  On some platforms, signals do not interrupt the wait, or even
- * cause the timeout to be restarted, so beware that the function can sleep
- * for several times longer than the requested timeout.  However, this
- * difficulty is not so great as it seems, because the signal handlers for any
- * signals that the caller should respond to ought to be programmed to end the
- * wait by calling SetLatch.  Ideally, the timeout parameter is vestigial.
+ * is given.  Note that some extra overhead is incurred when WL_TIMEOUT is
+ * given, so avoid using a timeout if possible.
  *
  * The latch must be owned by the current process, ie. it must be a
  * backend-local latch initialized with InitLatch, or a shared latch
 {
    int         result = 0;
    int         rc;
+   instr_time  start_time,
+               cur_time;
+   long        cur_timeout;
 
 #ifdef HAVE_POLL
    struct pollfd pfds[3];
    int         nfds;
 #else
    struct timeval tv,
-              *tvp = NULL;
+              *tvp;
    fd_set      input_mask;
    fd_set      output_mask;
    int         hifd;
    if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid)
        elog(ERROR, "cannot wait on a latch owned by another process");
 
-   /* Initialize timeout */
+   /*
+    * Initialize timeout if requested.  We must record the current time so
+    * that we can determine the remaining timeout if the poll() or select()
+    * is interrupted.  (On some platforms, select() will update the contents
+    * of "tv" for us, but unfortunately we can't rely on that.)
+    */
    if (wakeEvents & WL_TIMEOUT)
    {
+       INSTR_TIME_SET_CURRENT(start_time);
        Assert(timeout >= 0);
+       cur_timeout = timeout;
+
 #ifndef HAVE_POLL
-       tv.tv_sec = timeout / 1000L;
-       tv.tv_usec = (timeout % 1000L) * 1000L;
+       tv.tv_sec = cur_timeout / 1000L;
+       tv.tv_usec = (cur_timeout % 1000L) * 1000L;
        tvp = &tv;
 #endif
    }
    else
    {
-#ifdef HAVE_POLL
-       /* make sure poll() agrees there is no timeout */
-       timeout = -1;
+       cur_timeout = -1;
+
+#ifndef HAVE_POLL
+       tvp = NULL;
 #endif
    }
 
        }
 
        /* Sleep */
-       rc = poll(pfds, nfds, (int) timeout);
+       rc = poll(pfds, nfds, (int) cur_timeout);
 
        /* Check return code */
        if (rc < 0)
        {
-           if (errno == EINTR)
-               continue;
-           waiting = false;
-           ereport(ERROR,
-                   (errcode_for_socket_access(),
-                    errmsg("poll() failed: %m")));
+           /* EINTR is okay, otherwise complain */
+           if (errno != EINTR)
+           {
+               waiting = false;
+               ereport(ERROR,
+                       (errcode_for_socket_access(),
+                        errmsg("poll() failed: %m")));
+           }
        }
-       if (rc == 0 && (wakeEvents & WL_TIMEOUT))
+       else if (rc == 0)
        {
            /* timeout exceeded */
-           result |= WL_TIMEOUT;
+           if (wakeEvents & WL_TIMEOUT)
+               result |= WL_TIMEOUT;
        }
-       if ((wakeEvents & WL_SOCKET_READABLE) &&
-           (pfds[0].revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL)))
+       else
        {
-           /* data available in socket, or EOF/error condition */
-           result |= WL_SOCKET_READABLE;
-       }
-       if ((wakeEvents & WL_SOCKET_WRITEABLE) &&
-           (pfds[0].revents & POLLOUT))
-       {
-           result |= WL_SOCKET_WRITEABLE;
-       }
+           /* at least one event occurred, so check revents values */
+           if ((wakeEvents & WL_SOCKET_READABLE) &&
+               (pfds[0].revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL)))
+           {
+               /* data available in socket, or EOF/error condition */
+               result |= WL_SOCKET_READABLE;
+           }
+           if ((wakeEvents & WL_SOCKET_WRITEABLE) &&
+               (pfds[0].revents & POLLOUT))
+           {
+               result |= WL_SOCKET_WRITEABLE;
+           }
 
-       /*
-        * We expect a POLLHUP when the remote end is closed, but because we
-        * don't expect the pipe to become readable or to have any errors
-        * either, treat those as postmaster death, too.
-        */
-       if ((wakeEvents & WL_POSTMASTER_DEATH) &&
-         (pfds[nfds - 1].revents & (POLLHUP | POLLIN | POLLERR | POLLNVAL)))
-       {
            /*
-            * According to the select(2) man page on Linux, select(2) may
-            * spuriously return and report a file descriptor as readable,
-            * when it's not; and presumably so can poll(2).  It's not clear
-            * that the relevant cases would ever apply to the postmaster
-            * pipe, but since the consequences of falsely returning
-            * WL_POSTMASTER_DEATH could be pretty unpleasant, we take the
-            * trouble to positively verify EOF with PostmasterIsAlive().
+            * We expect a POLLHUP when the remote end is closed, but because
+            * we don't expect the pipe to become readable or to have any
+            * errors either, treat those cases as postmaster death, too.
             */
-           if (!PostmasterIsAlive())
-               result |= WL_POSTMASTER_DEATH;
+           if ((wakeEvents & WL_POSTMASTER_DEATH) &&
+               (pfds[nfds - 1].revents & (POLLHUP | POLLIN | POLLERR | POLLNVAL)))
+           {
+               /*
+                * According to the select(2) man page on Linux, select(2) may
+                * spuriously return and report a file descriptor as readable,
+                * when it's not; and presumably so can poll(2).  It's not
+                * clear that the relevant cases would ever apply to the
+                * postmaster pipe, but since the consequences of falsely
+                * returning WL_POSTMASTER_DEATH could be pretty unpleasant,
+                * we take the trouble to positively verify EOF with
+                * PostmasterIsAlive().
+                */
+               if (!PostmasterIsAlive())
+                   result |= WL_POSTMASTER_DEATH;
+           }
        }
 #else                          /* !HAVE_POLL */
 
        /* Check return code */
        if (rc < 0)
        {
-           if (errno == EINTR)
-               continue;
-           waiting = false;
-           ereport(ERROR,
-                   (errcode_for_socket_access(),
-                    errmsg("select() failed: %m")));
+           /* EINTR is okay, otherwise complain */
+           if (errno != EINTR)
+           {
+               waiting = false;
+               ereport(ERROR,
+                       (errcode_for_socket_access(),
+                        errmsg("select() failed: %m")));
+           }
        }
-       if (rc == 0 && (wakeEvents & WL_TIMEOUT))
+       else if (rc == 0)
        {
            /* timeout exceeded */
-           result |= WL_TIMEOUT;
-       }
-       if ((wakeEvents & WL_SOCKET_READABLE) && FD_ISSET(sock, &input_mask))
-       {
-           /* data available in socket, or EOF */
-           result |= WL_SOCKET_READABLE;
+           if (wakeEvents & WL_TIMEOUT)
+               result |= WL_TIMEOUT;
        }
-       if ((wakeEvents & WL_SOCKET_WRITEABLE) && FD_ISSET(sock, &output_mask))
+       else
        {
-           result |= WL_SOCKET_WRITEABLE;
-       }
-       if ((wakeEvents & WL_POSTMASTER_DEATH) &&
+           /* at least one event occurred, so check masks */
+           if ((wakeEvents & WL_SOCKET_READABLE) && FD_ISSET(sock, &input_mask))
+           {
+               /* data available in socket, or EOF */
+               result |= WL_SOCKET_READABLE;
+           }
+           if ((wakeEvents & WL_SOCKET_WRITEABLE) && FD_ISSET(sock, &output_mask))
+           {
+               result |= WL_SOCKET_WRITEABLE;
+           }
+           if ((wakeEvents & WL_POSTMASTER_DEATH) &&
            FD_ISSET(postmaster_alive_fds[POSTMASTER_FD_WATCH], &input_mask))
-       {
-           /*
-            * According to the select(2) man page on Linux, select(2) may
-            * spuriously return and report a file descriptor as readable,
-            * when it's not; and presumably so can poll(2).  It's not clear
-            * that the relevant cases would ever apply to the postmaster
-            * pipe, but since the consequences of falsely returning
-            * WL_POSTMASTER_DEATH could be pretty unpleasant, we take the
-            * trouble to positively verify EOF with PostmasterIsAlive().
-            */
-           if (!PostmasterIsAlive())
-               result |= WL_POSTMASTER_DEATH;
+           {
+               /*
+                * According to the select(2) man page on Linux, select(2) may
+                * spuriously return and report a file descriptor as readable,
+                * when it's not; and presumably so can poll(2).  It's not
+                * clear that the relevant cases would ever apply to the
+                * postmaster pipe, but since the consequences of falsely
+                * returning WL_POSTMASTER_DEATH could be pretty unpleasant,
+                * we take the trouble to positively verify EOF with
+                * PostmasterIsAlive().
+                */
+               if (!PostmasterIsAlive())
+                   result |= WL_POSTMASTER_DEATH;
+           }
        }
 #endif   /* HAVE_POLL */
+
+       /* If we're not done, update cur_timeout for next iteration */
+       if (result == 0 && cur_timeout >= 0)
+       {
+           INSTR_TIME_SET_CURRENT(cur_time);
+           INSTR_TIME_SUBTRACT(cur_time, start_time);
+           cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
+           if (cur_timeout < 0)
+               cur_timeout = 0;
+
+#ifndef HAVE_POLL
+           tv.tv_sec = cur_timeout / 1000L;
+           tv.tv_usec = (cur_timeout % 1000L) * 1000L;
+#endif
+       }
    } while (result == 0);
    waiting = false;
 
 
 #include <unistd.h>
 
 #include "miscadmin.h"
+#include "portability/instr_time.h"
 #include "postmaster/postmaster.h"
 #include "storage/latch.h"
 #include "storage/pmsignal.h"
                  long timeout)
 {
    DWORD       rc;
+   instr_time  start_time,
+               cur_time;
+   long        cur_timeout;
    HANDLE      events[4];
    HANDLE      latchevent;
    HANDLE      sockevent = WSA_INVALID_EVENT;
    if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid)
        elog(ERROR, "cannot wait on a latch owned by another process");
 
-   /* Convert timeout to form used by WaitForMultipleObjects() */
+   /*
+    * Initialize timeout if requested.  We must record the current time so
+    * that we can determine the remaining timeout if WaitForMultipleObjects
+    * is interrupted.
+    */
    if (wakeEvents & WL_TIMEOUT)
+   {
+       INSTR_TIME_SET_CURRENT(start_time);
        Assert(timeout >= 0);
+       cur_timeout = timeout;
+   }
    else
-       timeout = INFINITE;
+       cur_timeout = INFINITE;
 
    /*
     * Construct an array of event handles for WaitforMultipleObjects().
            break;
        }
 
-       rc = WaitForMultipleObjects(numevents, events, FALSE, timeout);
+       rc = WaitForMultipleObjects(numevents, events, FALSE, cur_timeout);
 
        if (rc == WAIT_FAILED)
            elog(ERROR, "WaitForMultipleObjects() failed: error code %lu",
        }
        else if (rc == WAIT_OBJECT_0 + 1)
        {
-           /* Latch is set, we'll handle that on next iteration of loop */
+           /*
+            * Latch is set.  We'll handle that on next iteration of loop, but
+            * let's not waste the cycles to update cur_timeout below.
+            */
+           continue;
        }
        else if ((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) &&
                 rc == WAIT_OBJECT_0 + 2)       /* socket is at event slot 2 */
        }
        else
            elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %lu", rc);
-   }
-   while (result == 0);
+
+       /* If we're not done, update cur_timeout for next iteration */
+       if (result == 0 && cur_timeout != INFINITE)
+       {
+           INSTR_TIME_SET_CURRENT(cur_time);
+           INSTR_TIME_SUBTRACT(cur_time, start_time);
+           cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
+           if (cur_timeout < 0)
+               cur_timeout = 0;
+       }
+   } while (result == 0);
 
    /* Clean up the event object we created for the socket */
    if (sockevent != WSA_INVALID_EVENT)