Blocking Read on PTY – Why It Returns When Process Dies

clinuxpseudoterminalptytty

When slave side of pty is not opened, strace on the process, which does read(master_fd, &byte, 1);, shows this:

read(3, 

So, when nobody is connected to the slave side of pty, read() waits for data – it does not return with a error.

But when slave side of pty is opened by a process and that process exits, the read() dies with this:

read(3, 0xbf8ba7f3, 1)                  = -1 EIO (Input/output error)

The pty is created with

master_fd = posix_openpt(O_RDWR|O_NOCTTY)

Slave side of the pty is opened with

comfd = open(COM_PORT, O_RDWR|O_NOCTTY)

Why the read() exits when process which opened slave side of the pty exits? Where is this described?

Best Answer

On Linux, a read() on the master side of a pseudo-tty will return -1 and set ERRNO to EIO when all the handles to its slave side have been closed, but will either block or return EAGAIN before the slave has been first opened.

The same thing will happen when trying to read from a slave with no master. For the master side, the condition is transient; re-opening the slave will cause a read() on the master side to work again.

On *BSD and Solaris the behavior is similar, with the difference that the read() will return 0 instead of -1 + EIO. Also, on OpenBSD a read() will also return 0 before the slave is first opened.

I don't know if there's any standard spec or rationale for this, but it allows to (crudely) detect when the other side was closed, and simplifies the logic of programs like script which are just creating a pty and running another program inside it.

The solution in a program which manages the master part of a pty to which other unrelated programs can connect is to also open and keep open a handle to its slave side.

See related answer: read(2) blocking behaviour changes when pts is closed resulting in read() returning error: -1 (EIO)

Why the read() exits when process which opened slave side of the pty exits?

When a process exits, all its file descriptors are automatically closed.

Related Question