Author: sobomax
Date: Wed Oct 17 00:44:34 2012
New Revision: 241625
URL: http://svn.freebsd.org/changeset/base/241625

Log:
  o Use nanosleep(2) to sleep exact amount of time till the next second,
  not multiple of 1 second, which results in actual time to drift back
  and forth every run within 1 second of the actual action has
  been set for.
  
  Suggested by:   Ian Lepore
  
  o Schedule the first run in 1 second after starting up, not on the
  boundary of the next minute, which results in the every_second jobs
  not being run.

Modified:
  head/usr.sbin/cron/cron/cron.c

Modified: head/usr.sbin/cron/cron/cron.c
==============================================================================
--- head/usr.sbin/cron/cron/cron.c      Wed Oct 17 00:33:10 2012        
(r241624)
+++ head/usr.sbin/cron/cron/cron.c      Wed Oct 17 00:44:34 2012        
(r241625)
@@ -341,37 +341,73 @@ cron_tick(db)
  */
 static void
 cron_sync() {
+#if 0
        register struct tm      *tm;
+#endif
 
-       TargetTime = time((time_t*)0);
+       TargetTime = time((time_t*)0) + 1;
+#if 0
        tm = localtime(&TargetTime);
        TargetTime += (60 - tm->tm_sec);
+#endif
 }
 
+static int
+timeval_subtract(struct timespec *result, struct timeval *x, struct timeval *y)
+{
+       int nsec;
+
+       /* Perform the carry for the later subtraction by updating y. */
+       if (x->tv_usec < y->tv_usec) {
+               nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+               y->tv_usec -= 1000000 * nsec;
+               y->tv_sec += nsec;
+       }
+       if (x->tv_usec - y->tv_usec > 1000000) {
+               nsec = (x->tv_usec - y->tv_usec) / 1000000;
+               y->tv_usec += 1000000 * nsec;
+               y->tv_sec -= nsec;
+       }
+     
+       /* tv_nsec is certainly positive. */
+       result->tv_sec = x->tv_sec - y->tv_sec;
+       result->tv_nsec = (x->tv_usec - y->tv_usec) * 1000;
+     
+       /* Return difference in seconds */
+       return (x->tv_sec - y->tv_sec);
+}
 
 static void
 cron_sleep(db)
        cron_db *db;
 {
-       int     seconds_to_wait = 0;
+       int seconds_to_wait;
+       int rval;
+       struct timeval ctime, ttime;
+       struct timespec stime, remtime;
 
        /*
         * Loop until we reach the top of the next minute, sleep when possible.
         */
 
        for (;;) {
-               seconds_to_wait = (int) (TargetTime - time((time_t*)0));
+               gettimeofday(&ctime, NULL);
+               ttime.tv_sec = TargetTime;
+               ttime.tv_usec = 0;
+               timeval_subtract(&stime, &ttime, &ctime);
 
                /*
                 * If the seconds_to_wait value is insane, jump the cron
                 */
 
-               if (seconds_to_wait < -600 || seconds_to_wait > 600) {
+               if (stime.tv_sec < -600 || stime.tv_sec > 600) {
                        cron_clean(db);
                        cron_sync();
                        continue;
                }
 
+               seconds_to_wait = (stime.tv_nsec > 0) ? stime.tv_sec + 1 : 
stime.tv_sec;
+
                Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
                        getpid(), (long)TargetTime, seconds_to_wait))
 
@@ -380,13 +416,19 @@ cron_sleep(db)
                 * to run, break
                 */
 
-               if (seconds_to_wait <= 0)
+               if (stime.tv_sec < 0)
                        break;
                if (job_runqueue() == 0) {
                        Debug(DSCH, ("[%d] sleeping for %d seconds\n",
                                getpid(), seconds_to_wait))
 
-                       sleep(seconds_to_wait);
+                       for (;;) {
+                               rval = nanosleep(&stime, &remtime);
+                               if (rval == 0 || errno != EINTR)
+                                       break;
+                               stime.tv_sec = remtime.tv_sec;
+                               stime.tv_nsec = remtime.tv_nsec;
+                       }
                }
        }
 }
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to