#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <err.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
void report_relapse(int, struct timespec *, struct timespec *);
void *thread_func(void *);
void thread_spawn(pthread_t **, int, void *(*)(void *));
int
main(int argc, char *argv[])
{
const char *errstr;
pthread_t *thread;
int error, i, nthreads;
if (argc != 2) {
fprintf(stderr, "usage: %s nthreads\n", getprogname());
return 1;
}
nthreads = strtonum(argv[1], 1, INT_MAX, &errstr);
if (errstr != NULL)
errx(1, "nthreads is %s: %s", errstr, argv[1]);
thread = calloc(nthreads, sizeof(*thread));
if (thread == NULL)
err(1, NULL);
for (i = 0; i < nthreads; i++) {
error = pthread_create(&thread[i], NULL, thread_func,
(void *)((uintptr_t)i + 1));
if (error)
errc(1, error, "pthread_create");
}
sleep(10);
return 0;
}
void
report_relapse(int num, struct timespec *before, struct timespec *after)
{
static pthread_mutex_t report_mutex = PTHREAD_MUTEX_INITIALIZER;
struct timespec relapsed;
int error;
error = pthread_mutex_lock(&report_mutex);
if (error)
errc(1, error, "T%d: pthread_mutex_lock", num);
timespecsub(before, after, &relapsed);
errx(1, "T%d: monotonic clock relapsed %.9f seconds: %.9f -> %.9f",
num, relapsed.tv_sec + relapsed.tv_nsec / 1000000000.0,
before->tv_sec + before->tv_nsec / 1000000000.0,
after->tv_sec + after->tv_nsec / 1000000000.0);
}
void *
thread_func(void *arg)
{
struct timespec after, before, timeout;
int num;
timeout.tv_sec = 0;
timeout.tv_nsec = 1;
num = (int)arg;
for (;;) {
clock_gettime(CLOCK_MONOTONIC, &before);
if (nanosleep(&timeout, NULL) == -1)
err(1, "T%d: nanosleep", num);
clock_gettime(CLOCK_MONOTONIC, &after);
if (timespeccmp(&after, &before, <))
report_relapse(num, &before, &after);
}
return NULL;
}