X-Git-Url: https://git.xandkar.net/?a=blobdiff_plain;f=x5%2Fkhatus.c;h=cc28cba53b212177532b7a366484fa4cb9f583e7;hb=b7487ec5a6f62c0c57836fff6cbaa52b116f0831;hp=2a026dc1626a906ff7dcdb97564846892e9bcc6d;hpb=69b75a40d02e69f77e7a4bf3c9c4b0ad6d35ba70;p=khatus.git diff --git a/x5/khatus.c b/x5/khatus.c index 2a026dc..cc28cba 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -8,10 +8,13 @@ #include #include #include +#include #include #include +#include "bsdtimespec.h" + #define debug(args...) {fprintf(stderr, "[debug] " args);} #define info( args...) {fprintf(stderr, "[info] " args);} #define error(args...) {fprintf(stderr, "[error] " args);} @@ -178,14 +181,20 @@ void parse_opts_opt(Config *cfg, int argc, char *argv[], int i) { switch (argv[i][1]) { - case 'i': parse_opts_opt_i(cfg, argc, argv, ++i); break; /* TODO: Generic set_int */ - case 's': parse_opts_opt_s(cfg, argc, argv, ++i); break; /* TODO: Generic set_str */ - case 'x': { + case 'i': + /* TODO: Generic set_int */ + parse_opts_opt_i(cfg, argc, argv, ++i); + break; + case 's': + /* TODO: Generic set_str */ + parse_opts_opt_s(cfg, argc, argv, ++i); + break; + case 'x': cfg->output_to_x_root_window = 1; opts_parse_any(cfg, argc, argv, ++i); break; - } - default : usage("Option \"%s\" is invalid\n", argv[i]); + default : + usage("Option \"%s\" is invalid\n", argv[i]); } } @@ -227,8 +236,11 @@ opts_parse_any(Config *cfg, int argc, char *argv[], int i) { if (i < argc) { switch (argv[i][0]) { - case '-': parse_opts_opt(cfg, argc, argv, i); break; - default : parse_opts_spec(cfg, argc, argv, i); + case '-': + parse_opts_opt(cfg, argc, argv, i); + break; + default : + parse_opts_spec(cfg, argc, argv, i); } } } @@ -276,14 +288,14 @@ fifo_read_one(Fifo *f, char *buf) total = 0; c = '\0'; b = buf + f->pos; - /* TODO: Could optimize here and only blank-out the remaining slots. */ - memset(b, ' ', f->width); while ((current = read(f->fd, &c, 1)) && c != '\n' && c != '\0' && total++ < f->width) *b++ = c; if (current == -1) { error("Failed to read: \"%s\". Error: %s\n", f->name, strerror(errno)); fifo_read_error(f, buf); - } + } else + while (total++ < f->width) + *b++ = ' '; /* TODO Record timestamp read */ close(f->fd); f->fd = -1; @@ -298,7 +310,6 @@ fifo_read_all(Config *cfg, char *buf) struct stat st; FD_ZERO(&fds); - /* TODO: Check TTL */ for (Fifo *f = cfg->fifos; f; f = f->next) { /* TODO: Create the FIFO if it doesn't already exist. */ if (lstat(f->name, &st) < 0) { @@ -338,6 +349,29 @@ fifo_read_all(Config *cfg, char *buf) } } +void +snooze(struct timespec *t) +{ + struct timespec remainder; + int result; + + result = nanosleep(t, &remainder); + + if (result < 0) { + if (errno == EINTR) { + info( + "nanosleep interrupted. Remainder: " + "{ tv_sec = %ld, tv_nsec = %ld }", + remainder.tv_sec, remainder.tv_nsec); + /* No big deal if we occasionally sleep less, + * so not attempting to correct after an interruption. + */ + } else { + fatal("nanosleep: %s\n", strerror(errno)); + } + } +} + int main(int argc, char *argv[]) { @@ -351,12 +385,23 @@ main(int argc, char *argv[]) Config *cfg = &cfg0; Display *display = NULL; struct stat st; + struct timespec + t0, /* time stamp. before reading fifos */ + t1, /* time stamp. after reading fifos */ + ti, /* time interval desired (t1 - t0) */ + td, /* time interval measured (t1 - t0) */ + tc; /* time interval correction (ti - td) when td < ti */ argv0 = argv[0]; opts_parse(cfg, argc, argv); debug("argv0 = %s\n", argv0); config_print(cfg); + + /* TODO: Support interval < 1. i.e. implement timespec_of_float */ + ti.tv_sec = cfg->interval; + ti.tv_nsec = 0; + if (cfg->fifos == NULL) usage("No fifo specs were given!\n"); @@ -401,14 +446,15 @@ main(int argc, char *argv[]) if (cfg->output_to_x_root_window && !(display = XOpenDisplay(NULL))) fatal("XOpenDisplay failed with: %p\n", display); - /* TODO: nanosleep and nano time diff */ /* TODO: Handle signals */ for (;;) { - /* TODO: Check TTL and maybe blank-out */ + clock_gettime(CLOCK_MONOTONIC, &t0); // FIXME: check errors + /* TODO: Cache expiration. i.e. use the TTL */ /* TODO: How to trigger TTL check? On select? Alarm signal? */ /* TODO: Set timeout on fifo_read_all based on diff of last time of * fifo_read_all and desired time of next TTL check. - * */ + */ + /* TODO: How long to wait on IO? Max TTL? */ fifo_read_all(cfg, buf); if (cfg->output_to_x_root_window) { if (XStoreName(display, DefaultRootWindow(display), buf) < 0) @@ -418,6 +464,18 @@ main(int argc, char *argv[]) puts(buf); fflush(stdout); } + clock_gettime(CLOCK_MONOTONIC, &t1); // FIXME: check errors + timespecsub(&t1, &t0, &td); + debug("td {tv_sec = %ld, tv_nsec = %ld}\n", td.tv_sec, td.tv_nsec); + if (timespeccmp(&td, &ti, <)) { + /* Pushback on data producers by refusing to read the + * pipe more frequently than the interval. + */ + timespecsub(&ti, &td, &tc); + debug("snooze YES\n"); + snooze(&tc); + } else + debug("snooze NO\n"); } return EXIT_SUCCESS;