summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/env-inl.h40
-rw-r--r--src/env.cc36
-rw-r--r--src/env.h17
-rw-r--r--src/node_perf.cc18
-rw-r--r--src/timer_wrap.cc12
5 files changed, 80 insertions, 43 deletions
diff --git a/src/env-inl.h b/src/env-inl.h
index 0328f058de..37d1cf172e 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -229,6 +229,10 @@ inline uint32_t Environment::ImmediateInfo::count() const {
return fields_[kCount];
}
+inline uint32_t Environment::ImmediateInfo::ref_count() const {
+ return fields_[kRefCount];
+}
+
inline bool Environment::ImmediateInfo::has_outstanding() const {
return fields_[kHasOutstanding] == 1;
}
@@ -241,6 +245,14 @@ inline void Environment::ImmediateInfo::count_dec(uint32_t decrement) {
fields_[kCount] = fields_[kCount] - decrement;
}
+inline void Environment::ImmediateInfo::ref_count_inc(uint32_t increment) {
+ fields_[kRefCount] = fields_[kRefCount] + increment;
+}
+
+inline void Environment::ImmediateInfo::ref_count_dec(uint32_t decrement) {
+ fields_[kRefCount] = fields_[kRefCount] - decrement;
+}
+
inline Environment::TickInfo::TickInfo(v8::Isolate* isolate)
: fields_(isolate, kFieldsCount) {}
@@ -514,20 +526,36 @@ inline void Environment::set_fs_stats_field_array(double* fields) {
fs_stats_field_array_ = fields;
}
-void Environment::SetImmediate(native_immediate_callback cb,
+void Environment::CreateImmediate(native_immediate_callback cb,
void* data,
- v8::Local<v8::Object> obj) {
+ v8::Local<v8::Object> obj,
+ bool ref) {
native_immediate_callbacks_.push_back({
cb,
data,
- std::unique_ptr<v8::Persistent<v8::Object>>(
- obj.IsEmpty() ? nullptr : new v8::Persistent<v8::Object>(isolate_, obj))
+ std::unique_ptr<v8::Persistent<v8::Object>>(obj.IsEmpty() ?
+ nullptr : new v8::Persistent<v8::Object>(isolate_, obj)),
+ ref
});
- if (immediate_info()->count() == 0)
- ActivateImmediateCheck();
immediate_info()->count_inc(1);
}
+void Environment::SetImmediate(native_immediate_callback cb,
+ void* data,
+ v8::Local<v8::Object> obj) {
+ CreateImmediate(cb, data, obj, true);
+
+ if (immediate_info()->ref_count() == 0)
+ ToggleImmediateRef(true);
+ immediate_info()->ref_count_inc(1);
+}
+
+void Environment::SetUnrefImmediate(native_immediate_callback cb,
+ void* data,
+ v8::Local<v8::Object> obj) {
+ CreateImmediate(cb, data, obj, false);
+}
+
inline performance::performance_state* Environment::performance_state() {
return performance_state_.get();
}
diff --git a/src/env.cc b/src/env.cc
index e4afb35786..17cdbbb79f 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -80,6 +80,8 @@ void Environment::Start(int argc,
uv_idle_init(event_loop(), immediate_idle_handle());
+ uv_check_start(immediate_check_handle(), CheckImmediate);
+
// Inform V8's CPU profiler when we're idle. The profiler is sampling-based
// but not all samples are created equal; mark the wall clock time spent in
// epoll_wait() and friends so profiling tools can filter it out. The samples
@@ -272,39 +274,35 @@ void Environment::EnvPromiseHook(v8::PromiseHookType type,
void Environment::RunAndClearNativeImmediates() {
size_t count = native_immediate_callbacks_.size();
if (count > 0) {
+ size_t ref_count = 0;
std::vector<NativeImmediateCallback> list;
native_immediate_callbacks_.swap(list);
for (const auto& cb : list) {
cb.cb_(this, cb.data_);
if (cb.keep_alive_)
cb.keep_alive_->Reset();
+ if (cb.refed_)
+ ref_count++;
}
#ifdef DEBUG
CHECK_GE(immediate_info()->count(), count);
#endif
immediate_info()->count_dec(count);
+ immediate_info()->ref_count_dec(ref_count);
}
}
-static bool MaybeStopImmediate(Environment* env) {
- if (env->immediate_info()->count() == 0) {
- uv_check_stop(env->immediate_check_handle());
- uv_idle_stop(env->immediate_idle_handle());
- return true;
- }
- return false;
-}
-
void Environment::CheckImmediate(uv_check_t* handle) {
Environment* env = Environment::from_immediate_check_handle(handle);
- HandleScope scope(env->isolate());
- Context::Scope context_scope(env->context());
- if (MaybeStopImmediate(env))
+ if (env->immediate_info()->count() == 0)
return;
+ HandleScope scope(env->isolate());
+ Context::Scope context_scope(env->context());
+
env->RunAndClearNativeImmediates();
do {
@@ -316,13 +314,17 @@ void Environment::CheckImmediate(uv_check_t* handle) {
{0, 0}).ToLocalChecked();
} while (env->immediate_info()->has_outstanding());
- MaybeStopImmediate(env);
+ if (env->immediate_info()->ref_count() == 0)
+ env->ToggleImmediateRef(false);
}
-void Environment::ActivateImmediateCheck() {
- uv_check_start(&immediate_check_handle_, CheckImmediate);
- // Idle handle is needed only to stop the event loop from blocking in poll.
- uv_idle_start(&immediate_idle_handle_, [](uv_idle_t*){ });
+void Environment::ToggleImmediateRef(bool ref) {
+ if (ref) {
+ // Idle handle is needed only to stop the event loop from blocking in poll.
+ uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
+ } else {
+ uv_idle_stop(immediate_idle_handle());
+ }
}
void Environment::AsyncHooks::grow_async_ids_stack() {
diff --git a/src/env.h b/src/env.h
index b295347a9a..b834585edd 100644
--- a/src/env.h
+++ b/src/env.h
@@ -455,17 +455,22 @@ class Environment {
public:
inline AliasedBuffer<uint32_t, v8::Uint32Array>& fields();
inline uint32_t count() const;
+ inline uint32_t ref_count() const;
inline bool has_outstanding() const;
inline void count_inc(uint32_t increment);
inline void count_dec(uint32_t decrement);
+ inline void ref_count_inc(uint32_t increment);
+ inline void ref_count_dec(uint32_t decrement);
+
private:
friend class Environment; // So we can call the constructor.
inline explicit ImmediateInfo(v8::Isolate* isolate);
enum Fields {
kCount,
+ kRefCount,
kHasOutstanding,
kFieldsCount
};
@@ -680,8 +685,12 @@ class Environment {
inline void SetImmediate(native_immediate_callback cb,
void* data,
v8::Local<v8::Object> obj = v8::Local<v8::Object>());
+ inline void SetUnrefImmediate(native_immediate_callback cb,
+ void* data,
+ v8::Local<v8::Object> obj =
+ v8::Local<v8::Object>());
// This needs to be available for the JS-land setImmediate().
- void ActivateImmediateCheck();
+ void ToggleImmediateRef(bool ref);
class ShouldNotAbortOnUncaughtScope {
public:
@@ -698,6 +707,11 @@ class Environment {
static inline Environment* ForAsyncHooks(AsyncHooks* hooks);
private:
+ inline void CreateImmediate(native_immediate_callback cb,
+ void* data,
+ v8::Local<v8::Object> obj,
+ bool ref);
+
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
const char* errmsg);
@@ -761,6 +775,7 @@ class Environment {
native_immediate_callback cb_;
void* data_;
std::unique_ptr<v8::Persistent<v8::Object>> keep_alive_;
+ bool refed_;
};
std::vector<NativeImmediateCallback> native_immediate_callbacks_;
void RunAndClearNativeImmediates();
diff --git a/src/node_perf.cc b/src/node_perf.cc
index 8862e5fab7..8ee805a838 100644
--- a/src/node_perf.cc
+++ b/src/node_perf.cc
@@ -184,9 +184,8 @@ void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
}
// Creates a GC Performance Entry and passes it to observers
-void PerformanceGCCallback(uv_async_t* handle) {
- GCPerformanceEntry* entry = static_cast<GCPerformanceEntry*>(handle->data);
- Environment* env = entry->env();
+void PerformanceGCCallback(Environment* env, void* ptr) {
+ GCPerformanceEntry* entry = static_cast<GCPerformanceEntry*>(ptr);
HandleScope scope(env->isolate());
Local<Context> context = env->context();
@@ -204,10 +203,6 @@ void PerformanceGCCallback(uv_async_t* handle) {
}
delete entry;
- auto closeCB = [](uv_handle_t* handle) {
- delete reinterpret_cast<uv_async_t*>(handle);
- };
- uv_close(reinterpret_cast<uv_handle_t*>(handle), closeCB);
}
// Marks the start of a GC cycle
@@ -224,16 +219,13 @@ void MarkGarbageCollectionEnd(Isolate* isolate,
v8::GCCallbackFlags flags,
void* data) {
Environment* env = static_cast<Environment*>(data);
- uv_async_t* async = new uv_async_t();
- if (uv_async_init(env->event_loop(), async, PerformanceGCCallback))
- return delete async;
- uv_unref(reinterpret_cast<uv_handle_t*>(async));
- async->data =
+ GCPerformanceEntry* entry =
new GCPerformanceEntry(env,
static_cast<PerformanceGCKind>(type),
performance_last_gc_start_mark_,
PERFORMANCE_NOW());
- CHECK_EQ(0, uv_async_send(async));
+ env->SetUnrefImmediate(PerformanceGCCallback,
+ entry);
}
diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc
index ab450fcb3e..1725cf30e7 100644
--- a/src/timer_wrap.cc
+++ b/src/timer_wrap.cc
@@ -83,16 +83,16 @@ class TimerWrap : public HandleWrap {
CHECK(args[0]->IsFunction());
auto env = Environment::GetCurrent(args);
env->set_immediate_callback_function(args[0].As<Function>());
- auto activate_cb = [] (const FunctionCallbackInfo<Value>& args) {
- Environment::GetCurrent(args)->ActivateImmediateCheck();
+ auto toggle_ref_cb = [] (const FunctionCallbackInfo<Value>& args) {
+ Environment::GetCurrent(args)->ToggleImmediateRef(args[0]->IsTrue());
};
- auto activate_function =
- env->NewFunctionTemplate(activate_cb)->GetFunction(env->context())
+ auto toggle_ref_function =
+ env->NewFunctionTemplate(toggle_ref_cb)->GetFunction(env->context())
.ToLocalChecked();
auto result = Array::New(env->isolate(), 2);
- result->Set(env->context(), 0, activate_function).FromJust();
- result->Set(env->context(), 1,
+ result->Set(env->context(), 0,
env->immediate_info()->fields().GetJSArray()).FromJust();
+ result->Set(env->context(), 1, toggle_ref_function).FromJust();
args.GetReturnValue().Set(result);
}