-}
-
-void
-snooze(struct timespec *t, Config *cfg)
-{
- 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));
+ /* 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);
+ }