diff --git a/lib/internal/fs/streams.js b/lib/internal/fs/streams.js index 9e6050139dc79a..0209f3e844c759 100644 --- a/lib/internal/fs/streams.js +++ b/lib/internal/fs/streams.js @@ -255,6 +255,12 @@ ReadStream.prototype._read = function(n) { }; ReadStream.prototype._destroy = function(err, cb) { + // Usually for async IO it is safe to close a file descriptor + // even when there are pending operations. However, due to platform + // differences file IO is implemented using synchronous operations + // running in a thread pool. Therefore, file descriptors are not safe + // to close while used in a pending read or write operation. Wait for + // any pending IO (kIsPerformingIO) to complete (kIoDone). if (this[kIsPerformingIO]) { this.once(kIoDone, (er) => close(this, err || er, cb)); } else { @@ -416,12 +422,19 @@ WriteStream.prototype._writev = function(data, cb) { }; WriteStream.prototype._destroy = function(err, cb) { + // Usually for async IO it is safe to close a file descriptor + // even when there are pending operations. However, due to platform + // differences file IO is implemented using synchronous operations + // running in a thread pool. Therefore, file descriptors are not safe + // to close while used in a pending read or write operation. Wait for + // any pending IO (kIsPerformingIO) to complete (kIoDone). if (this[kIsPerformingIO]) { this.once(kIoDone, (er) => close(this, err || er, cb)); } else { close(this, err, cb); } }; + WriteStream.prototype.close = function(cb) { if (cb) { if (this.closed) {