Reputation: 675
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
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
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