sleep(3)returns the remaining number of seconds if it was interrupted by a signal, but seconds are poor granularity, so it is better to use clock_nanosleep(2).
clock_nanosleep , , , - 7 , . , CLOCK_MONOTONIC. ( , , CLOCK_PROCESS_CPUTIME_ID ( ))
:
If the call is interrupted by a signal handler, clock_nanosleep() fails
with the error EINTR. In addition, if remain is not NULL, and flags
was not TIMER_ABSTIME, it returns the remaining unslept time in remain.
This value can then be used to call clock_nanosleep() again and com‐
plete a (relative) sleep.
: , , , :
#define _POSIX_C_SOURCE 200112L
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct all_times
{
struct timespec realtime;
#ifdef CLOCK_REALTIME_COARSE
struct timespec realtime_coarse;
#endif
struct timespec monotonic;
#ifdef CLOCK_MONOTONIC_COARSE
struct timespec monotonic_coarse;
#endif
#ifdef CLOCK_MONOTONIC_RAW
struct timespec monotonic_raw;
#endif
#ifdef CLOCK_BOOTTIME
struct timespec boottime;
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
struct timespec process_cputime_id;
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
struct timespec thread_cputime_id;
#endif
struct timespec clock_getcpuclockid;
struct timespec pthread_getcpuclockid;
};
void get_all_times(struct all_times *times)
{
clockid_t clock;
struct timespec *spec;
memset(times, '\0', sizeof(*times));
clock = CLOCK_REALTIME;
spec = ×->realtime;
clock_gettime(clock, spec);
#ifdef CLOCK_REALTIME_COARSE
clock = CLOCK_REALTIME_COARSE;
spec = ×->realtime_coarse;
clock_gettime(clock, spec);
#endif
clock = CLOCK_MONOTONIC;
spec = ×->monotonic;
clock_gettime(clock, spec);
#ifdef CLOCK_MONOTONIC_COARSE
clock = CLOCK_MONOTONIC_COARSE;
spec = ×->monotonic_coarse;
clock_gettime(clock, spec);
#endif
#ifdef CLOCK_MONOTONIC_RAW
clock = CLOCK_MONOTONIC_RAW;
spec = ×->monotonic_raw;
clock_gettime(clock, spec);
#endif
#ifdef CLOCK_BOOTTIME
clock = CLOCK_BOOTTIME;
spec = ×->boottime;
clock_gettime(clock, spec);
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
clock = CLOCK_PROCESS_CPUTIME_ID;
spec = ×->process_cputime_id;
clock_gettime(clock, spec);
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
clock = CLOCK_THREAD_CPUTIME_ID;
spec = ×->thread_cputime_id;
clock_gettime(clock, spec);
#endif
clock_getcpuclockid(0, &clock);
spec = ×->clock_getcpuclockid;
clock_gettime(clock, spec);
pthread_getcpuclockid(pthread_self(), &clock);
spec = ×->pthread_getcpuclockid;
clock_gettime(clock, spec);
}
void get_all_res(struct all_times *times)
{
clockid_t clock;
struct timespec *spec;
memset(times, '\0', sizeof(*times));
clock = CLOCK_REALTIME;
spec = ×->realtime;
clock_getres(clock, spec);
#ifdef CLOCK_REALTIME_COARSE
clock = CLOCK_REALTIME_COARSE;
spec = ×->realtime_coarse;
clock_getres(clock, spec);
#endif
clock = CLOCK_MONOTONIC;
spec = ×->monotonic;
clock_getres(clock, spec);
#ifdef CLOCK_MONOTONIC_COARSE
clock = CLOCK_MONOTONIC_COARSE;
spec = ×->monotonic_coarse;
clock_getres(clock, spec);
#endif
#ifdef CLOCK_MONOTONIC_RAW
clock = CLOCK_MONOTONIC_RAW;
spec = ×->monotonic_raw;
clock_getres(clock, spec);
#endif
#ifdef CLOCK_BOOTTIME
clock = CLOCK_BOOTTIME;
spec = ×->boottime;
clock_getres(clock, spec);
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
clock = CLOCK_PROCESS_CPUTIME_ID;
spec = ×->process_cputime_id;
clock_getres(clock, spec);
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
clock = CLOCK_THREAD_CPUTIME_ID;
spec = ×->thread_cputime_id;
clock_getres(clock, spec);
#endif
clock_getcpuclockid(0, &clock);
spec = ×->clock_getcpuclockid;
clock_getres(clock, spec);
pthread_getcpuclockid(pthread_self(), &clock);
spec = ×->pthread_getcpuclockid;
clock_getres(clock, spec);
}
void diff_time(const struct timespec *start, const struct timespec *end, struct timespec *diff)
{
diff->tv_sec = end->tv_sec - start->tv_sec;
diff->tv_nsec = end->tv_nsec - start->tv_nsec;
if (diff->tv_nsec < 0)
{
diff->tv_nsec += 1000 * 1000 * 1000;
diff->tv_sec--;
}
assert (diff->tv_sec >= 0);
assert (diff->tv_nsec >= 0);
}
void diff_all_times(const struct all_times *start, const struct all_times *end, struct all_times *diff)
{
diff_time(&start->realtime, &end->realtime, &diff->realtime);
diff_time(&start->realtime, &end->realtime, &diff->realtime);
#ifdef CLOCK_REALTIME_COARSE
diff_time(&start->realtime_coarse, &end->realtime_coarse, &diff->realtime_coarse);
#endif
diff_time(&start->monotonic, &end->monotonic, &diff->monotonic);
#ifdef CLOCK_MONOTONIC_COARSE
diff_time(&start->monotonic_coarse, &end->monotonic_coarse, &diff->monotonic_coarse);
#endif
#ifdef CLOCK_MONOTONIC_RAW
diff_time(&start->monotonic_raw, &end->monotonic_raw, &diff->monotonic_raw);
#endif
#ifdef CLOCK_BOOTTIME
diff_time(&start->boottime, &end->boottime, &diff->boottime);
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
diff_time(&start->process_cputime_id, &end->process_cputime_id, &diff->process_cputime_id);
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
diff_time(&start->thread_cputime_id, &end->thread_cputime_id, &diff->thread_cputime_id);
#endif
diff_time(&start->clock_getcpuclockid, &end->clock_getcpuclockid, &diff->clock_getcpuclockid);
diff_time(&start->pthread_getcpuclockid, &end->pthread_getcpuclockid, &diff->pthread_getcpuclockid);
}
void print_all_times(const struct all_times *start, const struct all_times *end, const struct all_times *diff, const struct all_times *res)
{
printf("%-27s %15s %-9s %15s %-9s %5s %-9s %5s %-9s\n", "clock", "", "start", "", "end", "", "diff", "", "res");
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_REALTIME", (long long)start->realtime.tv_sec, start->realtime.tv_nsec, (long long)end->realtime.tv_sec, end->realtime.tv_nsec, (long long)diff->realtime.tv_sec, diff->realtime.tv_nsec, (long long)res->realtime.tv_sec, res->realtime.tv_nsec);
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_REALTIME", (long long)start->realtime.tv_sec, start->realtime.tv_nsec, (long long)end->realtime.tv_sec, end->realtime.tv_nsec, (long long)diff->realtime.tv_sec, diff->realtime.tv_nsec, (long long)res->realtime.tv_sec, res->realtime.tv_nsec);
#ifdef CLOCK_REALTIME_COARSE
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_REALTIME_COARSE", (long long)start->realtime_coarse.tv_sec, start->realtime_coarse.tv_nsec, (long long)end->realtime_coarse.tv_sec, end->realtime_coarse.tv_nsec, (long long)diff->realtime_coarse.tv_sec, diff->realtime_coarse.tv_nsec, (long long)res->realtime_coarse.tv_sec, res->realtime_coarse.tv_nsec);
#else
printf("%-27s (not available)\n", "CLOCK_REALTIME_COARSE");
#endif
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_MONOTONIC", (long long)start->monotonic.tv_sec, start->monotonic.tv_nsec, (long long)end->monotonic.tv_sec, end->monotonic.tv_nsec, (long long)diff->monotonic.tv_sec, diff->monotonic.tv_nsec, (long long)res->monotonic.tv_sec, res->monotonic.tv_nsec);
#ifdef CLOCK_MONOTONIC_COARSE
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_MONOTONIC_COARSE", (long long)start->monotonic_coarse.tv_sec, start->monotonic_coarse.tv_nsec, (long long)end->monotonic_coarse.tv_sec, end->monotonic_coarse.tv_nsec, (long long)diff->monotonic_coarse.tv_sec, diff->monotonic_coarse.tv_nsec, (long long)res->monotonic_coarse.tv_sec, res->monotonic_coarse.tv_nsec);
#else
printf("%-27s (not available)\n", "CLOCK_MONOTONIC_COARSE");
#endif
#ifdef CLOCK_MONOTONIC_RAW
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_MONOTONIC_RAW", (long long)start->monotonic_raw.tv_sec, start->monotonic_raw.tv_nsec, (long long)end->monotonic_raw.tv_sec, end->monotonic_raw.tv_nsec, (long long)diff->monotonic_raw.tv_sec, diff->monotonic_raw.tv_nsec, (long long)res->monotonic_raw.tv_sec, res->monotonic_raw.tv_nsec);
#else
printf("%-27s (not available)\n", "CLOCK_MONOTONIC_RAW");
#endif
#ifdef CLOCK_BOOTTIME
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_BOOTTIME", (long long)start->boottime.tv_sec, start->boottime.tv_nsec, (long long)end->boottime.tv_sec, end->boottime.tv_nsec, (long long)diff->boottime.tv_sec, diff->boottime.tv_nsec, (long long)res->boottime.tv_sec, res->boottime.tv_nsec);
#else
printf("%-27s (not available)\n", "CLOCK_BOOTTIME");
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_PROCESS_CPUTIME_ID", (long long)start->process_cputime_id.tv_sec, start->process_cputime_id.tv_nsec, (long long)end->process_cputime_id.tv_sec, end->process_cputime_id.tv_nsec, (long long)diff->process_cputime_id.tv_sec, diff->process_cputime_id.tv_nsec, (long long)res->process_cputime_id.tv_sec, res->process_cputime_id.tv_nsec);
#else
printf("%-27s (not available)\n", "CLOCK_PROCESS_CPUTIME_ID");
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "CLOCK_THREAD_CPUTIME_ID", (long long)start->thread_cputime_id.tv_sec, start->thread_cputime_id.tv_nsec, (long long)end->thread_cputime_id.tv_sec, end->thread_cputime_id.tv_nsec, (long long)diff->thread_cputime_id.tv_sec, diff->thread_cputime_id.tv_nsec, (long long)res->thread_cputime_id.tv_sec, res->thread_cputime_id.tv_nsec);
#else
printf("%-27s (not available)\n", "CLOCK_THREAD_CPUTIME_ID");
#endif
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "clock_getcpuclockid", (long long)start->clock_getcpuclockid.tv_sec, start->clock_getcpuclockid.tv_nsec, (long long)end->clock_getcpuclockid.tv_sec, end->clock_getcpuclockid.tv_nsec, (long long)diff->clock_getcpuclockid.tv_sec, diff->clock_getcpuclockid.tv_nsec, (long long)res->clock_getcpuclockid.tv_sec, res->clock_getcpuclockid.tv_nsec);
printf("%-27s %15lld.%09ld %15lld.%09ld %5lld.%09ld %5lld.%09ld\n", "pthread_getcpuclockid", (long long)start->pthread_getcpuclockid.tv_sec, start->pthread_getcpuclockid.tv_nsec, (long long)end->pthread_getcpuclockid.tv_sec, end->pthread_getcpuclockid.tv_nsec, (long long)diff->pthread_getcpuclockid.tv_sec, diff->pthread_getcpuclockid.tv_nsec, (long long)res->pthread_getcpuclockid.tv_sec, res->pthread_getcpuclockid.tv_nsec);
}
void signal_handler(int sig)
{
(void)sig;
raise(SIGSTOP);
}
void do_sleep(struct timespec *total)
{
int not_errno;
struct sigaction act;
memset(&act, '\0', sizeof(act));
act.sa_handler = signal_handler;
sigaction(SIGTSTP, &act, NULL);
sigaction(SIGTTIN, &act, NULL);
sigaction(SIGTTOU, &act, NULL);
do
{
not_errno = clock_nanosleep(CLOCK_MONOTONIC, 0, total, total);
}
while (not_errno == EINTR);
}
static void die(const char *msg)
{
printf("%s\n", msg);
exit(1);
}
static void parse_time(char *str, struct timespec *spec)
{
unsigned long long sec, nsec, multiplier;
char *end;
if (!isdigit(str[0]))
{
die("Non-numeric character at start of duration.");
}
errno = 0;
sec = strtoull(str, &end, 10);
spec->tv_sec = sec;
if (errno || (unsigned long long)spec->tv_sec != sec)
{
die("Out-of-range duration.");
}
if (*end == '\0')
{
spec->tv_nsec = 0;
return;
}
if (*end != '.')
{
die("Non-numeric character in duration.");
}
++end;
multiplier = 100 * 1000 * 1000;
nsec = 0;
while (*end)
{
unsigned long long digit = *end - '0';
if (digit >= 10)
{
die("Non-numeric character in fractional duration.");
}
nsec += multiplier * digit;
multiplier /= 10;
++end;
}
spec->tv_nsec = nsec;
}
int main(int argc, char **argv)
{
struct timespec total;
struct all_times start, end, diff, res;
if (argc != 2 || argv[1][0] == '-')
{
die("Usage: ./nanosleep sss[.mmmuuunnn]");
}
parse_time(argv[1], &total);
get_all_res(&res);
get_all_times(&start);
do_sleep(&total);
get_all_times(&end);
diff_all_times(&start, &end, &diff);
print_all_times(&start, &end, &diff, &res);
return 0;
}
:
$ ./nanosleep 1.2
clock start end diff res
CLOCK_REALTIME 1461281943.302055558 1461281944.502279160 1.200223602 0.000000001
CLOCK_REALTIME 1461281943.302055558 1461281944.502279160 1.200223602 0.000000001
CLOCK_REALTIME_COARSE 1461281943.299600851 1461281944.499668121 1.200067270 0.004000000
CLOCK_MONOTONIC 130817.112863848 130818.313087604 1.200223756 0.000000001
CLOCK_MONOTONIC_COARSE 130817.110408795 130818.310476065 1.200067270 0.004000000
CLOCK_MONOTONIC_RAW 130809.723951252 130810.924108013 1.200156761 0.000000001
CLOCK_BOOTTIME 198571.683842245 198572.884067547 1.200225302 0.000000001
CLOCK_PROCESS_CPUTIME_ID 0.002856240 0.002900410 0.000044170 0.000000001
CLOCK_THREAD_CPUTIME_ID 0.002857132 0.002903159 0.000046027 0.000000001
clock_getcpuclockid 0.002857981 0.002905128 0.000047147 0.000000001
pthread_getcpuclockid 0.002858526 0.002908051 0.000049525 0.000000001