This converts spamd from select() to poll().  It might be a little
cleaner to embed a pointer to the pfd in struct con to avoid the
"pfd[PFD_FIRSTCON + i]" bits but I don't think it is a big deal.

The numcon bit is just to prevent the kernel from having to copy
and inspect a lot of unused entries.

 - todd

Index: libexec/spamd/spamd.c
===================================================================
RCS file: /cvs/src/libexec/spamd/spamd.c,v
retrieving revision 1.117
diff -u -r1.117 spamd.c
--- libexec/spamd/spamd.c       29 Dec 2014 20:39:27 -0000      1.117
+++ libexec/spamd/spamd.c       30 Dec 2014 00:02:44 -0000
@@ -29,6 +29,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <poll.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1031,13 +1032,21 @@
                return(maxfiles - 200);
 }
 
+/* Symbolic indexes for pfd[] below */
+#define PFD_SMTPLISTEN 0
+#define PFD_CONFLISTEN 1
+#define PFD_SYNCFD     2
+#define PFD_CONFFD     3
+#define PFD_TRAPFD     4
+#define PFD_FIRSTCON   5
+
 int
 main(int argc, char *argv[])
 {
-       fd_set *fdsr = NULL, *fdsw = NULL;
+       struct pollfd *pfd;
        struct sockaddr_in sin;
        struct sockaddr_in lin;
-       int ch, s, conflisten = 0, syncfd = 0, i, omax = 0, one = 1;
+       int ch, smtplisten, conflisten, syncfd = -1, i, one = 1;
        u_short port;
        long long passt, greyt, whitet;
        struct servent *ent;
@@ -1192,11 +1201,11 @@
 
        signal(SIGPIPE, SIG_IGN);
 
-       s = socket(AF_INET, SOCK_STREAM, 0);
-       if (s == -1)
+       smtplisten = socket(AF_INET, SOCK_STREAM, 0);
+       if (smtplisten == -1)
                err(1, "socket");
 
-       if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one,
+       if (setsockopt(smtplisten, SOL_SOCKET, SO_REUSEADDR, &one,
            sizeof(one)) == -1)
                return (-1);
 
@@ -1218,7 +1227,7 @@
        sin.sin_family = AF_INET;
        sin.sin_port = htons(port);
 
-       if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1)
+       if (bind(smtplisten, (struct sockaddr *)&sin, sizeof sin) == -1)
                err(1, "bind");
 
        memset(&lin, 0, sizeof sin);
@@ -1317,7 +1326,7 @@
                    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                        err(1, "failed to drop privs");
 
-       if (listen(s, 10) == -1)
+       if (listen(smtplisten, 10) == -1)
                err(1, "listen");
 
        if (listen(conflisten, 10) == -1)
@@ -1327,90 +1336,87 @@
                printf("listening for incoming connections.\n");
        syslog_r(LOG_WARNING, &sdata, "listening for incoming connections.");
 
+       pfd = reallocarray(NULL, PFD_FIRSTCON + maxcon, sizeof(*pfd));
+       if (pfd == NULL)
+               err(1, "reallocarray");
+
+       /* We always check for trap and sync events if configured. */
+       if (trapfd != -1) {
+               pfd[PFD_TRAPFD].fd = trapfd;
+               pfd[PFD_TRAPFD].events = POLLIN;
+       } else {
+               pfd[PFD_TRAPFD].fd = -1;
+               pfd[PFD_TRAPFD].events = 0;
+       }
+       if (syncrecv) {
+               pfd[PFD_SYNCFD].fd = syncfd;
+               pfd[PFD_SYNCFD].events = POLLIN;
+       } else {
+               pfd[PFD_SYNCFD].fd = -1;
+               pfd[PFD_SYNCFD].events = 0;
+       }
+
+       /* events and pfd entries for con[] are filled in below. */
+       pfd[PFD_SMTPLISTEN].fd = smtplisten;
+       pfd[PFD_CONFLISTEN].fd = conflisten;
+
        while (1) {
-               struct timeval tv, *tvp;
-               int max, n;
-               int writers;
-
-               max = MAX(s, conflisten);
-               if (syncrecv)
-                       max = MAX(max, syncfd);
-               max = MAX(max, conffd);
-               max = MAX(max, trapfd);
+               int numcon = 0, n, timeout, writers;
 
                time(&t);
-               for (i = 0; i < maxcon; i++)
-                       if (con[i].fd != -1)
-                               max = MAX(max, con[i].fd);
-
-               if (max > omax) {
-                       free(fdsr);
-                       fdsr = NULL;
-                       free(fdsw);
-                       fdsw = NULL;
-                       fdsr = (fd_set *)calloc(howmany(max+1, NFDBITS),
-                           sizeof(fd_mask));
-                       if (fdsr == NULL)
-                               err(1, "calloc");
-                       fdsw = (fd_set *)calloc(howmany(max+1, NFDBITS),
-                           sizeof(fd_mask));
-                       if (fdsw == NULL)
-                               err(1, "calloc");
-                       omax = max;
-               } else {
-                       memset(fdsr, 0, howmany(max+1, NFDBITS) *
-                           sizeof(fd_mask));
-                       memset(fdsw, 0, howmany(max+1, NFDBITS) *
-                           sizeof(fd_mask));
-               }
 
                writers = 0;
                for (i = 0; i < maxcon; i++) {
-                       if (con[i].fd != -1 && con[i].r) {
+                       pfd[PFD_FIRSTCON + i].fd = -1;
+                       pfd[PFD_FIRSTCON + i].events = 0;
+                       if (con[i].fd == -1)
+                               continue;
+                       if (i + 1 > numcon)
+                               numcon = i + 1;
+                       if (con[i].r) {
                                if (con[i].r + MAXTIME <= t) {
                                        closecon(&con[i]);
                                        continue;
                                }
-                               FD_SET(con[i].fd, fdsr);
+                               pfd[PFD_FIRSTCON + i].fd = con[i].fd;
+                               pfd[PFD_FIRSTCON + i].events |= POLLIN;
                        }
-                       if (con[i].fd != -1 && con[i].w) {
+                       if (con[i].w) {
                                if (con[i].w + MAXTIME <= t) {
                                        closecon(&con[i]);
                                        continue;
                                }
-                               if (con[i].w <= t)
-                                       FD_SET(con[i].fd, fdsw);
+                               if (con[i].w <= t) {
+                                       pfd[PFD_FIRSTCON + i].fd = con[i].fd;
+                                       pfd[PFD_FIRSTCON + i].events |= POLLOUT;
+                               }
                                writers = 1;
                        }
                }
+               pfd[PFD_SMTPLISTEN].events = 0;
+               pfd[PFD_CONFLISTEN].events = 0;
+               pfd[PFD_CONFFD].events = 0;
+               pfd[PFD_CONFFD].fd = conffd;
                if (slowdowntill == 0) {
-                       FD_SET(s, fdsr);
+                       pfd[PFD_SMTPLISTEN].events = POLLIN;
 
                        /* only one active config conn at a time */
                        if (conffd == -1)
-                               FD_SET(conflisten, fdsr);
+                               pfd[PFD_CONFLISTEN].events = POLLIN;
                        else
-                               FD_SET(conffd, fdsr);
+                               pfd[PFD_CONFFD].events = POLLIN;
                }
 
-               if (trapfd != -1)
-                       FD_SET(trapfd, fdsr);
-               if (syncrecv)
-                       FD_SET(syncfd, fdsr);
-
                /* If we are not listening, wake up at least once a second */
-               if (writers == 0 && slowdowntill == 0) {
-                       tvp = NULL;
-               } else {
-                       tv.tv_sec = 1;
-                       tv.tv_usec = 0;
-                       tvp = &tv;
-               }
+               if (writers == 0 && slowdowntill == 0)
+                       timeout = INFTIM;
+               else
+                       timeout = 1000;
 
-               n = select(max+1, fdsr, fdsw, NULL, tvp);
+               n = poll(pfd, PFD_FIRSTCON + numcon, timeout);
                if (n == -1) {
                        if (errno != EINTR)
-                               err(1, "select");
+                               err(1, "poll");
                        continue;
                }
 
@@ -1419,17 +1425,23 @@
                        slowdowntill = 0;
 
                for (i = 0; i < maxcon; i++) {
-                       if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsr))
+                       if (con[i].fd == -1)
+                               continue;
+                       if (pfd[PFD_FIRSTCON + i].revents & POLLHUP) {
+                               closecon(&con[i]);
+                               continue;
+                       }
+                       if (pfd[PFD_FIRSTCON + i].revents & POLLIN)
                                handler(&con[i]);
-                       if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsw))
+                       if (pfd[PFD_FIRSTCON + i].revents & POLLOUT)
                                handlew(&con[i], clients + 5 < maxcon);
                }
-               if (FD_ISSET(s, fdsr)) {
+               if (pfd[PFD_SMTPLISTEN].revents & (POLLIN|POLLHUP)) {
                        socklen_t sinlen;
                        int s2;
 
                        sinlen = sizeof(sin);
-                       s2 = accept(s, (struct sockaddr *)&sin, &sinlen);
+                       s2 = accept(smtplisten, (struct sockaddr *)&sin, 
&sinlen);
                        if (s2 == -1) {
                                switch (errno) {
                                case EINTR:
@@ -1463,7 +1475,7 @@
                                }
                        }
                }
-               if (FD_ISSET(conflisten, fdsr)) {
+               if (pfd[PFD_CONFLISTEN].revents & (POLLIN|POLLHUP)) {
                        socklen_t sinlen;
 
                        sinlen = sizeof(lin);
@@ -1486,11 +1498,11 @@
                                conffd = -1;
                                slowdowntill = 0;
                        }
-               } else if (conffd != -1 && FD_ISSET(conffd, fdsr))
+               } else if (pfd[PFD_CONFFD].revents & (POLLIN|POLLHUP))
                        do_config();
-               if (trapfd != -1 && FD_ISSET(trapfd, fdsr))
+               if (pfd[PFD_TRAPFD].revents & (POLLIN|POLLHUP))
                        read_configline(trapcfg);
-               if (syncrecv && FD_ISSET(syncfd, fdsr))
+               if (pfd[PFD_SYNCFD].revents & (POLLIN|POLLHUP))
                        sync_recv();
        }
        exit(1);

Reply via email to