2132fdfa28
This re-orders our node clean up so that we free the environment before the task runner is cleaned up as node uses the task runner during clean up. It also calls WaitForDisconnect() to ensure that inspector agents are notified that the context is going down.
139 lines
4.4 KiB
C++
139 lines
4.4 KiB
C++
// Copyright (c) 2015 GitHub, Inc.
|
|
// Use of this source code is governed by the MIT license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "shell/app/node_main.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "base/command_line.h"
|
|
#include "base/feature_list.h"
|
|
#include "base/task/thread_pool/thread_pool.h"
|
|
#include "base/threading/thread_task_runner_handle.h"
|
|
#include "electron/electron_version.h"
|
|
#include "gin/array_buffer.h"
|
|
#include "gin/public/isolate_holder.h"
|
|
#include "gin/v8_initializer.h"
|
|
#include "native_mate/dictionary.h"
|
|
#include "shell/app/uv_task_runner.h"
|
|
#include "shell/browser/javascript_environment.h"
|
|
#include "shell/browser/node_debugger.h"
|
|
#include "shell/common/api/electron_bindings.h"
|
|
#include "shell/common/crash_reporter/crash_reporter.h"
|
|
#include "shell/common/native_mate_converters/string16_converter.h"
|
|
#include "shell/common/node_bindings.h"
|
|
#include "shell/common/node_includes.h"
|
|
|
|
#if defined(_WIN64)
|
|
#include "shell/common/crash_reporter/crash_reporter_win.h"
|
|
#endif
|
|
|
|
namespace electron {
|
|
|
|
int NodeMain(int argc, char* argv[]) {
|
|
base::CommandLine::Init(argc, argv);
|
|
|
|
int exit_code = 1;
|
|
{
|
|
// Feed gin::PerIsolateData with a task runner.
|
|
argv = uv_setup_args(argc, argv);
|
|
uv_loop_t* loop = uv_default_loop();
|
|
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
|
|
base::ThreadTaskRunnerHandle handle(uv_task_runner);
|
|
|
|
// Initialize feature list.
|
|
auto feature_list = std::make_unique<base::FeatureList>();
|
|
feature_list->InitializeFromCommandLine("", "");
|
|
base::FeatureList::SetInstance(std::move(feature_list));
|
|
|
|
#if defined(_WIN64)
|
|
crash_reporter::CrashReporterWin::SetUnhandledExceptionFilter();
|
|
#endif
|
|
|
|
// Explicitly register electron's builtin modules.
|
|
NodeBindings::RegisterBuiltinModules();
|
|
|
|
int exec_argc;
|
|
const char** exec_argv;
|
|
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
|
|
|
|
gin::V8Initializer::LoadV8Snapshot(
|
|
gin::V8Initializer::V8SnapshotFileType::kWithAdditionalContext);
|
|
gin::V8Initializer::LoadV8Natives();
|
|
|
|
// V8 requires a task scheduler apparently
|
|
base::ThreadPoolInstance::CreateAndStartWithDefaultParams("Electron");
|
|
|
|
// Initialize gin::IsolateHolder.
|
|
JavascriptEnvironment gin_env(loop);
|
|
|
|
node::Environment* env = node::CreateEnvironment(
|
|
node::CreateIsolateData(gin_env.isolate(), loop, gin_env.platform()),
|
|
gin_env.context(), argc, argv, exec_argc, exec_argv, false);
|
|
|
|
// Enable support for v8 inspector.
|
|
NodeDebugger node_debugger(env);
|
|
node_debugger.Start();
|
|
|
|
node::BootstrapEnvironment(env);
|
|
|
|
mate::Dictionary process(gin_env.isolate(), env->process_object());
|
|
#if defined(OS_WIN)
|
|
process.SetMethod("log", &ElectronBindings::Log);
|
|
#endif
|
|
process.SetMethod("crash", &ElectronBindings::Crash);
|
|
|
|
// Setup process.crashReporter.start in child node processes
|
|
auto reporter = mate::Dictionary::CreateEmpty(gin_env.isolate());
|
|
reporter.SetMethod("start", &crash_reporter::CrashReporter::StartInstance);
|
|
process.Set("crashReporter", reporter);
|
|
|
|
mate::Dictionary versions;
|
|
if (process.Get("versions", &versions)) {
|
|
versions.SetReadOnly(ELECTRON_PROJECT_NAME, ELECTRON_VERSION_STRING);
|
|
}
|
|
|
|
node::LoadEnvironment(env);
|
|
|
|
bool more;
|
|
do {
|
|
more = uv_run(env->event_loop(), UV_RUN_ONCE);
|
|
gin_env.platform()->DrainTasks(env->isolate());
|
|
if (more == false) {
|
|
node::EmitBeforeExit(env);
|
|
|
|
// Emit `beforeExit` if the loop became alive either after emitting
|
|
// event, or after running some callbacks.
|
|
more = uv_loop_alive(env->event_loop());
|
|
if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
|
|
more = true;
|
|
}
|
|
} while (more == true);
|
|
|
|
node_debugger.Stop();
|
|
exit_code = node::EmitExit(env);
|
|
env->set_can_call_into_js(false);
|
|
node::RunAtExit(env);
|
|
|
|
v8::Isolate* isolate = env->isolate();
|
|
node::FreeEnvironment(env);
|
|
|
|
gin_env.platform()->DrainTasks(isolate);
|
|
gin_env.platform()->CancelPendingDelayedTasks(isolate);
|
|
gin_env.platform()->UnregisterIsolate(isolate);
|
|
}
|
|
|
|
// According to "src/gin/shell/gin_main.cc":
|
|
//
|
|
// gin::IsolateHolder waits for tasks running in ThreadPool in its
|
|
// destructor and thus must be destroyed before ThreadPool starts skipping
|
|
// CONTINUE_ON_SHUTDOWN tasks.
|
|
base::ThreadPoolInstance::Get()->Shutdown();
|
|
|
|
v8::V8::Dispose();
|
|
|
|
return exit_code;
|
|
}
|
|
|
|
} // namespace electron
|