]> granicus.if.org Git - postgresql/commitdiff
Teach unix_latch.c to use poll() where available.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 11 Aug 2011 16:49:45 +0000 (12:49 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 11 Aug 2011 16:50:22 +0000 (12:50 -0400)
poll() is preferred over select() on platforms where both are available,
because it tends to be a bit faster and it doesn't have an arbitrary limit
on the range of FD numbers that can be accessed.  The FD range limit does
not appear to be a risk factor for any 9.1 usages, so this doesn't need to
be back-patched, but we need to have it in place if we keep on expanding
the uses of WaitLatch.

src/backend/port/unix_latch.c

index a7482facebc0c8fe0d5047cbd1f889aa889c293d..02894976c06aff1281bb6ebaea7febd5c0ee5296 100644 (file)
@@ -14,6 +14,9 @@
  * however reliably interrupts the sleep, and causes select() to return
  * immediately even if the signal arrives before select() begins.
  *
+ * (Actually, we prefer poll() over select() where available, but the
+ * same comments apply to it.)
+ *
  * When SetLatch is called from the same process that owns the latch,
  * SetLatch writes the byte directly to the pipe. If it's owned by another
  * process, SIGUSR1 is sent and the signal handler in the waiting process
 #include <unistd.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -175,12 +184,18 @@ int
 WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
                                  long timeout)
 {
+       int                     result = 0;
+       int                     rc;
+#ifdef HAVE_POLL
+       struct pollfd pfds[3];
+       int                     nfds;
+#else
        struct timeval tv,
                           *tvp = NULL;
        fd_set          input_mask;
        fd_set          output_mask;
-       int                     rc;
-       int                     result = 0;
+       int                     hifd;
+#endif
 
        /* Ignore WL_SOCKET_* events if no valid socket is given */
        if (sock == PGINVALID_SOCKET)
@@ -195,21 +210,29 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
        if (wakeEvents & WL_TIMEOUT)
        {
                Assert(timeout >= 0);
+#ifndef HAVE_POLL
                tv.tv_sec = timeout / 1000L;
                tv.tv_usec = (timeout % 1000L) * 1000L;
                tvp = &tv;
+#endif
+       }
+       else
+       {
+#ifdef HAVE_POLL
+               /* make sure poll() agrees there is no timeout */
+               timeout = -1;
+#endif
        }
 
        waiting = true;
        do
        {
-               int                     hifd;
-
                /*
                 * Clear the pipe, then check if the latch is set already. If someone
-                * sets the latch between this and the select() below, the setter will
-                * write a byte to the pipe (or signal us and the signal handler will
-                * do that), and the select() will return immediately.
+                * sets the latch between this and the poll()/select() below, the
+                * setter will write a byte to the pipe (or signal us and the signal
+                * handler will do that), and the poll()/select() will return
+                * immediately.
                 *
                 * Note: we assume that the kernel calls involved in drainSelfPipe()
                 * and SetLatch() will provide adequate synchronization on machines
@@ -228,7 +251,73 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
                        break;
                }
 
-               /* Must wait ... set up the event masks for select() */
+               /* Must wait ... we use poll(2) if available, otherwise select(2) */
+#ifdef HAVE_POLL
+               nfds = 0;
+               if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE))
+               {
+                       /* socket, if used, is always in pfds[0] */
+                       pfds[0].fd = sock;
+                       pfds[0].events = 0;
+                       if (wakeEvents & WL_SOCKET_READABLE)
+                               pfds[0].events |= POLLIN;
+                       if (wakeEvents & WL_SOCKET_WRITEABLE)
+                               pfds[0].events |= POLLOUT;
+                       pfds[0].revents = 0;
+                       nfds++;
+               }
+
+               pfds[nfds].fd = selfpipe_readfd;
+               pfds[nfds].events = POLLIN;
+               pfds[nfds].revents = 0;
+               nfds++;
+
+               if (wakeEvents & WL_POSTMASTER_DEATH)
+               {
+                       /* postmaster fd, if used, is always in pfds[nfds - 1] */
+                       pfds[nfds].fd = postmaster_alive_fds[POSTMASTER_FD_WATCH];
+                       pfds[nfds].events = POLLIN;
+                       pfds[nfds].revents = 0;
+                       nfds++;
+               }
+
+               /* Sleep */
+               rc = poll(pfds, nfds, (int) timeout);
+
+               /* Check return code */
+               if (rc < 0)
+               {
+                       if (errno == EINTR)
+                               continue;
+                       waiting = false;
+                       ereport(ERROR,
+                                       (errcode_for_socket_access(),
+                                        errmsg("poll() failed: %m")));
+               }
+               if (rc == 0 && (wakeEvents & WL_TIMEOUT))
+               {
+                       /* timeout exceeded */
+                       result |= WL_TIMEOUT;
+               }
+               if ((wakeEvents & WL_SOCKET_READABLE) &&
+                       (pfds[0].revents & POLLIN))
+               {
+                       /* data available in socket */
+                       result |= WL_SOCKET_READABLE;
+               }
+               if ((wakeEvents & WL_SOCKET_WRITEABLE) &&
+                       (pfds[0].revents & POLLOUT))
+               {
+                       result |= WL_SOCKET_WRITEABLE;
+               }
+               if ((wakeEvents & WL_POSTMASTER_DEATH) &&
+                       (pfds[nfds - 1].revents & POLLIN))
+               {
+                       result |= WL_POSTMASTER_DEATH;
+               }
+
+#else /* !HAVE_POLL */
+
                FD_ZERO(&input_mask);
                FD_ZERO(&output_mask);
 
@@ -288,6 +377,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
                {
                        result |= WL_POSTMASTER_DEATH;
                }
+#endif /* HAVE_POLL */
        } while (result == 0);
        waiting = false;