¿Cómo hacer que pthread_cond_timedwait () sea robusto frente a las manipulaciones del reloj del sistema?

Considere el siguiente código fuente, que es totalmente compatible con POSIX:

#include <stdio.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>

int main (int argc, char ** argv) {
    pthread_cond_t c;
    pthread_mutex_t m;
    char printTime[UCHAR_MAX];

    pthread_mutex_init(&m, NULL);
    pthread_cond_init(&c, NULL);

    for (;;) {
        struct tm * tm;
        struct timeval tv;
        struct timespec ts;

        gettimeofday(&tv, NULL);

        printf("sleep (%ld)\n", (long)tv.tv_sec);
        sleep(3);

        tm = gmtime(&tv.tv_sec);
        strftime(printTime, UCHAR_MAX, "%Y-%m-%d %H:%M:%S", tm);
        printf("%s (%ld)\n", printTime, (long)tv.tv_sec);

        ts.tv_sec = tv.tv_sec + 5;
        ts.tv_nsec = tv.tv_usec * 1000;

        pthread_mutex_lock(&m);
        pthread_cond_timedwait(&c, &m, &ts);
        pthread_mutex_unlock(&m);
    }
    return 0;
}

Imprime la fecha actual del sistema cada 5 segundos, sin embargo, duerme 3 segundos entre la hora actual del sistema gettimeofday) y la condición espera pthread_cond_timedwait).

Justo después de imprimir "suspensión (...)", intente configurar el reloj del sistema dos días antes. ¿Lo que pasa? Bueno, en lugar de esperar 2 segundos más en la condición como generalmente lo hace,pthread_cond_timedwait ahora espera ados día y 2 segundos.

¿Cómo arreglo eso
¿Cómo puedo escribir código compatible con POSIX que no se rompa cuando el usuario manipula el reloj del sistema?

Tenga en cuenta que el reloj del sistema puede cambiar incluso sin la interacción del usuario (por ejemplo, un cliente NTP puede actualizar el reloj automáticamente una vez al día). Configurar el reloj en el futuro no es un problema, solo hará que el sueño se despierte temprano, lo que generalmente no es un problema y que puede "detectar" y manejar fácilmente en consecuencia, pero configurando el reloj en el pasado (por ejemplo, porque fue ejecutándose en el futuro, NTP lo detectó y lo arregló) puede causar un gran problema.

PD
Ningunopthread_condattr_setclock() norCLOCK_MONOTONIC existe en mi sistema. Esos son obligatorios para la especificación POSIX 2008 (parte de "Base"), pero la mayoría de los sistemas todavía solo siguen la especificación POSIX 2004 a partir de hoy y en la especificación POSIX 2004 estos dos eran opcionales (Advanced Realtime Extension).

Respuestas a la pregunta(2)

Su respuesta a la pregunta