summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremiah Senkpiel <fishrock123@rocketmail.com>2016-05-15 12:23:03 -0400
committerJeremiah Senkpiel <fishrock123@rocketmail.com>2016-05-16 14:27:13 -0400
commit2f6420ba38ab8ccaab3426c49b36484eafeb8e95 (patch)
tree57a4de7bf84f6d43ac066cd2c81fdc981366e09e
parentf4f6c6e8151071d6d866603d0837d851fdf49157 (diff)
downloadnode-new-process-exit-stdio-flushing.tar.gz
process: flush stdout/stderr upon `process.exit()`process-exit-stdio-flushing
-rw-r--r--deps/uv/include/uv.h2
-rw-r--r--deps/uv/src/unix/stream.c15
-rw-r--r--lib/internal/process.js62
-rw-r--r--src/stream_wrap.cc17
-rw-r--r--src/stream_wrap.h1
-rw-r--r--test/known_issues/known_issues.status1
-rw-r--r--test/parallel/test-stdout-buffer-flush-on-exit.js (renamed from test/known_issues/test-stdout-buffer-flush-on-exit.js)4
7 files changed, 98 insertions, 4 deletions
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index baa0b28124..fdaebc6a0c 100644
--- a/deps/uv/include/uv.h
+++ b/deps/uv/include/uv.h
@@ -483,6 +483,8 @@ UV_EXTERN int uv_try_write(uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs);
+UV_EXTERN int uv_flush_sync(uv_stream_t* stream);
+
/* uv_write_t is a subclass of uv_req_t. */
struct uv_write_s {
UV_REQ_FIELDS
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index 9043664dfc..7172ad4dd5 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -1625,6 +1625,21 @@ void uv__stream_close(uv_stream_t* handle) {
}
+/* Have stream block and then synchronously flush queued writes.
+ * This function works without an event loop.
+ * Intended to be used just prior to exit().
+ * Returns 0 on success, non-zero on failure.
+ */
+int uv_flush_sync(uv_stream_t* stream) {
+ int rc = uv_stream_set_blocking(stream, 1);
+ if (rc == 0) {
+ uv__write(stream);
+ rc = (int)stream->write_queue_size;
+ }
+ return rc;
+}
+
+
int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
/* Don't need to check the file descriptor, uv__nonblock()
* will fail with EBADF if it's not valid.
diff --git a/lib/internal/process.js b/lib/internal/process.js
index c435c2e871..5b6e56fa9a 100644
--- a/lib/internal/process.js
+++ b/lib/internal/process.js
@@ -145,7 +145,69 @@ function setupKillAndExit() {
process._exiting = true;
process.emit('exit', process.exitCode || 0);
}
+
+ // Flush stdio streams prior to exit.
+ // `flushSync` not present if stream redirected to file in shell.
+ flushSync(process.stdout);
+ flushSync(process.stderr);
+
process.reallyExit(process.exitCode || 0);
+
+ function flushSync(stream) {
+
+ // Behavior of this function outside of process.exit() is undefined
+ // due to the following factors:
+ // * Stream fd may be blocking after this call.
+ // * In the event of an incomplete flush pending buffered write
+ // requests may be truncated.
+ // * No return code.
+
+ if (stream._writev)
+ return;
+
+ var handle = stream._handle;
+ if (!handle || !handle.flushSync)
+ return;
+
+ var fd = handle.fd;
+ if (typeof fd !== 'number' || fd < 0)
+ return;
+
+ // FIXME: late module resolution avoids cross require problem
+ const fs = require('fs');
+
+ const Buffer = require('buffer');
+
+ // Queued libuv writes must be flushed first.
+ // Note: fd will set to blocking after handle.flushSync()
+ if (handle.flushSync() !== 0) {
+ // bad fd or write queue for libuv stream not entirely flushed
+ return;
+ }
+
+ // then the queued stream chunks can be flushed
+ var state = stream._writableState;
+ var entry = state.bufferedRequest;
+ while (entry) {
+ var chunk = entry.chunk;
+ if (!(chunk instanceof Buffer)) {
+ chunk = Buffer.from(chunk, entry.encoding);
+ }
+ // Note: fd is blocking at this point
+ var written = fs.writeSync(fd, chunk, 0, chunk.length);
+ if (written !== chunk.length) {
+ // stream chunk not flushed entirely - stop writing.
+ // FIXME: buffered request queue should be repaired here
+ // rather than being truncated after loop break
+ break;
+ }
+ entry = entry.next;
+ }
+
+ state.bufferedRequestCount = 0;
+ state.bufferedRequest = null;
+ state.lastBufferedRequest = null;
+ }
};
process.kill = function(pid, sig) {
diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc
index 695e917e02..10a7110812 100644
--- a/src/stream_wrap.cc
+++ b/src/stream_wrap.cc
@@ -77,6 +77,7 @@ StreamWrap::StreamWrap(Environment* env,
void StreamWrap::AddMethods(Environment* env,
v8::Local<v8::FunctionTemplate> target,
int flags) {
+ env->SetProtoMethod(target, "flushSync", FlushSync);
env->SetProtoMethod(target, "setBlocking", SetBlocking);
StreamBase::AddMethods<StreamWrap>(env, target, flags);
}
@@ -273,6 +274,22 @@ void StreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
}
+void StreamWrap::FlushSync(const FunctionCallbackInfo<Value>& args) {
+ StreamWrap* wrap = Unwrap<StreamWrap>(args.Holder());
+
+ if (!wrap->IsAlive())
+ return args.GetReturnValue().Set(UV_EINVAL);
+
+#if defined(_WIN32)
+ int rc = 0;
+#else
+ int rc = uv_flush_sync(wrap->stream());
+#endif
+
+ args.GetReturnValue().Set(rc);
+}
+
+
int StreamWrap::DoShutdown(ShutdownWrap* req_wrap) {
int err;
err = uv_shutdown(&req_wrap->req_, stream(), AfterShutdown);
diff --git a/src/stream_wrap.h b/src/stream_wrap.h
index b0d9986db5..9c60a6c755 100644
--- a/src/stream_wrap.h
+++ b/src/stream_wrap.h
@@ -72,6 +72,7 @@ class StreamWrap : public HandleWrap, public StreamBase {
int flags = StreamBase::kFlagNone);
private:
+ static void FlushSync(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetBlocking(const v8::FunctionCallbackInfo<v8::Value>& args);
// Callbacks for libuv
diff --git a/test/known_issues/known_issues.status b/test/known_issues/known_issues.status
index 12e4b10d06..e21913e232 100644
--- a/test/known_issues/known_issues.status
+++ b/test/known_issues/known_issues.status
@@ -7,7 +7,6 @@ prefix known_issues
[true] # This section applies to all platforms
[$system==win32]
-test-stdout-buffer-flush-on-exit: SKIP
[$system==linux]
diff --git a/test/known_issues/test-stdout-buffer-flush-on-exit.js b/test/parallel/test-stdout-buffer-flush-on-exit.js
index 709928693e..791a9ccd15 100644
--- a/test/known_issues/test-stdout-buffer-flush-on-exit.js
+++ b/test/parallel/test-stdout-buffer-flush-on-exit.js
@@ -15,7 +15,7 @@ if (process.argv[2] === 'child') {
process.exit();
}
-[22, 21, 20, 19, 18, 17, 16, 16, 17, 18, 19, 20, 21, 22].forEach((exponent) => {
+[22, 16].forEach((exponent) => {
const bigNum = Math.pow(2, exponent);
const longLine = lineSeed.repeat(bigNum);
const cmd = `${process.execPath} ${__filename} child ${exponent} ${bigNum}`;
@@ -23,5 +23,3 @@ if (process.argv[2] === 'child') {
assert.strictEqual(stdout, longLine, `failed with exponent ${exponent}`);
});
-
-