From owner-svn-src-all@FreeBSD.ORG Wed Oct 17 00:44:35 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id A3C45BD5; Wed, 17 Oct 2012 00:44:35 +0000 (UTC) (envelope-from sobomax@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7B1258FC0A; Wed, 17 Oct 2012 00:44:35 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q9H0iZfM055979; Wed, 17 Oct 2012 00:44:35 GMT (envelope-from sobomax@svn.freebsd.org) Received: (from sobomax@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q9H0iZHo055977; Wed, 17 Oct 2012 00:44:35 GMT (envelope-from sobomax@svn.freebsd.org) Message-Id: <201210170044.q9H0iZHo055977@svn.freebsd.org> From: Maxim Sobolev Date: Wed, 17 Oct 2012 00:44:35 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r241625 - head/usr.sbin/cron/cron X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Oct 2012 00:44:35 -0000 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; + } } } }