--- /dev/null
+/* $OpenBSD: time.h,v 1.36 2016/09/12 19:41:20 guenther Exp $ */
+/* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)time.h 8.2 (Berkeley) 7/10/94
+ */
+
+/* Operations on timespecs. */
+#ifndef timespecclear
+#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0
+#endif
+
+#ifndef timespecisset
+#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
+#endif
+
+#ifndef timespeccmp
+#define timespeccmp(tsp, usp, cmp) \
+ (((tsp)->tv_sec == (usp)->tv_sec) ? \
+ ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
+ ((tsp)->tv_sec cmp (usp)->tv_sec))
+#endif
+
+#ifndef timespecadd
+#define timespecadd(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec >= 1000000000L) { \
+ (vsp)->tv_sec++; \
+ (vsp)->tv_nsec -= 1000000000L; \
+ } \
+ } while (0)
+#endif
+
+#ifndef timespecsub
+#define timespecsub(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec < 0) { \
+ (vsp)->tv_sec--; \
+ (vsp)->tv_nsec += 1000000000L; \
+ } \
+ } while (0)
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include <X11/Xlib.h>
+#include "bsdtimespec.h"
+
#define debug(args...) {fprintf(stderr, "[debug] " args);}
#define info( args...) {fprintf(stderr, "[info] " args);}
#define error(args...) {fprintf(stderr, "[error] " args);}
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) {
}
}
+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[])
{
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");
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)
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;