enum read_status
fifo_read_one(Fifo *f, char *buf)
{
- /* Initialize all to an impossible value: */
- ssize_t n = -5; /* Number of bytes read. */
- char c = -1; /* Character read. */
- int r = -1; /* Remaining unused slots in buffer range. */
+ char c; /* Character read. */
+ int r; /* Remaining unused slots in buffer range. */
for (;;) {
- n = read(f->fd, &c, 1);
- assert(n >= -1 && n <= 1);
- switch (n) {
+ switch (read(f->fd, &c, 1)) {
case -1:
error("Failed to read: \"%s\". errno: %d, msg: %s\n",
f->name, errno, strerror(errno));
{
fd_set fds;
int maxfd = -1;
- int ready;
+ int ready = 0;
struct stat st;
FD_ZERO(&fds);
debug("ready: %d\n", ready);
assert(ready != 0);
if (ready < 0)
+ /* TODO: Do we really want to fail here? */
fatal("%s", strerror(errno));
- for (Fifo *f = cfg->fifos; f; f = f->next) {
- if (FD_ISSET(f->fd, &fds)) {
- debug("reading: %s\n", f->name);
- switch (fifo_read_one(f, buf)) {
- case END_OF_FILE:
- case FAILURE:
- close(f->fd);
- f->fd = -1;
- break;
- case END_OF_MESSAGE:
- case RETRY:
- break;
- default:
- assert(0);
+ while (ready) {
+ for (Fifo *f = cfg->fifos; f; f = f->next) {
+ if (FD_ISSET(f->fd, &fds)) {
+ debug("reading: %s\n", f->name);
+ switch (fifo_read_one(f, 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(f->fd);
+ f->fd = -1;
+ ready--;
+ break;
+ case RETRY:
+ break;
+ default:
+ assert(0);
+ }
}
}
}
+ assert(ready == 0);
}
int