- fd_set fds;
- int maxfd = -1;
- int ready = 0;
- struct stat st;
- struct timespec t;
- Slot *s;
-
- FD_ZERO(&fds);
- for (s = cfg->slots; s; s = s->next) {
- /* TODO: Create the FIFO if it doesn't already exist. */
- if (lstat(s->in_fifo, &st) < 0) {
- khlib_error(
- "Cannot stat \"%s\". Error: %s\n",
- s->in_fifo,
- strerror(errno)
- );
- slot_read_error(s, buf);
- continue;
- }
- if (!(st.st_mode & S_IFIFO)) {
- khlib_error("\"%s\" is not a FIFO\n", s->in_fifo);
- slot_read_error(s, buf);
- continue;
- }
- if (s->in_fd < 0) {
- khlib_debug(
- "%s: closed. opening. in_fd: %d\n",
- s->in_fifo,
- s->in_fd
- );
- s->in_fd = open(s->in_fifo, O_RDONLY | O_NONBLOCK);
- } else {
- khlib_debug(
- "%s: already openned. in_fd: %d\n",
- s->in_fifo,
- s->in_fd
- );
- }
- if (s->in_fd == -1) {
- /* TODO Consider backing off retries for failed slots */
- khlib_error("Failed to open \"%s\"\n", s->in_fifo);
- slot_read_error(s, buf);
- continue;
- }
- khlib_debug("%s: open. in_fd: %d\n", s->in_fifo, s->in_fd);
- if (s->in_fd > maxfd)
- maxfd = s->in_fd;
- FD_SET(s->in_fd, &fds);
- }
- khlib_debug("selecting...\n");
- ready = pselect(maxfd + 1, &fds, NULL, NULL, ti, NULL);
- khlib_debug("ready: %d\n", ready);
- clock_gettime(CLOCK_MONOTONIC, &t);
- if (ready == -1) {
- switch (errno) {
- case EINTR:
- khlib_error(
- "pselect temp failure: %d, errno: %d, msg: %s\n",
- ready,
- errno,
- strerror(errno)
- );
- /* TODO: Reconsider what to do here. */
- return;
- default:
- khlib_fatal(
- "pselect failed: %d, errno: %d, msg: %s\n",
- ready,
- errno,
- strerror(errno)
- );
- }
- }
- /* At-least-once ensures that expiries are still checked on timeouts. */
- do {
- for (s = cfg->slots; s; s = s->next) {
- if (FD_ISSET(s->in_fd, &fds)) {
- khlib_debug("reading: %s\n", s->in_fifo);
- switch (slot_read(s, t, buf)) {
- /*
- * ### MESSAGE LOSS ###
- * is introduced by closing at EOM in addition
- * to EOF, since there may be unread messages
- * remaining in the pipe. However,
- *
- * ### INTER-MESSAGE PUSHBACK ###
- * is also gained, since pipes block at the
- * "open" call.
- *
- * This is an acceptable trade-off because we
- * are a stateless reporter of a _most-recent_
- * status, not a stateful accumulator.
- */
- case END_OF_MESSAGE:
- case END_OF_FILE:
- case FAILURE:
- close(s->in_fd);
- s->in_fd = -1;
- ready--;
- break;
- case RETRY:
- break;
- default:
- assert(0);
- }
- } else {
- slot_expire(s, t, buf);
- }
- }
- } while (ready);
- assert(ready == 0);
-}
-
-int
-main(int argc, char *argv[])
-{
- Config cfg = {
- .interval = 1.0,
- .separator = "|",
- .slots = NULL,
- .slot_count = 0,
- .total_width = 0,
- .output_to_x_root_window = 0,
- };
-
- int width = 0;
- int nslots = 0;
- int seplen = 0;
- int prefix = 0;
- int errors = 0;
- char *buf;
- Display *d = NULL;
- struct stat st;