Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would I cope with changes to the system time while doing sem_timedwait?

Tags:

c

unix

semaphore

Say I've got that program that uses sem_timedwait in order to wait for 100 ms (get current time, add 100 ms, use the result as abs_timeout, cf. man page). Now it happens that the system time gets set by an external process (ntp) while waiting for the semaphore.

If we have bad luck, the system time gets set to say 2 days in the past. This would cause sem_timedwait to wait for 2 days and 100 ms.

Is there a way to get around this issue?

like image 510
eckes Avatar asked Mar 19 '15 19:03

eckes


1 Answers

You can use condition variables instead, and choose the monotonic clock as the reference clock. Semaphores are a bit old-school, I would avoid using them in new applications. You can easily implement semaphores using condition variables and mutexes if you like.

pthread_condattr_t cattr;
pthread_condattr_init(&cattr);
pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);

pthread_cond_t cond;
pthread_cond_init(&cond, &cattr);

struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_nsec += 100000000;
if (ts.tv_nsec >= 1000000000) {
    ts.tv_nsec -= 1000000000;
    ts.tv_sec += 1;
}
int r = pthread_cond_timedwait(&cond, &mutex, &ts);
if (r == ETIMEDOUT) {
    // ...
} else {
    // ...
}

The monotonic clock is "not affected by discontinuous jumps in the system time" (man clock_gettime), so it is exactly what you want for this kind of application.

You said,

Now it happens that the system time gets set by an external process (ntp) while waiting for the semaphore.

But the situation is worse than that... the system clock might be adjusted after you call clock_gettime() but before you call sem_timedwait()... so as far as it knows, you wanted sem_timedwait() to wait two days.

like image 57
Dietrich Epp Avatar answered Nov 08 '22 07:11

Dietrich Epp