Skip to content

Commit

Permalink
fixup! timers: use V8 fast API calls
Browse files Browse the repository at this point in the history
  • Loading branch information
joyeecheung committed Feb 11, 2023
1 parent 92a77aa commit 9567958
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 22 deletions.
23 changes: 18 additions & 5 deletions lib/internal/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,17 @@ class ImmediateList {
const immediateQueue = new ImmediateList();

function incRefCount() {
if (timeoutInfo[0]++ === 0)
if (timeoutInfo[0]++ === 0) {
// We need to use the binding as the receiver for fast API calls.
binding.toggleTimerRef(true);
}
}

function decRefCount() {
if (--timeoutInfo[0] === 0)
if (--timeoutInfo[0] === 0) {
// We need to use the binding as the receiver for fast API calls.
binding.toggleTimerRef(false);
}
}

// Schedule or re-schedule a timer.
Expand Down Expand Up @@ -353,6 +357,7 @@ function insertGuarded(item, refed, start) {
item[kRefed] = refed;
}

// We need to use the binding as the receiver for fast API calls.
function insert(item, msecs, start = binding.getLibuvNow()) {
// Truncate so that accuracy of sub-millisecond timers is not assumed.
msecs = MathTrunc(msecs);
Expand All @@ -367,6 +372,7 @@ function insert(item, msecs, start = binding.getLibuvNow()) {
timerListQueue.insert(list);

if (nextExpiry > expiry) {
// We need to use the binding as the receiver for fast API calls.
binding.scheduleTimer(msecs);
nextExpiry = expiry;
}
Expand Down Expand Up @@ -556,8 +562,10 @@ function getTimerCallbacks(runNextTicks) {
emitBefore(asyncId, timer[trigger_async_id_symbol], timer);

let start;
if (timer._repeat)
if (timer._repeat) {
// We need to use the binding as the receiver for fast API calls.
start = binding.getLibuvNow();
}

try {
const args = timer._timerArgs;
Expand Down Expand Up @@ -624,17 +632,22 @@ class Immediate {
ref() {
if (this[kRefed] === false) {
this[kRefed] = true;
if (immediateInfo[kRefCount]++ === 0)

if (immediateInfo[kRefCount]++ === 0) {
// We need to use the binding as the receiver for fast API calls.
binding.toggleImmediateRef(true);
}
}
return this;
}

unref() {
if (this[kRefed] === true) {
this[kRefed] = false;
if (--immediateInfo[kRefCount] === 0)
if (--immediateInfo[kRefCount] === 0) {
// We need to use the binding as the receiver for fast API calls.
binding.toggleImmediateRef(false);
}
}
return this;
}
Expand Down
4 changes: 3 additions & 1 deletion lib/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,10 @@ function clearImmediate(immediate) {
immediateInfo[kCount]--;
immediate._destroyed = true;

if (immediate[kRefed] && --immediateInfo[kRefCount] === 0)
if (immediate[kRefed] && --immediateInfo[kRefCount] === 0) {
// We need to use the binding as the receiver for fast API calls.
binding.toggleImmediateRef(false);
}
immediate[kRefed] = null;

if (destroyHooksExist() && immediate[async_id_symbol] !== undefined) {
Expand Down
18 changes: 9 additions & 9 deletions src/timers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ double BindingData::GetLibuvNowImpl(BindingData* data) {
return static_cast<double>(data->env()->GetNowUint64());
}

void BindingData::SlowScheduleTimers(const FunctionCallbackInfo<Value>& args) {
void BindingData::SlowScheduleTimer(const FunctionCallbackInfo<Value>& args) {
int64_t duration =
args[0]->IntegerValue(args.GetIsolate()->GetCurrentContext()).FromJust();
ScheduleTimersImpl(Environment::GetBindingData<BindingData>(args), duration);
ScheduleTimerImpl(Environment::GetBindingData<BindingData>(args), duration);
}

void BindingData::FastScheduleTimers(Local<Object> receiver, int64_t duration) {
ScheduleTimersImpl(FromJSObject<BindingData>(receiver), duration);
void BindingData::FastScheduleTimer(Local<Object> receiver, int64_t duration) {
ScheduleTimerImpl(FromJSObject<BindingData>(receiver), duration);
}

void BindingData::ScheduleTimersImpl(BindingData* data, int64_t duration) {
void BindingData::ScheduleTimerImpl(BindingData* data, int64_t duration) {
data->env()->ScheduleTimer(duration);
}

Expand Down Expand Up @@ -113,7 +113,7 @@ void BindingData::Deserialize(Local<Context> context,
v8::CFunction BindingData::fast_get_libuv_now_(
v8::CFunction::Make(FastGetLibuvNow));
v8::CFunction BindingData::fast_schedule_timers_(
v8::CFunction::Make(FastScheduleTimers));
v8::CFunction::Make(FastScheduleTimer));
v8::CFunction BindingData::fast_toggle_timer_ref_(
v8::CFunction::Make(FastToggleTimerRef));
v8::CFunction BindingData::fast_toggle_immediate_ref_(
Expand All @@ -134,7 +134,7 @@ void BindingData::Initialize(Local<Object> target,
SetFastMethod(context,
target,
"scheduleTimer",
SlowScheduleTimers,
SlowScheduleTimer,
&fast_schedule_timers_);
SetFastMethod(context,
target,
Expand Down Expand Up @@ -169,8 +169,8 @@ void BindingData::RegisterTimerExternalReferences(
registry->Register(FastGetLibuvNow);
registry->Register(fast_get_libuv_now_.GetTypeInfo());

registry->Register(SlowScheduleTimers);
registry->Register(FastScheduleTimers);
registry->Register(SlowScheduleTimer);
registry->Register(FastScheduleTimer);
registry->Register(fast_schedule_timers_.GetTypeInfo());

registry->Register(SlowToggleTimerRef);
Expand Down
14 changes: 7 additions & 7 deletions src/timers.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef SRC_NODE_TIMERS_H_
#define SRC_NODE_TIMERS_H_
#ifndef SRC_TIMERS_H_
#define SRC_TIMERS_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

Expand Down Expand Up @@ -31,11 +31,11 @@ class BindingData : public SnapshotableObject {
static double FastGetLibuvNow(v8::Local<v8::Object> receiver);
static double GetLibuvNowImpl(BindingData* data);

static void SlowScheduleTimers(
static void SlowScheduleTimer(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void FastScheduleTimers(v8::Local<v8::Object> receiver,
int64_t duration);
static void ScheduleTimersImpl(BindingData* data, int64_t duration);
static void FastScheduleTimer(v8::Local<v8::Object> receiver,
int64_t duration);
static void ScheduleTimerImpl(BindingData* data, int64_t duration);

static void SlowToggleTimerRef(
const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down Expand Up @@ -67,4 +67,4 @@ class BindingData : public SnapshotableObject {

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_NODE_TIMERS_H_
#endif // SRC_TIMERS_H_
1 change: 1 addition & 0 deletions test/parallel/test-timers-now.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ const { internalBinding } = require('internal/test/binding');
const binding = internalBinding('timers');

// Return value of getLibuvNow() should easily fit in a SMI after start-up.
// We need to use the binding as the receiver for fast API calls.
assert(binding.getLibuvNow() < 0x3ffffff);
1 change: 1 addition & 0 deletions test/parallel/test-timers-ordering.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function f(i) {
last_i = i;

// Check that this iteration is fired at least 1ms later than the previous
// We need to use the binding as the receiver for fast API calls.
const now = binding.getLibuvNow();
assert(now >= last_ts + 1,
`current ts ${now} < prev ts ${last_ts} + 1`);
Expand Down

0 comments on commit 9567958

Please sign in to comment.