summaryrefslogtreecommitdiff
path: root/src/env.cc
diff options
context:
space:
mode:
authorGireesh Punathil <gpunathi@in.ibm.com>2018-06-12 09:01:46 -0400
committerGireesh Punathil <gpunathi@in.ibm.com>2019-03-16 12:50:26 +0530
commitd35af56e5f3b1334c4360dbf8a013d0c522fe5f8 (patch)
treea6f9bb5467ec693c04d6741c3704a7c80a4eb482 /src/env.cc
parent22de2cfb71f3f1ab63e9663f4aa62bd9016b762a (diff)
downloadnode-new-d35af56e5f3b1334c4360dbf8a013d0c522fe5f8.tar.gz
src: shutdown node in-flight
This commit introduces a `node::Stop()` API. An identified use case for embedders is their ability to tear down Node while it is still running (event loop contain pending events) Here the assumptions are that (i) embedders do not wish to resort to JS routines to initiate shutdown (ii) embedders have the Environment handle handy. (iii) embedders stop Node through a second thread. Fixes: https://github.com/nodejs/node/issues/19365 Refs: https://github.com/nodejs/user-feedback/issues/51 PR-URL: https://github.com/nodejs/node/pull/21283 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Michael Dawson <Michael_Dawson@ca.ibm.com>
Diffstat (limited to 'src/env.cc')
-rw-r--r--src/env.cc62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/env.cc b/src/env.cc
index 2448754db9..768e14d796 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -340,6 +340,14 @@ void Environment::InitializeLibuv(bool start_profiler_idle_notifier) {
uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
+ GetAsyncRequest()->Install(
+ this, static_cast<void*>(this), [](uv_async_t* handle) {
+ Environment* env = static_cast<Environment*>(handle->data);
+ uv_stop(env->event_loop());
+ });
+ GetAsyncRequest()->SetStopped(false);
+ uv_unref(reinterpret_cast<uv_handle_t*>(GetAsyncRequest()->GetHandle()));
+
// Register clean-up cb to be called to clean up the handles
// when the environment is freed, note that they are not cleaned in
// the one environment per process setup, but will be called in
@@ -355,6 +363,12 @@ void Environment::InitializeLibuv(bool start_profiler_idle_notifier) {
uv_key_set(&thread_local_env, this);
}
+void Environment::ExitEnv() {
+ set_can_call_into_js(false);
+ GetAsyncRequest()->Stop();
+ isolate_->TerminateExecution();
+}
+
MaybeLocal<Object> Environment::ProcessCliArgs(
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args) {
@@ -519,6 +533,7 @@ void Environment::RunCleanup() {
started_cleanup_ = true;
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"RunCleanup", this);
+ GetAsyncRequest()->Uninstall();
CleanupHandles();
while (!cleanup_hooks_.empty()) {
@@ -932,6 +947,53 @@ char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
return new_data;
}
+void AsyncRequest::Install(Environment* env, void* data, uv_async_cb target) {
+ Mutex::ScopedLock lock(mutex_);
+ env_ = env;
+ async_ = new uv_async_t;
+ async_->data = data;
+ CHECK_EQ(uv_async_init(env_->event_loop(), async_, target), 0);
+}
+
+void AsyncRequest::Uninstall() {
+ Mutex::ScopedLock lock(mutex_);
+ if (async_ != nullptr) {
+ env_->CloseHandle(async_, [](uv_async_t* async) { delete async; });
+ async_ = nullptr;
+ }
+}
+
+void AsyncRequest::Stop() {
+ Mutex::ScopedLock lock(mutex_);
+ stop_ = true;
+ if (async_ != nullptr) uv_async_send(async_);
+}
+
+void AsyncRequest::SetStopped(bool flag) {
+ Mutex::ScopedLock lock(mutex_);
+ stop_ = flag;
+}
+
+bool AsyncRequest::IsStopped() const {
+ Mutex::ScopedLock lock(mutex_);
+ return stop_;
+}
+
+uv_async_t* AsyncRequest::GetHandle() {
+ Mutex::ScopedLock lock(mutex_);
+ return async_;
+}
+
+void AsyncRequest::MemoryInfo(MemoryTracker* tracker) const {
+ Mutex::ScopedLock lock(mutex_);
+ if (async_ != nullptr) tracker->TrackField("async_request", *async_);
+}
+
+AsyncRequest::~AsyncRequest() {
+ Mutex::ScopedLock lock(mutex_);
+ CHECK_NULL(async_);
+}
+
// Not really any better place than env.cc at this moment.
void BaseObject::DeleteMe(void* data) {
BaseObject* self = static_cast<BaseObject*>(data);