Skip to content
Prev Previous commit
Next Next commit
bootstrap: make I/O streams work with user-land snapshot
Use the mksnapshot cleanup hooks to release the references
to the native streams so that they can be destroyed right
before the snapshot is taken, and move the initialization
of the global console to pre-execution so that they can be
re-initialized during snapshot dehydration. This makes
it possible for user-land snapshots to use the I/O during
snapshot building.
  • Loading branch information
joyeecheung committed Mar 25, 2022
commit c812b986554b3146fcfc3b812e9fefc12ecd5a3c
6 changes: 6 additions & 0 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ function patchProcessObject(expandArgv1) {
}
}

// We need to initialize the global console here again with process.stdout
// and friends for snapshot deserialization.
const globalConsole = require('internal/console/global');
const { initializeGlobalConsole } = require('internal/console/constructor');
initializeGlobalConsole(globalConsole);

// TODO(joyeecheung): most of these should be deprecated and removed,
// except some that we need to be able to mutate during run time.
addReadOnlyProcessAlias('_eval', '--eval');
Expand Down
34 changes: 32 additions & 2 deletions lib/internal/bootstrap/switches/is_main_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,27 +122,53 @@ let stdin;
let stdout;
let stderr;

let stdoutDestroy;
let stderrDestroy;

function refreshStdoutOnSigWinch() {
stdout._refreshSize();
}

function refreshStderrOnSigWinch() {
stderr._refreshSize();
}

function getStdout() {
if (stdout) return stdout;
stdout = createWritableStdioStream(1);
stdout.destroySoon = stdout.destroy;
// Override _destroy so that the fd is never actually closed.
stdoutDestroy = stdout._destroy;
stdout._destroy = dummyDestroy;
if (stdout.isTTY) {
process.on('SIGWINCH', () => stdout._refreshSize());
process.on('SIGWINCH', refreshStdoutOnSigWinch);
}

internalBinding('mksnapshot').cleanups.push(function cleanupStdout() {
stdout._destroy = stdoutDestroy;
stdout.destroy();
process.removeListener('SIGWINCH', refreshStdoutOnSigWinch);
stdout = undefined;
});
return stdout;
}

function getStderr() {
if (stderr) return stderr;
stderr = createWritableStdioStream(2);
stderr.destroySoon = stderr.destroy;
stderrDestroy = stderr._destroy;
// Override _destroy so that the fd is never actually closed.
stderr._destroy = dummyDestroy;
if (stderr.isTTY) {
process.on('SIGWINCH', () => stderr._refreshSize());
process.on('SIGWINCH', refreshStderrOnSigWinch);
}
internalBinding('mksnapshot').cleanups.push(function cleanupStderr() {
stderr._destroy = stderrDestroy;
stderr.destroy();
process.removeListener('SIGWINCH', refreshStderrOnSigWinch);
stderr = undefined;
});
return stderr;
}

Expand Down Expand Up @@ -229,6 +255,10 @@ function getStdin() {
}
}

internalBinding('mksnapshot').cleanups.push(function cleanupStdin() {
stdin.destroy();
stdin = undefined;
});
return stdin;
}

Expand Down
6 changes: 6 additions & 0 deletions lib/internal/console/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -669,9 +669,15 @@ Console.prototype.dirxml = Console.prototype.log;
Console.prototype.error = Console.prototype.warn;
Console.prototype.groupCollapsed = Console.prototype.group;

function initializeGlobalConsole(globalConsole) {
globalConsole[kBindStreamsLazy](process);
globalConsole[kBindProperties](true, 'auto');
}

module.exports = {
Console,
kBindStreamsLazy,
kBindProperties,
initializeGlobalConsole,
formatTime // exported for tests
};
7 changes: 1 addition & 6 deletions lib/internal/console/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ const {
} = primordials;

const {
Console,
kBindStreamsLazy,
kBindProperties
Console
} = require('internal/console/constructor');

const globalConsole = ObjectCreate({});
Expand All @@ -44,9 +42,6 @@ for (const prop of ReflectOwnKeys(Console.prototype)) {
ReflectDefineProperty(globalConsole, prop, desc);
}

globalConsole[kBindStreamsLazy](process);
globalConsole[kBindProperties](true, 'auto');

// This is a legacy feature - the Console constructor is exposed on
// the global console instance.
globalConsole.Console = Console;
Expand Down