diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/env-inl.h | 40 | ||||
-rw-r--r-- | src/env.cc | 36 | ||||
-rw-r--r-- | src/env.h | 17 | ||||
-rw-r--r-- | src/node_perf.cc | 18 | ||||
-rw-r--r-- | src/timer_wrap.cc | 12 |
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() { @@ -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); } |