Skip to content

Commit

Permalink
src: introduce internal C++ SetImmediate() mechanism
Browse files Browse the repository at this point in the history
PR-URL: #17117
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
addaleax committed Nov 21, 2017
1 parent 69e6c5a commit 85f3e31
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 32 deletions.
7 changes: 7 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
}
Expand Down
53 changes: 53 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 13 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 1 addition & 32 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}


Expand Down

0 comments on commit 85f3e31

Please sign in to comment.