Replacing usleep with nanosleep

user1840007 picture user1840007 · Jun 15, 2013 · Viewed 16.8k times · Source

I want to replace obsolete usleep function with nanosleep in my code:

static int timediff( struct timeval *large, struct timeval *small )
{
        return (   ( ( large->tv_sec * 1000 * 1000 ) + large->tv_usec )
                 - ( ( small->tv_sec * 1000 * 1000 ) + small->tv_usec ) );
}

struct performance_s
{
        struct timeval acquired_input;
};

performance_t *performance_new( int fieldtimeus )
{
     performance_t *perf = malloc( sizeof( performance_t ) );
     if( !perf ) return 0;

     gettimeofday( &perf->acquired_input, 0 );

     return perf;
}

performance_t *perf = 0;

int performance_get_usecs_since_frame_acquired( performance_t *perf )
{
    struct timeval now;
    gettimeofday( &now, 0 );
    return timediff( &now, &perf->acquired_input );
}


int fieldtime = videoinput_get_time_per_field( norm );


if( rtctimer ) {
    while( performance_get_usecs_since_frame_acquired( perf )
                  < ( (fieldtime*2) - (rtctimer_get_usecs( rtctimer ) / 2) ) ) {
        rtctimer_next_tick( rtctimer );
    }
} else {
    int timeleft = performance_get_usecs_since_frame_acquired( perf );
    if( timeleft < fieldtime )
        usleep( fieldtime - timeleft );

Questions: does this replacement get the same precision timing than with usleep ( and is it a correct replacement )?

struct timespec delay = {0, ( fieldtime - timeleft )}; nanosleep(&delay, NULL);

Answer

R.. GitHub STOP HELPING ICE picture R.. GitHub STOP HELPING ICE · Jun 15, 2013

One of the reasons usleep is obsolete is that the behavior when it was interrupted by a signal was inconsistent among historical systems. Depending on your needs, this may mean your naive replacement with nanosleep is not quite what you want. In particular, nanosleep returns immediately when any signal handler is executed, even if the signal handler was installed with SA_RESTART. So you may want to do something like:

while (nanosleep(&delay, &delay));

to save the remaining time if it's interrupted and restart sleeping for the remaining time.

Note also that nanosleep uses timespec, which is in nanoseconds, not microseconds. Thus, if your interval values are in microseconds, you must scale them by 1000 to make nanoseconds.

Also, be aware that it is an error (reported by EINVAL) to pass a nanoseconds value less than 0 or greater than 1000000000 (1 second). timespec values must be "normalized", i.e. the nanoseconds must be between 0 and 999999999 (inclusive) and larger values converted to use the seconds (tv_sec) field of the structure.