If child is slow reading from its input, or even completely stops doing the read, script(1) hangs in write(2) to the pts master waiting until there is a space in the terminal discipline buffer. This also stops handling any outer io, as well as child output. Work around the problem by making pts master fd non-blocking, and be prepared for short writes to it. The data to be written to master is buffered in the tailq which is processed when select(2) detects that master is ready for write. PR: 260938
Details
- Reviewers
cperciva markj emaste - Commits
- rGc0ba4c2ee2c4: script(1): work around slow reading child
Diff Detail
- Repository
- rG FreeBSD src repository
- Lint
Lint Not Applicable - Unit
Tests Not Applicable
Event Timeline
Seems reasonable to me.
usr.bin/script/script.c | ||
---|---|---|
311 | I think this can leave the terminal in a weird state, we should call done() before exiting, same way read() errors above are handled. |
usr.bin/script/script.c | ||
---|---|---|
311 | I added done() call, but I in fact do not see what the weird state would be. For the terminal, done() only flushes the pending output. Also, I do not believe that for correctly operating program, the cc == -1 case there, except for EWOULDBLOCK/EINTR errnos, is ever possible. It can be artificially created, by e.g. revoking the pts in other process. But we cannot do anything useful there then. |
A lot of bug fixes, sorry.
Handle EINTR as acceptable error from write() on master.
Properly use select, i.e. do not forget to zero write set, and then pass it to select.
Fix fcntl(F_SETFL).
usr.bin/script/script.c | ||
---|---|---|
311 | script puts STDIN_FILENO in raw mode. done() restores the terminal state. |