summaryrefslogtreecommitdiffstats
path: root/usr.sbin/cron
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2012-10-17 00:44:34 +0000
committersobomax <sobomax@FreeBSD.org>2012-10-17 00:44:34 +0000
commit19f11b875baec8f2fe330de020ab982aef517542 (patch)
tree6c97cfe9d6e459b6309ee9f2ba62c6748c7f8816 /usr.sbin/cron
parentf4127691ff8eb4cd732a46b615fb3d55cb1e7aa9 (diff)
downloadFreeBSD-src-19f11b875baec8f2fe330de020ab982aef517542.zip
FreeBSD-src-19f11b875baec8f2fe330de020ab982aef517542.tar.gz
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.
Diffstat (limited to 'usr.sbin/cron')
-rw-r--r--usr.sbin/cron/cron/cron.c54
1 files changed, 48 insertions, 6 deletions
diff --git a/usr.sbin/cron/cron/cron.c b/usr.sbin/cron/cron/cron.c
index 011458a..5f3e7fd 100644
--- a/usr.sbin/cron/cron/cron.c
+++ b/usr.sbin/cron/cron/cron.c
@@ -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;
+ }
}
}
}
OpenPOWER on IntegriCloud