Skip to content

Commit 92fcc24

Browse files
committed
src: introduce internal C++ SetImmediate() mechanism
PR-URL: nodejs#17117
1 parent e413350 commit 92fcc24

4 files changed

Lines changed: 73 additions & 32 deletions

File tree

src/env-inl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,13 @@ Environment::scheduled_immediate_count() {
539539
return scheduled_immediate_count_;
540540
}
541541

542+
void Environment::SetImmediate(native_immediate_callback cb, void* data) {
543+
native_immediate_callbacks_.push_back({ cb, data });
544+
if (scheduled_immediate_count_[0] == 0)
545+
ActivateImmediateCheck();
546+
scheduled_immediate_count_[0] = scheduled_immediate_count_[0] + 1;
547+
}
548+
542549
inline performance::performance_state* Environment::performance_state() {
543550
return performance_state_;
544551
}

src/env.cc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,56 @@ void Environment::EnvPromiseHook(v8::PromiseHookType type,
223223
}
224224
}
225225

226+
void Environment::RunAndClearNativeImmediates() {
227+
size_t count = native_immediate_callbacks_.size();
228+
if (count > 0) {
229+
std::vector<NativeImmediateCallback> list;
230+
native_immediate_callbacks_.swap(list);
231+
for (const auto& cb : list) {
232+
cb.cb_(this, cb.data_);
233+
}
234+
235+
#ifdef DEBUG
236+
CHECK_GE(scheduled_immediate_count_[0], count);
237+
#endif
238+
scheduled_immediate_count_[0] = scheduled_immediate_count_[0] - count;
239+
}
240+
}
241+
242+
static bool MaybeStopImmediate(Environment* env) {
243+
if (env->scheduled_immediate_count()[0] == 0) {
244+
uv_check_stop(env->immediate_check_handle());
245+
uv_idle_stop(env->immediate_idle_handle());
246+
return true;
247+
}
248+
return false;
249+
}
250+
251+
252+
void Environment::CheckImmediate(uv_check_t* handle) {
253+
Environment* env = Environment::from_immediate_check_handle(handle);
254+
HandleScope scope(env->isolate());
255+
Context::Scope context_scope(env->context());
256+
257+
if (MaybeStopImmediate(env))
258+
return;
259+
260+
env->RunAndClearNativeImmediates();
261+
262+
MakeCallback(env->isolate(),
263+
env->process_object(),
264+
env->immediate_callback_string(),
265+
0,
266+
nullptr,
267+
{0, 0}).ToLocalChecked();
268+
269+
MaybeStopImmediate(env);
270+
}
271+
272+
void Environment::ActivateImmediateCheck() {
273+
uv_check_start(&immediate_check_handle_, CheckImmediate);
274+
// Idle handle is needed only to stop the event loop from blocking in poll.
275+
uv_idle_start(&immediate_idle_handle_, [](uv_idle_t*){ });
276+
}
277+
226278
} // namespace node

src/env.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,11 @@ class Environment {
692692
bool RemovePromiseHook(promise_hook_func fn, void* arg);
693693
bool EmitNapiWarning();
694694

695+
typedef void (*native_immediate_callback)(Environment* env, void* data);
696+
inline void SetImmediate(native_immediate_callback cb, void* data);
697+
// This needs to be available for the JS-land setImmediate().
698+
void ActivateImmediateCheck();
699+
695700
private:
696701
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
697702
const char* errmsg);
@@ -752,6 +757,14 @@ class Environment {
752757
};
753758
std::vector<PromiseHookCallback> promise_hooks_;
754759

760+
struct NativeImmediateCallback {
761+
native_immediate_callback cb_;
762+
void* data_;
763+
};
764+
std::vector<NativeImmediateCallback> native_immediate_callbacks_;
765+
void RunAndClearNativeImmediates();
766+
static void CheckImmediate(uv_check_t* handle);
767+
755768
static void EnvPromiseHook(v8::PromiseHookType type,
756769
v8::Local<v8::Promise> promise,
757770
v8::Local<v8::Value> parent);

src/node.cc

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,40 +3243,9 @@ static void DebugEnd(const FunctionCallbackInfo<Value>& args);
32433243

32443244
namespace {
32453245

3246-
bool MaybeStopImmediate(Environment* env) {
3247-
if (env->scheduled_immediate_count()[0] == 0) {
3248-
uv_check_stop(env->immediate_check_handle());
3249-
uv_idle_stop(env->immediate_idle_handle());
3250-
return true;
3251-
}
3252-
return false;
3253-
}
3254-
3255-
void CheckImmediate(uv_check_t* handle) {
3256-
Environment* env = Environment::from_immediate_check_handle(handle);
3257-
HandleScope scope(env->isolate());
3258-
Context::Scope context_scope(env->context());
3259-
3260-
if (MaybeStopImmediate(env))
3261-
return;
3262-
3263-
MakeCallback(env->isolate(),
3264-
env->process_object(),
3265-
env->immediate_callback_string(),
3266-
0,
3267-
nullptr,
3268-
{0, 0}).ToLocalChecked();
3269-
3270-
MaybeStopImmediate(env);
3271-
}
3272-
3273-
32743246
void ActivateImmediateCheck(const FunctionCallbackInfo<Value>& args) {
32753247
Environment* env = Environment::GetCurrent(args);
3276-
uv_check_start(env->immediate_check_handle(), CheckImmediate);
3277-
// Idle handle is needed only to stop the event loop from blocking in poll.
3278-
uv_idle_start(env->immediate_idle_handle(),
3279-
[](uv_idle_t*){ /* do nothing, just keep the loop running */ });
3248+
env->ActivateImmediateCheck();
32803249
}
32813250

32823251

0 commit comments

Comments
 (0)