src: introduce internal C++ SetImmediate() mechanism

PR-URL: https://github.com/nodejs/node/pull/17117
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Anna Henningsen 2017-11-18 14:24:04 +01:00
parent 69e6c5a212
commit 85f3e319c4
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
4 changed files with 74 additions and 32 deletions

View File

@ -492,6 +492,13 @@ Environment::scheduled_immediate_count() {
return scheduled_immediate_count_;
}
void Environment::SetImmediate(native_immediate_callback cb, void* data) {
native_immediate_callbacks_.push_back({ cb, data });
if (scheduled_immediate_count_[0] == 0)
ActivateImmediateCheck();
scheduled_immediate_count_[0] = scheduled_immediate_count_[0] + 1;
}
inline performance::performance_state* Environment::performance_state() {
return performance_state_;
}

View File

@ -277,6 +277,59 @@ void Environment::EnvPromiseHook(v8::PromiseHookType type,
}
}
void Environment::RunAndClearNativeImmediates() {
size_t count = native_immediate_callbacks_.size();
if (count > 0) {
std::vector<NativeImmediateCallback> list;
native_immediate_callbacks_.swap(list);
for (const auto& cb : list) {
cb.cb_(this, cb.data_);
}
#ifdef DEBUG
CHECK_GE(scheduled_immediate_count_[0], count);
#endif
scheduled_immediate_count_[0] = scheduled_immediate_count_[0] - count;
}
}
static bool MaybeStopImmediate(Environment* env) {
if (env->scheduled_immediate_count()[0] == 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))
return;
env->RunAndClearNativeImmediates();
MakeCallback(env->isolate(),
env->process_object(),
env->immediate_callback_string(),
0,
nullptr,
{0, 0}).ToLocalChecked();
MaybeStopImmediate(env);
}
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 CollectExceptionInfo(Environment* env,
v8::Local<v8::Object> obj,
int errorno,

View File

@ -688,6 +688,11 @@ class Environment {
bool RemovePromiseHook(promise_hook_func fn, void* arg);
bool EmitNapiWarning();
typedef void (*native_immediate_callback)(Environment* env, void* data);
inline void SetImmediate(native_immediate_callback cb, void* data);
// This needs to be available for the JS-land setImmediate().
void ActivateImmediateCheck();
private:
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
const char* errmsg);
@ -747,6 +752,14 @@ class Environment {
};
std::vector<PromiseHookCallback> promise_hooks_;
struct NativeImmediateCallback {
native_immediate_callback cb_;
void* data_;
};
std::vector<NativeImmediateCallback> native_immediate_callbacks_;
void RunAndClearNativeImmediates();
static void CheckImmediate(uv_check_t* handle);
static void EnvPromiseHook(v8::PromiseHookType type,
v8::Local<v8::Promise> promise,
v8::Local<v8::Value> parent);

View File

@ -2933,40 +2933,9 @@ static void DebugEnd(const FunctionCallbackInfo<Value>& args);
namespace {
bool MaybeStopImmediate(Environment* env) {
if (env->scheduled_immediate_count()[0] == 0) {
uv_check_stop(env->immediate_check_handle());
uv_idle_stop(env->immediate_idle_handle());
return true;
}
return false;
}
void 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))
return;
MakeCallback(env->isolate(),
env->process_object(),
env->immediate_callback_string(),
0,
nullptr,
{0, 0}).ToLocalChecked();
MaybeStopImmediate(env);
}
void ActivateImmediateCheck(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
uv_check_start(env->immediate_check_handle(), CheckImmediate);
// Idle handle is needed only to stop the event loop from blocking in poll.
uv_idle_start(env->immediate_idle_handle(),
[](uv_idle_t*){ /* do nothing, just keep the loop running */ });
env->ActivateImmediateCheck();
}