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

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to