]> Pileus Git - ~andy/fetchmail/commitdiff
Track due time and prevent excess repelling idle
authorAndy Spencer <andy753421@gmail.com>
Mon, 15 Jul 2013 02:31:48 +0000 (02:31 +0000)
committerAndy Spencer <andy753421@gmail.com>
Mon, 15 Jul 2013 02:31:48 +0000 (02:31 +0000)
When we wakeup due to idle data available, we just want to poll the
connections with data, not all the connections. This prevents polling
everything by tracking when the full poll is needed.

fetchmail.c
idle.c

index d720b04539172120dc902918a801dde91143f249..cdbd4445044ee8cadaa9fa0245f8379b94ee8c97 100644 (file)
@@ -433,6 +433,7 @@ int main(int argc, char **argv)
     char *netrc_file, *tmpbuf;
     pid_t pid;
     int lastsig = 0;
+    time_t awoke = 0, due = 0;
 
 #if defined(__FreeBSD__) && defined(__FreeBSD_USE_KVM)
     dropprivs();
@@ -1026,6 +1027,16 @@ int main(int argc, char **argv)
                        continue;
                    }
 
+                   /* check due counts on idle connections */
+                   if (awoke < due && !ctl->server.idle_ready)
+                   {
+                       if (outlevel >= O_VERBOSE)
+                           report(stdout,
+                                  GT_("no idle data available, not querying %s\n"),
+                                  ctl->server.pollname);
+                       continue;
+                   }
+
                    /* check skip interval first so that it counts all polls */
                    if (run.poll_interval && ctl->server.interval) 
                    {
@@ -1153,6 +1164,8 @@ int main(int argc, char **argv)
             * spinning uselessly.
             */
            int unwedged = 0;
+           int delay = 0;
+           time_t now = 0;
 
            for (ctl = querylist; ctl; ctl = ctl->next)
                if (ctl->active && !(implicitmode && ctl->server.skip))
@@ -1181,13 +1194,46 @@ int main(int argc, char **argv)
            if (getuid() == ROOT_UID)
                set_signal_handler(SIGHUP, donothing);
 
+           /*
+            * Calculate next wakeup time (due) and how long we have to
+            * sleep to get there (delay). Idle polls may occur during the
+            * middle of the sleep so we can't just sleep the full amount
+            * every time.
+            *
+            * Also watch for clock adjustments so we don't get stuck.
+            */
+           now = time(NULL);
+           if (awoke >= due)
+           {
+               delay = run.poll_interval;
+               due = now + delay;
+               report(stdout, GT_("Full poll completed\n"));
+           }
+           else if (now >= due)
+           {
+               awoke = now;
+               report(stdout, GT_("Poll interval expired during idle poll, skipping sleep\n"));
+               continue;
+           }
+           else if ((due-now) > run.poll_interval)
+           {
+               delay = run.poll_interval;
+               due = now + delay;
+               report(stdout, GT_("Great Scott! Someone must have reset the clocks!\n"));
+           }
+           else
+           {
+               delay = due-now;
+               report(stdout, GT_("Idle poll finished, polling in %d seconds.\n"));
+           }
+
            /*
             * OK, now pause until it's time for the next poll cycle.
             * A nonzero return indicates we received a wakeup signal;
             * unwedge all servers in case the problem has been
             * manually repaired.
             */
-           if ((lastsig = interruptible_idle(run.poll_interval)))
+           if ((lastsig = interruptible_idle(delay)))
            {
                if (outlevel > O_SILENT)
 #ifdef SYS_SIGLIST_DECLARED
@@ -1204,6 +1250,11 @@ int main(int argc, char **argv)
            if ((outlevel > O_SILENT && !run.use_syslog && isatty(1))
                    || outlevel > O_NORMAL)
                report(stdout, GT_("awakened at %s\n"), timestamp());
+
+           /* force full poll when we wakeup from a signal */
+           awoke = time(NULL);
+           if (lastsig)
+               due = awoke;
        }
     } while (run.poll_interval);
 
diff --git a/idle.c b/idle.c
index a58e7778c3be90c2b2d336222ddbe063ec6cf433..b1b25be10b71c9a2ae48ff65d64f31a6c2697b43 100644 (file)
--- a/idle.c
+++ b/idle.c
@@ -22,6 +22,7 @@ MIT license.  Compile with -DMAIN to build the demonstrator.
 #include <signal.h>
 #include <errno.h>
 #include <fetchmail.h> /* for ROOT_UID */
+#include <socket.h>    /* for SockClose */
 
 #ifndef TRUE
 #define TRUE 1
@@ -119,7 +120,7 @@ int interruptible_idle(int seconds)
     struct timeval timeout;
     struct query *ctl;
     int maxfd;
-    fd_set rfds;
+    fd_set rfds, efds;
 
     timeout.tv_sec = seconds;
     timeout.tv_usec = 0;
@@ -134,9 +135,11 @@ int interruptible_idle(int seconds)
      */
     maxfd = 0;
     FD_ZERO(&rfds);
+    FD_ZERO(&efds);
     for (ctl = querylist; ctl; ctl = ctl->next) {
        if (ctl->server.idle_socket) {
            FD_SET(ctl->server.idle_socket, &rfds);
+           FD_SET(ctl->server.idle_socket, &efds);
            if (ctl->server.idle_socket > maxfd)
                maxfd = ctl->server.idle_socket;
            ctl->server.idle_ready = FALSE;
@@ -148,7 +151,11 @@ int interruptible_idle(int seconds)
     /* Wait for the next event */
     do {
        lastsig = 0;
-       select(maxfd+1, &rfds,0,0, &timeout);
+       if (select(maxfd+1, &rfds,0,&efds, &timeout) < 0) {
+           /* fds are invalid on errors */
+           FD_ZERO(&rfds);
+           FD_ZERO(&efds);
+       }
     } while (lastsig == SIGCHLD);
 
     /* Set ready flags on sockets with data available */
@@ -159,6 +166,13 @@ int interruptible_idle(int seconds)
            report(stdout, "IDLE> data available on socket=%d\n",
                    ctl->server.idle_socket);
        }
+       if (ctl->server.idle_socket &&
+               FD_ISSET(ctl->server.idle_socket, &efds)) {
+           SockClose(ctl->server.idle_socket);
+           ctl->server.idle_socket = 0;
+           report(stdout, "IDLE> error on socket=%d\n",
+                   ctl->server.idle_socket);
+       }
     }
 #endif
     if (lastsig == SIGUSR1 || ((seconds && getuid() == ROOT_UID)