Skip to content

Commit

Permalink
timers: use V8 fast API calls
Browse files Browse the repository at this point in the history
PR-URL: #46579
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
  • Loading branch information
joyeecheung authored and targos committed Mar 14, 2023
1 parent c0b6413 commit 25069a6
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 59 deletions.
44 changes: 27 additions & 17 deletions lib/internal/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,11 @@ const {
Symbol,
} = primordials;

const binding = internalBinding('timers');
const {
scheduleTimer,
toggleTimerRef,
getLibuvNow,
immediateInfo,
timeoutInfo,
toggleImmediateRef,
} = internalBinding('timers');
} = binding;

const {
getDefaultTriggerAsyncId,
Expand Down Expand Up @@ -306,13 +303,17 @@ class ImmediateList {
const immediateQueue = new ImmediateList();

function incRefCount() {
if (timeoutInfo[0]++ === 0)
toggleTimerRef(true);
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)
toggleTimerRef(false);
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 @@ -356,7 +357,8 @@ function insertGuarded(item, refed, start) {
item[kRefed] = refed;
}

function insert(item, msecs, start = getLibuvNow()) {
// 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);
item._idleStart = start;
Expand All @@ -370,7 +372,8 @@ function insert(item, msecs, start = getLibuvNow()) {
timerListQueue.insert(list);

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

let start;
if (timer._repeat)
start = getLibuvNow();
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 @@ -627,17 +632,22 @@ class Immediate {
ref() {
if (this[kRefed] === false) {
this[kRefed] = true;
if (immediateInfo[kRefCount]++ === 0)
toggleImmediateRef(true);

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)
toggleImmediateRef(false);
if (--immediateInfo[kRefCount] === 0) {
// We need to use the binding as the receiver for fast API calls.
binding.toggleImmediateRef(false);
}
}
return this;
}
Expand Down
10 changes: 6 additions & 4 deletions lib/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ const {
SymbolToPrimitive
} = primordials;

const binding = internalBinding('timers');
const {
immediateInfo,
toggleImmediateRef
} = internalBinding('timers');
} = binding;
const L = require('internal/linkedlist');
const {
async_id_symbol,
Expand Down Expand Up @@ -323,8 +323,10 @@ function clearImmediate(immediate) {
immediateInfo[kCount]--;
immediate._destroyed = true;

if (immediate[kRefed] && --immediateInfo[kRefCount] === 0)
toggleImmediateRef(false);
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
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@
'src/string_decoder-inl.h',
'src/string_search.h',
'src/tcp_wrap.h',
'src/timers.h',
'src/tracing/agent.h',
'src/tracing/node_trace_buffer.h',
'src/tracing/node_trace_writer.h',
Expand Down
3 changes: 2 additions & 1 deletion src/base_object_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ namespace node {
V(fs_binding_data, fs::BindingData) \
V(v8_binding_data, v8_utils::BindingData) \
V(blob_binding_data, BlobBindingData) \
V(process_binding_data, process::BindingData)
V(process_binding_data, process::BindingData) \
V(timers_binding_data, timers::BindingData)

#define UNSERIALIZABLE_BINDING_TYPES(V) \
V(http2_binding_data, http2::BindingData) \
Expand Down
8 changes: 6 additions & 2 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1273,12 +1273,16 @@ void Environment::ToggleImmediateRef(bool ref) {
}
}


Local<Value> Environment::GetNow() {
uint64_t Environment::GetNowUint64() {
uv_update_time(event_loop());
uint64_t now = uv_now(event_loop());
CHECK_GE(now, timer_base());
now -= timer_base();
return now;
}

Local<Value> Environment::GetNow() {
uint64_t now = GetNowUint64();
if (now <= 0xffffffff)
return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
else
Expand Down
2 changes: 2 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,8 @@ class Environment : public MemoryRetainer {
static inline Environment* ForAsyncHooks(AsyncHooks* hooks);

v8::Local<v8::Value> GetNow();
uint64_t GetNowUint64();

void ScheduleTimer(int64_t duration);
void ToggleTimerRef(bool ref);

Expand Down
9 changes: 9 additions & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ namespace node {
using CFunctionCallbackWithOneByteString =
uint32_t (*)(v8::Local<v8::Value>, const v8::FastOneByteString&);
using CFunctionCallback = void (*)(v8::Local<v8::Value> receiver);
using CFunctionCallbackReturnDouble =
double (*)(v8::Local<v8::Object> receiver);
using CFunctionCallbackWithInt64 = void (*)(v8::Local<v8::Object> receiver,
int64_t);
using CFunctionCallbackWithBool = void (*)(v8::Local<v8::Object> receiver,
bool);

// This class manages the external references from the V8 heap
// to the C++ addresses in Node.js.
Expand All @@ -23,6 +29,9 @@ class ExternalReferenceRegistry {
#define ALLOWED_EXTERNAL_REFERENCE_TYPES(V) \
V(CFunctionCallback) \
V(CFunctionCallbackWithOneByteString) \
V(CFunctionCallbackReturnDouble) \
V(CFunctionCallbackWithInt64) \
V(CFunctionCallbackWithBool) \
V(const v8::CFunctionInfo*) \
V(v8::FunctionCallback) \
V(v8::AccessorGetterCallback) \
Expand Down
1 change: 1 addition & 0 deletions src/node_snapshotable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "node_util.h"
#include "node_v8.h"
#include "node_v8_platform-inl.h"
#include "timers.h"

#if HAVE_INSPECTOR
#include "inspector/worker_inspector.h" // ParentInspectorHandle
Expand Down
Loading

0 comments on commit 25069a6

Please sign in to comment.