joyent/node — Issue #2747: read(2) never getting called for read streams
Author: chjj
Created: 2012-02-13 10:31:45+00:00
State: open

I apologize in advance for the wall of text, this seems to be an elusive problem. and kind of complicated to explain.

For a terminal emulator I wrote with node, I call `forkpty(3)`, and open an `fs.ReadStream` and `fs.WriteStream` with the resulting master fd.

Everything works great, until I open more than 3 pty's at certain intervals. Node sits there ostensibly trying to `read(2)` the 4th fd, forever. The callback is never executed despite data being written to the slave from the forked process.

In a bout of frustration, I tried starting up one of the internal `fs.SyncWriteStream`s. To my surprise, things improved with synchronous writes. The read stream was able to spit out some more data, ultimately echoing the bytes that were being written to the master fd. But the read stream still wasn't able to read any data that was written to the slave.

I'm guessing this may be a problem with libeio, because sync writes don't have to go on the event loop or be executed by libeio. I followed this hunch until it lead me to write a synchronous read stream. The synchronous read stream, which of course, doesn't go through libeio, works *beautifully*. It has no problem reading from the file descriptor, whereas the async stream hangs there. Unfortunately, the sync stream blocks the process.

This problem occurs consistently if these pty's are opened at certain intervals. It will usually always happen after more than 3 read/write streams are instantiated with pty fd's. I realize the ability to open pty's isn't a core part of node, but I think this might be a sign of some deeper underlying problem.

I wrote [a small test](https://gist.github.com/1815766#file_index.js) (with the other relevant files there as well) to demonstrate this problem. If you run it, you will see an output like this:

```
Starting a terminal every 5 seconds and announcing data events...
Starting terminal #0.
#0: data event
Starting terminal #1.
#1: data event
#1: data event
Starting terminal #2.
#2: data event
#2: data event
Starting terminal #3.
#3: data event
#3: data event
Starting terminal #4.
```

No reads ever complete on the `#4` terminal's master fd.

[Doing an strace on it](https://gist.github.com/1815766#file_2vs4.strace) reveals that after terminal `#4` is opened, no actual `read(2)` calls are __ever__ executed on the master file descriptor after it's opened (it doesn't even look like the fd is being polled?), whereas with 0-3, they are.

In the test, you'll also notice that a sync read stream is opened for terminal `#5`, which works.

__Node version:__
v0.6.8, v0.6.10

__OS:__
Linux 3.1.0-1-686-pae
Debian Testing

__Relevant code:__
https://github.com/chjj/tty.js/blob/master/lib/tty.js
https://github.com/chjj/tty.js/blob/master/src/pty.cc