Absolute Time
TIMER_ABSTIME
Selectable
What Makes clock_nanosleep() Better?
nanosleep() is good, but has a subtle flaw: when interrupted by signals and restarted, each restart introduces rounding errors, causing oversleeping.
clock_nanosleep() solves this with absolute time mode (TIMER_ABSTIME) β sleep until a specific clock time, not for a relative duration. Restarts with the same absolute target never overshoot.
#define _XOPEN_SOURCE 600
#include <time.h>
int clock_nanosleep(clockid_t clockid,
int flags,
const struct timespec *request,
struct timespec *remain);
/* Returns 0 on success,
positive error number on error or EINTR */
/* flags:
0 β relative sleep (like nanosleep)
TIMER_ABSTIME β absolute sleep (sleep UNTIL this time)
clockid: CLOCK_REALTIME, CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID, etc.
When TIMER_ABSTIME is used, 'remain' is unused/NULL.
Restart the call with the SAME 'request' if interrupted.
Compile: gcc prog.c -o prog -lrt
*/
/* Sleep for 5 seconds from NOW */
struct timespec req = {5, 0};
clock_nanosleep(CLOCK_REALTIME, 0,
&req, &remain);
/* If interrupted, req = remain
then call again β drift possible */
/* Sleep UNTIL a specific time */
clock_gettime(CLOCK_REALTIME, &abs);
abs.tv_sec += 5;
/* If interrupted, call again with
SAME abs β no drift ever */
clock_nanosleep(CLOCK_REALTIME,
TIMER_ABSTIME, &abs, NULL);
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
static void handler(int sig) { (void)sig; }
int main(void) {
struct timespec abs_target;
struct sigaction sa;
int s;
/* Allow SIGINT to interrupt sleep */
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
/* Get current CLOCK_REALTIME value */
clock_gettime(CLOCK_REALTIME, &abs_target);
/* Target = now + 5 seconds */
abs_target.tv_sec += 5;
printf("Sleeping for 5 seconds (absolute mode)...\n");
printf("Press Ctrl-C to interrupt β sleep will resume!\n");
/* Loop to restart on interruption β same abs_target each time */
while ((s = clock_nanosleep(CLOCK_REALTIME,
TIMER_ABSTIME,
&abs_target, NULL)) != 0) {
if (s == EINTR) {
printf("Interrupted β restarting (no drift)...\n");
} else {
perror("clock_nanosleep");
return 1;
}
}
printf("Woke up at the exact target time.\n");
return 0;
}
/* Compile: gcc -o abs_sleep abs_sleep.c -lrt -D_XOPEN_SOURCE=600
Press Ctrl-C multiple times β sleep always ends at correct time */
Run a task exactly every 100ms without any accumulating error.
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <time.h>
#include <errno.h>
#define INTERVAL_NS 100000000L /* 100 ms in nanoseconds */
#define ITERATIONS 10
/* Add nanoseconds to a timespec (handles carry) */
void timespec_add_ns(struct timespec *ts, long ns) {
ts->tv_nsec += ns;
while (ts->tv_nsec >= 1000000000L) {
ts->tv_nsec -= 1000000000L;
ts->tv_sec++;
}
}
int main(void) {
struct timespec next_wake;
struct timespec now;
int i, s;
/* Set first wake-up = now + 100ms */
clock_gettime(CLOCK_MONOTONIC, &next_wake);
timespec_add_ns(&next_wake, INTERVAL_NS);
for (i = 1; i <= ITERATIONS; i++) {
/* Sleep until next_wake (absolute) */
do {
s = clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME,
&next_wake, NULL);
} while (s == EINTR); /* Restart if interrupted */
if (s != 0) { perror("clock_nanosleep"); return 1; }
/* Do the periodic work */
clock_gettime(CLOCK_MONOTONIC, &now);
printf("Tick %2d at %ld.%06ld s\n",
i, now.tv_sec, now.tv_nsec / 1000);
/* Advance next target by one interval */
timespec_add_ns(&next_wake, INTERVAL_NS);
}
return 0;
}
/* Output (ticks at precise 100ms intervals):
Tick 1 at 12345.100123 s
Tick 2 at 12345.200089 s
Tick 3 at 12345.300104 s
...
Intervals stay steady β no accumulated error */
Compare relative nanosleep() vs absolute clock_nanosleep() over 10 iterations.
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <time.h>
#include <errno.h>
#define ITERS 10
#define SLEEP_NS 10000000L /* 10 ms */
int main(void) {
struct timespec req = {0, SLEEP_NS};
struct timespec start, now, abs_target;
long expected_us, actual_us;
/* --- Method 1: relative nanosleep() --- */
printf("=== Relative nanosleep() ===\n");
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 1; i <= ITERS; i++) {
nanosleep(&req, NULL);
clock_gettime(CLOCK_MONOTONIC, &now);
actual_us = (now.tv_sec - start.tv_sec) * 1000000L
+ (now.tv_nsec - start.tv_nsec) / 1000L;
expected_us = i * (SLEEP_NS / 1000);
printf("Iter %2d: expected %ld Β΅s, actual %ld Β΅s, drift %+ld Β΅s\n",
i, expected_us, actual_us, actual_us - expected_us);
}
/* --- Method 2: absolute clock_nanosleep() --- */
printf("\n=== Absolute clock_nanosleep(TIMER_ABSTIME) ===\n");
clock_gettime(CLOCK_MONOTONIC, &start);
abs_target = start;
for (int i = 1; i <= ITERS; i++) {
abs_target.tv_nsec += SLEEP_NS;
while (abs_target.tv_nsec >= 1000000000L) {
abs_target.tv_nsec -= 1000000000L;
abs_target.tv_sec++;
}
int s;
do { s = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
&abs_target, NULL);
} while (s == EINTR);
clock_gettime(CLOCK_MONOTONIC, &now);
actual_us = (now.tv_sec - start.tv_sec) * 1000000L
+ (now.tv_nsec - start.tv_nsec) / 1000L;
expected_us = i * (SLEEP_NS / 1000);
printf("Iter %2d: expected %ld Β΅s, actual %ld Β΅s, drift %+ld Β΅s\n",
i, expected_us, actual_us, actual_us - expected_us);
}
return 0;
}
/* Absolute method shows near-zero cumulative drift across all iterations */
clock_nanosleep() supports absolute time mode via TIMER_ABSTIME, and lets you choose the clock (REALTIME, MONOTONIC, etc.). nanosleep() is always relative and uses CLOCK_REALTIME implicitly.
With absolute mode, you always target a fixed future point. When interrupted and restarted, the same target is passed β the OS automatically handles the case where the target time has already passed (fires immediately). No rounding error accumulates.
CLOCK_MONOTONIC β it never jumps, never goes backward, and is not affected by NTP adjustments. CLOCK_REALTIME could cause unexpected long sleeps if the clock jumps backward.
With TIMER_ABSTIME: just call clock_nanosleep() again with the SAME absolute target β no modification needed. The remain parameter is not used. Without TIMER_ABSTIME: copy remain to request and call again.
