commit 926ee8364e8c83d7a22dcd5bceb65e235486703a from: Omar Polo date: Thu May 19 14:43:06 2022 UTC consume all enqueued messages before calling imsg_read player_dispatch reads only one imsg from the ibuf. Next time it's called, the other messages on the ibuf (if any) are discarded and new ones are read. This can cause the player process to go out-of-sync with the main process if multiple messages were "bundled" in the same chunk. To avoid this, always try to imsg_read before. If it succeedes, we read process the equeued messages one by one, if it fails then we poll for new data and call imsg_read to process them and retry. This fixes a bug where amused could be "confused" by running $ amused pause ; amused stop ; amused play in a loop a few times. This bug and the repro were reported two months ago by Dirk-Wilhelm Peters, thanks! (and sorry it took so long to understand and fix the issue) commit - fc4a38afafeec3a23f264e76659b3405d2d7cc48 commit + 926ee8364e8c83d7a22dcd5bceb65e235486703a blob - 5fdc9aaf6d8e883142898ac8286585135a723535 blob + e65ba1ff5f86266696f18deedc4069455e3eae51 --- player.c +++ player.c @@ -146,20 +146,20 @@ player_dispatch(void) if (halted != 0) return IMSG_STOP; - pfd.fd = ibuf->fd; - pfd.events = POLLIN; - if (poll(&pfd, 1, INFTIM) == -1) - fatal("poll"); - - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatalx("imsg_read"); - if (n == 0) - fatalx("pipe closed"); - +again: if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); - if (n == 0) /* no more messages */ - fatalx("expected at least a message"); + if (n == 0) { + pfd.fd = ibuf->fd; + pfd.events = POLLIN; + if (poll(&pfd, 1, INFTIM) == -1) + fatal("poll"); + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read"); + if (n == 0) + fatalx("pipe closed"); + goto again; + } ret = imsg.hdr.type; switch (imsg.hdr.type) {