src: split ownsProcessState off isMainThread
Embedders may want to control whether a Node.js instance controls the current process, similar to what we currently have with `Worker`s. Previously, the `isMainThread` flag had a bit of a double usage, both for indicating whether we are (not) running a Worker and whether we can modify per-process state. PR-URL: https://github.com/nodejs/node/pull/25881 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
8d63f4037e
commit
39eca841c3
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
// This file is compiled as if it's wrapped in a function with arguments
|
// This file is compiled as if it's wrapped in a function with arguments
|
||||||
// passed by node::LoadEnvironment()
|
// passed by node::LoadEnvironment()
|
||||||
/* global process, loaderExports, isMainThread */
|
/* global process, loaderExports, isMainThread, ownsProcessState */
|
||||||
|
|
||||||
const { internalBinding, NativeModule } = loaderExports;
|
const { internalBinding, NativeModule } = loaderExports;
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ const perThreadSetup = NativeModule.require('internal/process/per_thread');
|
|||||||
let mainThreadSetup;
|
let mainThreadSetup;
|
||||||
// Bootstrappers for the worker threads only
|
// Bootstrappers for the worker threads only
|
||||||
let workerThreadSetup;
|
let workerThreadSetup;
|
||||||
if (isMainThread) {
|
if (ownsProcessState) {
|
||||||
mainThreadSetup = NativeModule.require(
|
mainThreadSetup = NativeModule.require(
|
||||||
'internal/process/main_thread_only'
|
'internal/process/main_thread_only'
|
||||||
);
|
);
|
||||||
@ -140,7 +140,7 @@ if (credentials.implementsPosixCredentials) {
|
|||||||
process.getegid = credentials.getegid;
|
process.getegid = credentials.getegid;
|
||||||
process.getgroups = credentials.getgroups;
|
process.getgroups = credentials.getgroups;
|
||||||
|
|
||||||
if (isMainThread) {
|
if (ownsProcessState) {
|
||||||
const wrapped = mainThreadSetup.wrapPosixCredentialSetters(credentials);
|
const wrapped = mainThreadSetup.wrapPosixCredentialSetters(credentials);
|
||||||
process.initgroups = wrapped.initgroups;
|
process.initgroups = wrapped.initgroups;
|
||||||
process.setgroups = wrapped.setgroups;
|
process.setgroups = wrapped.setgroups;
|
||||||
|
@ -30,9 +30,10 @@ const { deserializeError } = require('internal/error-serdes');
|
|||||||
const { pathToFileURL } = require('url');
|
const { pathToFileURL } = require('url');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
Worker: WorkerImpl,
|
ownsProcessState,
|
||||||
|
isMainThread,
|
||||||
threadId,
|
threadId,
|
||||||
isMainThread
|
Worker: WorkerImpl,
|
||||||
} = internalBinding('worker');
|
} = internalBinding('worker');
|
||||||
|
|
||||||
const kHandle = Symbol('kHandle');
|
const kHandle = Symbol('kHandle');
|
||||||
@ -243,7 +244,8 @@ function pipeWithoutWarning(source, dest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
ownsProcessState,
|
||||||
|
isMainThread,
|
||||||
threadId,
|
threadId,
|
||||||
Worker,
|
Worker,
|
||||||
isMainThread
|
|
||||||
};
|
};
|
||||||
|
@ -13,8 +13,8 @@ const {
|
|||||||
ERR_INVALID_ARG_TYPE
|
ERR_INVALID_ARG_TYPE
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
|
|
||||||
const { isMainThread } = require('internal/worker');
|
const { ownsProcessState } = require('internal/worker');
|
||||||
if (!hasTracing || !isMainThread)
|
if (!hasTracing || !ownsProcessState)
|
||||||
throw new ERR_TRACE_EVENTS_UNAVAILABLE();
|
throw new ERR_TRACE_EVENTS_UNAVAILABLE();
|
||||||
|
|
||||||
const { CategorySet, getEnabledCategories } = internalBinding('trace_events');
|
const { CategorySet, getEnabledCategories } = internalBinding('trace_events');
|
||||||
|
@ -143,8 +143,12 @@ Environment* CreateEnvironment(IsolateData* isolate_data,
|
|||||||
std::vector<std::string> args(argv, argv + argc);
|
std::vector<std::string> args(argv, argv + argc);
|
||||||
std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
|
std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
|
||||||
// TODO(addaleax): Provide more sensible flags, in an embedder-accessible way.
|
// TODO(addaleax): Provide more sensible flags, in an embedder-accessible way.
|
||||||
Environment* env =
|
Environment* env = new Environment(
|
||||||
new Environment(isolate_data, context, Environment::kIsMainThread);
|
isolate_data,
|
||||||
|
context,
|
||||||
|
static_cast<Environment::Flags>(Environment::kIsMainThread |
|
||||||
|
Environment::kOwnsProcessState |
|
||||||
|
Environment::kOwnsInspector));
|
||||||
env->Start(per_process::v8_is_profiling);
|
env->Start(per_process::v8_is_profiling);
|
||||||
env->ProcessCliArgs(args, exec_args);
|
env->ProcessCliArgs(args, exec_args);
|
||||||
return env;
|
return env;
|
||||||
|
@ -650,6 +650,14 @@ inline bool Environment::is_main_thread() const {
|
|||||||
return flags_ & kIsMainThread;
|
return flags_ & kIsMainThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Environment::owns_process_state() const {
|
||||||
|
return flags_ & kOwnsProcessState;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Environment::owns_inspector() const {
|
||||||
|
return flags_ & kOwnsInspector;
|
||||||
|
}
|
||||||
|
|
||||||
inline uint64_t Environment::thread_id() const {
|
inline uint64_t Environment::thread_id() const {
|
||||||
return thread_id_;
|
return thread_id_;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ void InitThreadLocalOnce() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Environment::TrackingTraceStateObserver::UpdateTraceCategoryState() {
|
void Environment::TrackingTraceStateObserver::UpdateTraceCategoryState() {
|
||||||
if (!env_->is_main_thread()) {
|
if (!env_->owns_process_state()) {
|
||||||
// Ideally, we’d have a consistent story that treats all threads/Environment
|
// Ideally, we’d have a consistent story that treats all threads/Environment
|
||||||
// instances equally here. However, tracing is essentially global, and this
|
// instances equally here. However, tracing is essentially global, and this
|
||||||
// callback is called from whichever thread calls `StartTracing()` or
|
// callback is called from whichever thread calls `StartTracing()` or
|
||||||
|
@ -599,7 +599,9 @@ class Environment {
|
|||||||
|
|
||||||
enum Flags {
|
enum Flags {
|
||||||
kNoFlags = 0,
|
kNoFlags = 0,
|
||||||
kIsMainThread = 1
|
kIsMainThread = 1 << 0,
|
||||||
|
kOwnsProcessState = 1 << 1,
|
||||||
|
kOwnsInspector = 1 << 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline Environment* GetCurrent(v8::Isolate* isolate);
|
static inline Environment* GetCurrent(v8::Isolate* isolate);
|
||||||
@ -768,6 +770,8 @@ class Environment {
|
|||||||
inline void set_has_run_bootstrapping_code(bool has_run_bootstrapping_code);
|
inline void set_has_run_bootstrapping_code(bool has_run_bootstrapping_code);
|
||||||
|
|
||||||
inline bool is_main_thread() const;
|
inline bool is_main_thread() const;
|
||||||
|
inline bool owns_process_state() const;
|
||||||
|
inline bool owns_inspector() const;
|
||||||
inline uint64_t thread_id() const;
|
inline uint64_t thread_id() const;
|
||||||
inline worker::Worker* worker_context() const;
|
inline worker::Worker* worker_context() const;
|
||||||
inline void set_worker_context(worker::Worker* context);
|
inline void set_worker_context(worker::Worker* context);
|
||||||
|
@ -141,7 +141,7 @@ DispatchResponse TracingAgent::start(
|
|||||||
return DispatchResponse::Error(
|
return DispatchResponse::Error(
|
||||||
"Call NodeTracing::end to stop tracing before updating the config");
|
"Call NodeTracing::end to stop tracing before updating the config");
|
||||||
}
|
}
|
||||||
if (!env_->is_main_thread()) {
|
if (!env_->owns_process_state()) {
|
||||||
return DispatchResponse::Error(
|
return DispatchResponse::Error(
|
||||||
"Tracing properties can only be changed through main thread sessions");
|
"Tracing properties can only be changed through main thread sessions");
|
||||||
}
|
}
|
||||||
|
@ -686,7 +686,7 @@ bool Agent::Start(const std::string& path,
|
|||||||
host_port_ = host_port;
|
host_port_ = host_port;
|
||||||
|
|
||||||
client_ = std::make_shared<NodeInspectorClient>(parent_env_, is_main);
|
client_ = std::make_shared<NodeInspectorClient>(parent_env_, is_main);
|
||||||
if (parent_env_->is_main_thread()) {
|
if (parent_env_->owns_inspector()) {
|
||||||
CHECK_EQ(start_io_thread_async_initialized.exchange(true), false);
|
CHECK_EQ(start_io_thread_async_initialized.exchange(true), false);
|
||||||
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
|
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
|
||||||
&start_io_thread_async,
|
&start_io_thread_async,
|
||||||
|
11
src/node.cc
11
src/node.cc
@ -314,16 +314,18 @@ MaybeLocal<Value> RunBootstrapping(Environment* env) {
|
|||||||
loader_exports_obj->Get(context, env->require_string()).ToLocalChecked();
|
loader_exports_obj->Get(context, env->require_string()).ToLocalChecked();
|
||||||
env->set_native_module_require(require.As<Function>());
|
env->set_native_module_require(require.As<Function>());
|
||||||
|
|
||||||
// process, loaderExports, isMainThread
|
// process, loaderExports, isMainThread, ownsProcessState, primordials
|
||||||
std::vector<Local<String>> node_params = {
|
std::vector<Local<String>> node_params = {
|
||||||
env->process_string(),
|
env->process_string(),
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "loaderExports"),
|
FIXED_ONE_BYTE_STRING(isolate, "loaderExports"),
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "isMainThread"),
|
FIXED_ONE_BYTE_STRING(isolate, "isMainThread"),
|
||||||
|
FIXED_ONE_BYTE_STRING(isolate, "ownsProcessState"),
|
||||||
env->primordials_string()};
|
env->primordials_string()};
|
||||||
std::vector<Local<Value>> node_args = {
|
std::vector<Local<Value>> node_args = {
|
||||||
process,
|
process,
|
||||||
loader_exports_obj,
|
loader_exports_obj,
|
||||||
Boolean::New(isolate, env->is_main_thread()),
|
Boolean::New(isolate, env->is_main_thread()),
|
||||||
|
Boolean::New(isolate, env->owns_process_state()),
|
||||||
env->primordials()};
|
env->primordials()};
|
||||||
|
|
||||||
MaybeLocal<Value> result = ExecuteBootstrapper(
|
MaybeLocal<Value> result = ExecuteBootstrapper(
|
||||||
@ -752,7 +754,12 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
|||||||
HandleScope handle_scope(isolate);
|
HandleScope handle_scope(isolate);
|
||||||
Local<Context> context = NewContext(isolate);
|
Local<Context> context = NewContext(isolate);
|
||||||
Context::Scope context_scope(context);
|
Context::Scope context_scope(context);
|
||||||
Environment env(isolate_data, context, Environment::kIsMainThread);
|
Environment env(
|
||||||
|
isolate_data,
|
||||||
|
context,
|
||||||
|
static_cast<Environment::Flags>(Environment::kIsMainThread |
|
||||||
|
Environment::kOwnsProcessState |
|
||||||
|
Environment::kOwnsInspector));
|
||||||
env.Start(per_process::v8_is_profiling);
|
env.Start(per_process::v8_is_profiling);
|
||||||
env.ProcessCliArgs(args, exec_args);
|
env.ProcessCliArgs(args, exec_args);
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ static void GetEGid(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
static void SetGid(const FunctionCallbackInfo<Value>& args) {
|
static void SetGid(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
CHECK(env->is_main_thread());
|
CHECK(env->owns_process_state());
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||||
@ -194,7 +194,7 @@ static void SetGid(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
static void SetEGid(const FunctionCallbackInfo<Value>& args) {
|
static void SetEGid(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
CHECK(env->is_main_thread());
|
CHECK(env->owns_process_state());
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||||
@ -213,7 +213,7 @@ static void SetEGid(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
static void SetUid(const FunctionCallbackInfo<Value>& args) {
|
static void SetUid(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
CHECK(env->is_main_thread());
|
CHECK(env->owns_process_state());
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||||
@ -232,7 +232,7 @@ static void SetUid(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
static void SetEUid(const FunctionCallbackInfo<Value>& args) {
|
static void SetEUid(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
CHECK(env->is_main_thread());
|
CHECK(env->owns_process_state());
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||||
@ -363,7 +363,7 @@ static void Initialize(Local<Object> target,
|
|||||||
env->SetMethodNoSideEffect(target, "getegid", GetEGid);
|
env->SetMethodNoSideEffect(target, "getegid", GetEGid);
|
||||||
env->SetMethodNoSideEffect(target, "getgroups", GetGroups);
|
env->SetMethodNoSideEffect(target, "getgroups", GetGroups);
|
||||||
|
|
||||||
if (env->is_main_thread()) {
|
if (env->owns_process_state()) {
|
||||||
env->SetMethod(target, "initgroups", InitGroups);
|
env->SetMethod(target, "initgroups", InitGroups);
|
||||||
env->SetMethod(target, "setegid", SetEGid);
|
env->SetMethod(target, "setegid", SetEGid);
|
||||||
env->SetMethod(target, "seteuid", SetEUid);
|
env->SetMethod(target, "seteuid", SetEUid);
|
||||||
|
@ -72,7 +72,7 @@ static void Abort(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
static void Chdir(const FunctionCallbackInfo<Value>& args) {
|
static void Chdir(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
CHECK(env->is_main_thread());
|
CHECK(env->owns_process_state());
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
CHECK(args[0]->IsString());
|
CHECK(args[0]->IsString());
|
||||||
@ -392,17 +392,17 @@ static void InitializeProcessMethods(Local<Object> target,
|
|||||||
Environment* env = Environment::GetCurrent(context);
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
|
||||||
// define various internal methods
|
// define various internal methods
|
||||||
if (env->is_main_thread()) {
|
if (env->owns_process_state()) {
|
||||||
env->SetMethod(target, "_debugProcess", DebugProcess);
|
env->SetMethod(target, "_debugProcess", DebugProcess);
|
||||||
env->SetMethod(target, "_debugEnd", DebugEnd);
|
env->SetMethod(target, "_debugEnd", DebugEnd);
|
||||||
env->SetMethod(
|
|
||||||
target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
|
|
||||||
env->SetMethod(
|
|
||||||
target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
|
|
||||||
env->SetMethod(target, "abort", Abort);
|
env->SetMethod(target, "abort", Abort);
|
||||||
env->SetMethod(target, "chdir", Chdir);
|
env->SetMethod(target, "chdir", Chdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env->SetMethod(
|
||||||
|
target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
|
||||||
|
env->SetMethod(target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
|
||||||
|
|
||||||
env->SetMethod(target, "umask", Umask);
|
env->SetMethod(target, "umask", Umask);
|
||||||
env->SetMethod(target, "_rawDebug", RawDebug);
|
env->SetMethod(target, "_rawDebug", RawDebug);
|
||||||
env->SetMethod(target, "memoryUsage", MemoryUsage);
|
env->SetMethod(target, "memoryUsage", MemoryUsage);
|
||||||
|
@ -86,15 +86,17 @@ MaybeLocal<Object> CreateProcessObject(
|
|||||||
|
|
||||||
// process.title
|
// process.title
|
||||||
auto title_string = FIXED_ONE_BYTE_STRING(env->isolate(), "title");
|
auto title_string = FIXED_ONE_BYTE_STRING(env->isolate(), "title");
|
||||||
CHECK(process->SetAccessor(
|
CHECK(process
|
||||||
env->context(),
|
->SetAccessor(
|
||||||
title_string,
|
env->context(),
|
||||||
ProcessTitleGetter,
|
title_string,
|
||||||
env->is_main_thread() ? ProcessTitleSetter : nullptr,
|
ProcessTitleGetter,
|
||||||
env->as_external(),
|
env->owns_process_state() ? ProcessTitleSetter : nullptr,
|
||||||
DEFAULT,
|
env->as_external(),
|
||||||
None,
|
DEFAULT,
|
||||||
SideEffectType::kHasNoSideEffect).FromJust());
|
None,
|
||||||
|
SideEffectType::kHasNoSideEffect)
|
||||||
|
.FromJust());
|
||||||
|
|
||||||
// process.version
|
// process.version
|
||||||
READONLY_PROPERTY(process,
|
READONLY_PROPERTY(process,
|
||||||
@ -290,11 +292,13 @@ MaybeLocal<Object> CreateProcessObject(
|
|||||||
|
|
||||||
// process.debugPort
|
// process.debugPort
|
||||||
auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort");
|
auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort");
|
||||||
CHECK(process->SetAccessor(env->context(),
|
CHECK(process
|
||||||
debug_port_string,
|
->SetAccessor(env->context(),
|
||||||
DebugPortGetter,
|
debug_port_string,
|
||||||
env->is_main_thread() ? DebugPortSetter : nullptr,
|
DebugPortGetter,
|
||||||
env->as_external()).FromJust());
|
env->owns_process_state() ? DebugPortSetter : nullptr,
|
||||||
|
env->as_external())
|
||||||
|
.FromJust());
|
||||||
|
|
||||||
// process._rawDebug: may be overwritten later in JS land, but should be
|
// process._rawDebug: may be overwritten later in JS land, but should be
|
||||||
// availbale from the begining for debugging purposes
|
// availbale from the begining for debugging purposes
|
||||||
|
@ -569,6 +569,12 @@ void InitWorker(Local<Object> target,
|
|||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "isMainThread"),
|
FIXED_ONE_BYTE_STRING(env->isolate(), "isMainThread"),
|
||||||
Boolean::New(env->isolate(), env->is_main_thread()))
|
Boolean::New(env->isolate(), env->is_main_thread()))
|
||||||
.FromJust();
|
.FromJust();
|
||||||
|
|
||||||
|
target
|
||||||
|
->Set(env->context(),
|
||||||
|
FIXED_ONE_BYTE_STRING(env->isolate(), "ownsProcessState"),
|
||||||
|
Boolean::New(env->isolate(), env->owns_process_state()))
|
||||||
|
.FromJust();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user