how can I pause and then resume a call to `sleep`
sleep(3)
returns the number of seconds remaining if it was interrupted by a signal, but seconds are poor granularity, so it's better to use clock_nanosleep(2)
.
clock_nanosleep
also has the advantage of allowing you to specify what kind of clock you want to sleep with - there are at least 7 different clocks, each useful in different circumstances. Chances are you want CLOCK_MONOTONIC
though. (Note that you use no CPU time while sleeping, so you definitely don't want CLOCK_PROCESS_CPUTIME_ID
(it would be meaningful in a multithreaded process))
Quoting the latter man page:
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.
Edit: I ended up writing a program demonstrating what you need to do, as well as the difference between the various clocks:
/* Requires adding -pthread -lrt to your command line. */#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; /* We don't actually need to do anything, just the presence of the signal handler is enough to make `clock_nanosleep` return. However, because somebody requested that we stop, we *should* listen to them and actually stop. */ raise(SIGSTOP);}void do_sleep(struct timespec *total){ int not_errno; struct sigaction act; memset(&act, '\0', sizeof(act)); act.sa_handler = signal_handler; /* TODO - it is impossible to catch SIGSTOP, is there another way? */ sigaction(SIGTSTP, &act, NULL); sigaction(SIGTTIN, &act, NULL); sigaction(SIGTTOU, &act, NULL); /* Note: synchronous methods of signal handling do *not* work here. The `clock_nanosleep` will just resume silently in that case. Using `sigtimedwait` does not directly give is a `remain` value. */ do { /* Important note: clock_nanosleep does *not* use `errno`. */ 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; /* TODO instead of truncating extra precision, round up? */ } 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;}
Output:
$ ./nanosleep 1.2clock start end diff res CLOCK_REALTIME 1461281943.302055558 1461281944.502279160 1.200223602 0.000000001CLOCK_REALTIME 1461281943.302055558 1461281944.502279160 1.200223602 0.000000001CLOCK_REALTIME_COARSE 1461281943.299600851 1461281944.499668121 1.200067270 0.004000000CLOCK_MONOTONIC 130817.112863848 130818.313087604 1.200223756 0.000000001CLOCK_MONOTONIC_COARSE 130817.110408795 130818.310476065 1.200067270 0.004000000CLOCK_MONOTONIC_RAW 130809.723951252 130810.924108013 1.200156761 0.000000001CLOCK_BOOTTIME 198571.683842245 198572.884067547 1.200225302 0.000000001CLOCK_PROCESS_CPUTIME_ID 0.002856240 0.002900410 0.000044170 0.000000001CLOCK_THREAD_CPUTIME_ID 0.002857132 0.002903159 0.000046027 0.000000001clock_getcpuclockid 0.002857981 0.002905128 0.000047147 0.000000001pthread_getcpuclockid 0.002858526 0.002908051 0.000049525 0.000000001
Sorry I don't know the right solution.But I have an idea, I hope to help you.
If the code is below
{ ... sleep(10); ...}
The code maybe will become three part.sample code as below:
{//change code ... sleep_thread(); mutex_lock(&sleep_mutex); ...}{//sleep thread mutex_lock(&sleep_mutex); sleep(10); mutex_unlock(&sleep_mutex);}{//handle signal if(receive_signal == SIGUSR) mutex_unlock(&sleep_mutex);}