Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node: extract node env initialization out of process initialization #980

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 82 additions & 53 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3499,7 +3499,7 @@ void Init(int* argc,
uv_disable_stdio_inheritance();

// init async debug messages dispatching
// FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
// Main thread uses uv_default_loop
uv_async_init(uv_default_loop(),
&dispatch_debug_messages_async,
DispatchDebugMessagesAsyncCallback);
Expand Down Expand Up @@ -3663,6 +3663,18 @@ Environment* CreateEnvironment(Isolate* isolate,
return env;
}

static Environment* CreateEnvironment(Isolate* isolate,
Handle<Context> context,
NodeInstanceData* instance_data) {
return CreateEnvironment(isolate,
instance_data->event_loop(),
context,
instance_data->argc(),
instance_data->argv(),
instance_data->exec_argc(),
instance_data->exec_argv());
}


static void HandleCloseCb(uv_handle_t* handle) {
Environment* env = reinterpret_cast<Environment*>(handle->data);
Expand Down Expand Up @@ -3746,62 +3758,32 @@ Environment* CreateEnvironment(Isolate* isolate,
}


int Start(int argc, char** argv) {
PlatformInit();

const char* replaceInvalid = secure_getenv("NODE_INVALID_UTF8");

if (replaceInvalid == nullptr)
WRITE_UTF8_FLAGS |= String::REPLACE_INVALID_UTF8;

CHECK_GT(argc, 0);

// Hack around with the argv pointer. Used for process.title = "blah".
argv = uv_setup_args(argc, argv);

// This needs to run *before* V8::Initialize(). The const_cast is not
// optional, in case you're wondering.
int exec_argc;
const char** exec_argv;
Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);

#if HAVE_OPENSSL
// V8 on Windows doesn't have a good source of entropy. Seed it from
// OpenSSL's pool.
V8::SetEntropySource(crypto::EntropySource);
#endif

V8::InitializePlatform(new Platform(4));

int code;
V8::Initialize();

// Fetch a reference to the main isolate, so we have a reference to it
// Entry point for new node instances, also called directly for the main
// node instance.
static void StartNodeInstance(void* arg) {
NodeInstanceData* instance_data = static_cast<NodeInstanceData*>(arg);
Isolate* isolate = Isolate::New();
// Fetch a reference to the main isolate, so we have a reference to it
// even when we need it to access it from another (debugger) thread.
node_isolate = Isolate::New();
if (instance_data->is_main())
node_isolate = isolate;
{
Locker locker(node_isolate);
Isolate::Scope isolate_scope(node_isolate);
HandleScope handle_scope(node_isolate);
Local<Context> context = Context::New(node_isolate);
Environment* env = CreateEnvironment(
node_isolate,
uv_default_loop(),
context,
argc,
argv,
exec_argc,
exec_argv);
Locker locker(isolate);
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
Local<Context> context = Context::New(isolate);
Environment* env = CreateEnvironment(isolate, context, instance_data);
Context::Scope context_scope(context);
env->set_using_abort_on_uncaught_exc(abort_on_uncaught_exception);
if (instance_data->is_main())
env->set_using_abort_on_uncaught_exc(abort_on_uncaught_exception);
// Start debug agent when argv has --debug
if (use_debug_agent)
if (instance_data->use_debug_agent())
StartDebug(env, debug_wait_connect);

LoadEnvironment(env);

// Enable debugger
if (use_debug_agent)
if (instance_data->use_debug_agent())
EnableDebug(env);

bool more;
Expand All @@ -3817,22 +3799,69 @@ int Start(int argc, char** argv) {
more = true;
}
} while (more == true);
code = EmitExit(env);

int exit_code = EmitExit(env);
if (instance_data->is_main())
instance_data->set_exit_code(exit_code);
RunAtExit(env);

env->Dispose();
env = nullptr;
}

CHECK_NE(node_isolate, nullptr);
node_isolate->Dispose();
node_isolate = nullptr;
CHECK_NE(isolate, nullptr);
isolate->Dispose();
isolate = nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure you clean up node_isolate here as well.

if (instance_data->is_main())
node_isolate = nullptr;
}

int Start(int argc, char** argv) {
PlatformInit();

const char* replace_invalid = secure_getenv("NODE_INVALID_UTF8");

if (replace_invalid == nullptr)
WRITE_UTF8_FLAGS |= String::REPLACE_INVALID_UTF8;

CHECK_GT(argc, 0);

// Hack around with the argv pointer. Used for process.title = "blah".
argv = uv_setup_args(argc, argv);

// This needs to run *before* V8::Initialize(). The const_cast is not
// optional, in case you're wondering.
int exec_argc;
const char** exec_argv;
Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);

#if HAVE_OPENSSL
// V8 on Windows doesn't have a good source of entropy. Seed it from
// OpenSSL's pool.
V8::SetEntropySource(crypto::EntropySource);
#endif

V8::InitializePlatform(new Platform(4));
V8::Initialize();

int exit_code = 1;
{
NodeInstanceData instance_data(NodeInstanceType::MAIN,
uv_default_loop(),
argc,
const_cast<const char**>(argv),
exec_argc,
exec_argv,
use_debug_agent);
StartNodeInstance(&instance_data);
exit_code = instance_data.exit_code();
}
V8::Dispose();

delete[] exec_argv;
exec_argv = nullptr;

return code;
return exit_code;
}


Expand Down
77 changes: 77 additions & 0 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,83 @@ inline void NODE_SET_EXTERNAL(v8::Handle<v8::ObjectTemplate> target,
v8::DontDelete));
}

enum NodeInstanceType { MAIN, WORKER };

class NodeInstanceData {
public:
NodeInstanceData(NodeInstanceType node_instance_type,
uv_loop_t* event_loop,
int argc,
const char** argv,
int exec_argc,
const char** exec_argv,
bool use_debug_agent_flag)
: node_instance_type_(node_instance_type),
exit_code_(1),
event_loop_(event_loop),
argc_(argc),
argv_(argv),
exec_argc_(exec_argc),
exec_argv_(exec_argv),
use_debug_agent_flag_(use_debug_agent_flag) {
CHECK_NE(event_loop_, nullptr);
}

uv_loop_t* event_loop() const {
return event_loop_;
}

int exit_code() {
CHECK(is_main());
return exit_code_;
}

void set_exit_code(int exit_code) {
CHECK(is_main());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, what is the reason to allow set_exit_code() only for the main thread?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well ultimately it will depend on how the Worker API will turn out and whether it's going to need the exit code, for now I just made it more restrictive in case it won't be needed. If it turns out it's going to be needed, it can always be loosened up after.

exit_code_ = exit_code;
}

bool is_main() {
return node_instance_type_ == MAIN;
}

bool is_worker() {
return node_instance_type_ == WORKER;
}

int argc() {
return argc_;
}

const char** argv() {
return argv_;
}

int exec_argc() {
return exec_argc_;
}

const char** exec_argv() {
return exec_argv_;
}

bool use_debug_agent() {
return is_main() && use_debug_agent_flag_;
}

private:
const NodeInstanceType node_instance_type_;
int exit_code_;
uv_loop_t* const event_loop_;
const int argc_;
const char** argv_;
const int exec_argc_;
const char** exec_argv_;
const bool use_debug_agent_flag_;

DISALLOW_COPY_AND_ASSIGN(NodeInstanceData);
};

} // namespace node

#endif // SRC_NODE_INTERNALS_H_