Calling sleep(10)
means to sleep for the specified number of seconds. When I type "sleep 10" I suppose to wait 10 seconds but when I'm using CTRL-Z (or sending SIGTSTP
) right after sleep command, it won't stop the "timer" (or the counter) even though that the process has stopped.
I can see via jobs
that the status of sleep
has changed to STOPPED
but if I'll wait 10 seconds and then send this process to the foreground it will finish immediately, even though it run less then 10 seconds.
So, my question is how can I stop sleep timer from running??
Update:: I Understand now that sleep is using wall-clock time, so how can I implement sleep with a user cpu time
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.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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With