aboutsummaryrefslogtreecommitdiffstats
path: root/sleep-until.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sleep-until.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/sleep-until.c b/sleep-until.c
new file mode 100644
index 0000000..88124ac
--- /dev/null
+++ b/sleep-until.c
@@ -0,0 +1,118 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/timerfd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+int
+main(int argc, char *argv[])
+{
+ char *argv0;
+ char float_part[10];
+ struct itimerspec value;
+ struct itimerspec largest_value;
+ int i, fd = -1, clocks = 0;
+ uint64_t overrun;
+ int clockid = CLOCK_REALTIME;
+ const char *clockstr = "CLOCK_REALTIME";
+ char *p1, *p2, excess;
+ size_t len;
+
+ argv0 = *argv++, argc--;
+ if (*argv && **argv == '-') {
+ if (argv[0][1] == '-' && !argv[0][2]) {
+ argv++, argc--;
+ } else {
+ fprintf(stderr, "usage: %s [clock | timepoint] ...", argv0);
+ return 1;
+ }
+ }
+
+ if (!argc)
+ return 0;
+
+ memset(&value, 0, sizeof(value));
+ float_part[9] = '\0';
+ for (i = 0; i < argc; i++) {
+ p1 = argv[i];
+
+ if (strstr(p1, "CLOCK_") != p1)
+ goto parse_time;
+#define X(C)\
+ else if (!strcmp(p1, #C))\
+ clockid = C, clockstr = #C;
+#include "clocks.h"
+#undef X
+ else
+ clockid = -1, clockstr = "invalid";
+ clocks++;
+ continue;
+
+ parse_time:
+ if ((p2 = strchr(p1, '.')))
+ *p2++ = '\0';
+
+ value.it_value.tv_sec = (time_t)atoll(p1);
+
+ if (p2) {
+ len = strlen(p2);
+ memset(float_part, '0', 9 * sizeof(char));
+ excess = len > 9 ? p2[9] : '0';
+ len = len > 9 ? 9 : len;
+ memcpy(float_part + 9 - len, p2, len * sizeof(char));
+ value.it_value.tv_nsec = atol(float_part);
+ if ((excess >= '5') && (value.it_value.tv_nsec++ == 999999999L))
+ value.it_value.tv_nsec = 0, value.it_value.tv_sec++;
+ }
+
+ if (i == clocks)
+ largest_value = value;
+ else if (value.it_value.tv_sec > largest_value.it_value.tv_sec)
+ largest_value = value;
+ else if (value.it_value.tv_sec == largest_value.it_value.tv_sec)
+ if (value.it_value.tv_nsec > largest_value.it_value.tv_nsec)
+ largest_value = value;
+ }
+
+ if (clocks == argc)
+ return 0;
+
+ fd = timerfd_create(clockid, 0);
+ if (fd < 0)
+ goto fail;
+ if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &largest_value, NULL))
+ goto fail;
+
+ if (clock_gettime(clockid, &(value.it_value)) == 0)
+ fprintf(stderr, "%s: sleeping until %lli.%09li (current time: %lli.%09li, clock: %s)\n",
+ argv0, (long long int)(largest_value.it_value.tv_sec), largest_value.it_value.tv_nsec,
+ (long long int)(value.it_value.tv_sec), value.it_value.tv_nsec, clockstr);
+
+ for (;;) {
+ if (clock_gettime(clockid, &(value.it_value)))
+ goto fail;
+ if (value.it_value.tv_sec > largest_value.it_value.tv_sec)
+ break;
+ if (value.it_value.tv_sec == largest_value.it_value.tv_sec)
+ if (value.it_value.tv_nsec >= largest_value.it_value.tv_nsec)
+ break;
+ if (read(fd, &overrun, (size_t)8) < 8) {
+ if (errno == EINTR)
+ continue;
+ goto fail;
+ }
+ }
+
+ close(fd);
+ return 0;
+
+fail:
+ perror(argv0);
+ if (fd >= 0)
+ close(fd);
+ return 1;
+}