sea: only assert snapshot main function for main threads

Snapshot main functions are only loaded for main threads in single
executable applications. Update the check to avoid asserting it
in worker threads - this allows worker threads to be spawned in
snapshot main functions bundled into a single executable
application.

PR-URL: https://github.com/nodejs/node/pull/56120
Fixes: https://github.com/nodejs/node/issues/56077
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
Joyee Cheung 2024-12-07 18:25:02 +01:00 committed by GitHub
parent ee8810731d
commit 7fdeeac4d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 85 additions and 1 deletions

View File

@ -320,7 +320,8 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
CHECK(!env->isolate_data()->is_building_snapshot());
#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION
if (sea::IsSingleExecutable()) {
// Snapshot in SEA is only loaded for the main thread.
if (sea::IsSingleExecutable() && env->is_main_thread()) {
sea::SeaResource sea = sea::FindSingleExecutableResource();
// The SEA preparation blob building process should already enforce this,
// this check is just here to guard against the unlikely case where
@ -342,6 +343,9 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
// move the pre-execution part into a different file that can be
// reused when dealing with user-defined main functions.
if (!env->snapshot_deserialize_main().IsEmpty()) {
// Custom worker snapshot is not supported yet,
// so workers can't have deserialize main functions.
CHECK(env->is_main_thread());
return env->RunSnapshotDeserializeMain();
}

View File

@ -0,0 +1,80 @@
'use strict';
require('../common');
const {
generateSEA,
skipIfSingleExecutableIsNotSupported,
} = require('../common/sea');
skipIfSingleExecutableIsNotSupported();
// This tests the snapshot support in single executable applications.
const tmpdir = require('../common/tmpdir');
const { writeFileSync, existsSync } = require('fs');
const {
spawnSyncAndAssert, spawnSyncAndExitWithoutError,
} = require('../common/child_process');
const assert = require('assert');
const configFile = tmpdir.resolve('sea-config.json');
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
{
tmpdir.refresh();
// FIXME(joyeecheung): currently `worker_threads` cannot be loaded during the
// snapshot building process because internal/worker.js is accessing isMainThread at
// the top level (and there are maybe more code that access these at the top-level),
// and have to be loaded in the deserialized snapshot main function.
// Change these states to be accessed on-demand.
const code = `
const {
setDeserializeMainFunction,
} = require('v8').startupSnapshot;
setDeserializeMainFunction(() => {
const { Worker } = require('worker_threads');
new Worker("console.log('Hello from Worker')", { eval: true });
});
`;
writeFileSync(tmpdir.resolve('snapshot.js'), code, 'utf-8');
writeFileSync(configFile, `
{
"main": "snapshot.js",
"output": "sea-prep.blob",
"useSnapshot": true
}
`);
spawnSyncAndExitWithoutError(
process.execPath,
['--experimental-sea-config', 'sea-config.json'],
{
cwd: tmpdir.path,
env: {
NODE_DEBUG_NATIVE: 'SEA',
...process.env,
},
});
assert(existsSync(seaPrepBlob));
generateSEA(outputFile, process.execPath, seaPrepBlob);
spawnSyncAndAssert(
outputFile,
{
env: {
NODE_DEBUG_NATIVE: 'SEA',
...process.env,
}
},
{
trim: true,
stdout: 'Hello from Worker'
}
);
}