X-Git-Url: https://git.xandkar.net/?a=blobdiff_plain;f=x5%2Fkhatus.c;h=2445c1b918298fdfcaf7a76d4d41927c17adfafd;hb=51e63a6f4abb7090146eff8a0294375ec9525205;hp=5caae33d698edc1d4d4abf1e1a1035c7629ef46f;hpb=4bfac488ba99787df53cf6b8627b0192921309cf;p=khatus.git diff --git a/x5/khatus.c b/x5/khatus.c index 5caae33..2445c1b 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -121,29 +121,29 @@ slot_expire(Slot *s, struct timespec t, char *buf) timespecsub(&t, &(s->in_last_read), &td); if (timespeccmp(&td, &(s->out_ttl), >=)) { /* TODO: Maybe configurable expiry character. */ - memset(buf + s->out_pos_lo, '_', s->out_pos_hi - s->out_pos_lo); + memset(buf + s->out_pos_lo, '_', s->out_width); khlib_warn("Slot expired: \"%s\"\n", s->in_fifo); } } void -slot_read_error(Slot *s, char *buf) +slot_set_error(Slot *s, char *buf) { char *b; int i; + s->in_fd = -1; b = buf + s->out_pos_lo; /* Copy as much of the error message as possible. * EXCLUDING the terminating \0. */ for (i = 0; i < errlen && i < s->out_width; i++) b[i] = errmsg[i]; /* Any remaining positions: */ - for (; i < s->out_width; i++) - b[i] = '_'; + memset(b + i, '_', s->out_width - i); } enum read_status -slot_read(Slot *s, struct timespec t, char *buf) +slot_read(Slot *s, char *buf) { char c; /* Character read. */ int r; /* Remaining unused positions in buffer range. */ @@ -171,21 +171,21 @@ slot_read(Slot *s, struct timespec t, char *buf) case 1: /* TODO: Consider making msg term char a CLI option */ if (c == '\n' || c == '\0') { - r = s->out_pos_hi - s->out_pos_cur; + r = (s->out_pos_hi - s->out_pos_cur) + 1; if (r > 0) memset(buf + s->out_pos_cur, ' ', r); - s->out_pos_cur = s->out_pos_lo; - s->in_last_read = t; return END_OF_MESSAGE; } else { if (s->out_pos_cur <= s->out_pos_hi) buf[s->out_pos_cur++] = c; - /* Drop beyond available range. */ - /* - * TODO Define max after which we stop reading. - * To ensure that a rogue large message - * doesn't trap us here. - */ + else + /* + * Force EOM beyond available range. + * To ensure that a rogue large message + * doesn't trap us here needlessly + * long. + */ + return END_OF_MESSAGE; } break; default: @@ -213,12 +213,12 @@ slots_read(Config *cfg, struct timespec *ti, char *buf) s->in_fifo, strerror(errno) ); - slot_read_error(s, buf); + slot_set_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); + slot_set_error(s, buf); continue; } if (s->in_fd < 0) { @@ -238,7 +238,7 @@ slots_read(Config *cfg, struct timespec *ti, char *buf) 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); + slot_set_error(s, buf); continue; } khlib_debug("%s: open. in_fd: %d\n", s->in_fifo, s->in_fd); @@ -273,9 +273,11 @@ slots_read(Config *cfg, struct timespec *ti, char *buf) /* At-least-once ensures that expiries are still checked on timeouts. */ do { for (s = cfg->slots; s; s = s->next) { + if (s->in_fd < 0) + continue; if (FD_ISSET(s->in_fd, &fds)) { khlib_debug("reading: %s\n", s->in_fifo); - switch (slot_read(s, t, buf)) { + switch (slot_read(s, buf)) { /* * ### MESSAGE LOSS ### * is introduced by closing at EOM in addition @@ -289,12 +291,27 @@ slots_read(Config *cfg, struct timespec *ti, char *buf) * This is an acceptable trade-off because we * are a stateless reporter of a _most-recent_ * status, not a stateful accumulator. + * + * ### LOSSLESS ALTERNATIVES ### + * - Read each pipe until EOF before reading + * another. + * PROBLEM: a fast writer can trap us in the + * read loop. + * + * - Read each pipe until EOM, but close only + * at EOF. + * PROBLEM: a fast writer can fill the pipe + * faster than we can read it and we end-up + * displaying stale data. + * */ case END_OF_MESSAGE: case END_OF_FILE: case FAILURE: close(s->in_fd); - s->in_fd = -1; + s->in_fd = -1; + s->in_last_read = t; + s->out_pos_cur = s->out_pos_lo; ready--; break; case RETRY: