user1840007
user1840007

Reputation: 675

Replacing usleep with nanosleep

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);

Upvotes: 4

Views: 21838

Answers (2)

caf
caf

Reputation: 239111

Your underlying objective here is to sleep until fieldtime microseconds after the previous frame was acquired. The clock_nanosleep() function allows you to do this directly - sleep until a particular absolute time has been reached - so it is a better fit for your requirement. Using this function would look like:

int fieldtime = videoinput_get_time_per_field( norm );
struct timespec deadline = performance->input;

deadline.tv_nsec += fieldtime * 1000L;
deadline.tv_sec += deadline.tv_nsec / 1000000000;
deadline.tv_nsec %= 1000000000;

while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, NULL) && errno == EINTR)
    ;

This presumes that you change performance->input to be a struct timespec set by clock_gettime(CLOCK_MONOTONIC, &performance->input) rather than gettimeofday(). The CLOCK_MONOTONIC clock is a better fit for this case, because it's not affected by changes to the system time.

Upvotes: 3

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215287

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.

Upvotes: 13

Related Questions