From 5e7c6518a3146d76476137a7611417e05fdb4480 Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Fri, 8 Jun 2018 10:23:25 -0400 Subject: [PATCH] doc: warn against streaming from character devices charcter device streaming works just like any other streams, but hangs on the close callsite due to the worker thread being blocked on the read and main thread waiting for any async event that may not occur. Document this behavior and suggest a potential workaround. Fixes: https://github.com/nodejs/node/issues/15439 PR-URL: https://github.com/nodejs/node/pull/21212 Reviewed-By: Vse Mozhet Byt Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/fs.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/api/fs.md b/doc/api/fs.md index 253f223276e159..b481e94c2945ff 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1459,6 +1459,26 @@ the specified file descriptor. This means that no `'open'` event will be emitted. `fd` should be blocking; non-blocking `fd`s should be passed to [`net.Socket`][]. +The blocking `fd`, if pointing to a character device (such as keyboard or +sound card) can potentially block the main thread on stream close. This is +because these devices do not produce EOF character as part of their data +flow cycle, and thereby exemplify endless streams. As a result, they do not +respond to `stream.close()`. A workaround is to close the stream first +using `stream.close()` and then push a random character into the stream, and +issue a single read. This unblocks the reader thread, leads to the completion +of the data flow cycle, and the actual closing of the stream. + +```js +const fs = require('fs'); +// Create a stream from some character device. +const stream = fs.createReadStream('/dev/input/event0'); +setTimeout(() => { + stream.close(); // This does not close the stream. + stream.push(null); + stream.read(0); // Pushing a null and reading leads to close. +}, 100); +``` + If `autoClose` is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak. If `autoClose` is set to true (default