On 10/17/12 4:44 AM, Maxim Sobolev wrote: > 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
This should be type of time_t. > +timeval_subtract(struct timespec *result, struct timeval *x, struct timeval > *y) > +{ > + int nsec; And this should be suseconds_t. > + > + /* 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); > +} May be it's better to use timersub() and TIMEVAL_TO_TIMESPEC()? > > 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; > + } > } > } > } > -- Andrey Zonov
signature.asc
Description: OpenPGP digital signature