Two fixes in os/src/pipe.rs:
-
PipeReceiver::poll: when pipe is empty and all writers are gone, return POLLIN|POLLHUP (was only POLLHUP). POSIX requires POLLIN because read() returns 0 (EOF) without blocking. Busybox ash's read builtin uses ppoll to wait for POLLIN before reading the next byte — without POLLIN on EOF, ppoll blocked forever after the last line.
-
Drop for PipeSender/PipeReceiver: when the last writer closes, signal write_wait to wake blocked readers; when the last reader closes, signal read_wait to wake blocked writers. Without these, a reader blocked on an empty pipe would sleep forever if the writer exited without writing more data.
Root cause of busybox-musl test hang: cat | while read loop never exited because ash's ppoll(fd=0, POLLIN) returned 0 events on EOF pipe, causing the shell to block instead of calling read() to get EOF.