mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
timers: use V8 fast API calls
PR-URL: https://github.com/nodejs/node/pull/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>
This commit is contained in:
parent
9562c20bc9
commit
1101713cc2
@ -81,14 +81,11 @@ const {
|
||||
Symbol,
|
||||
} = primordials;
|
||||
|
||||
const binding = internalBinding('timers');
|
||||
const {
|
||||
scheduleTimer,
|
||||
toggleTimerRef,
|
||||
getLibuvNow,
|
||||
immediateInfo,
|
||||
timeoutInfo,
|
||||
toggleImmediateRef,
|
||||
} = internalBinding('timers');
|
||||
} = binding;
|
||||
|
||||
const {
|
||||
getDefaultTriggerAsyncId,
|
||||
@ -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.
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
@ -627,8 +632,11 @@ 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;
|
||||
}
|
||||
@ -636,8 +644,10 @@ class Immediate {
|
||||
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;
|
||||
}
|
||||
|
@ -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,
|
||||
@ -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) {
|
||||
|
1
node.gyp
1
node.gyp
@ -677,6 +677,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',
|
||||
|
@ -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) \
|
||||
|
@ -1299,12 +1299,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
|
||||
|
@ -891,6 +891,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);
|
||||
|
||||
|
@ -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.
|
||||
@ -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) \
|
||||
|
@ -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
|
||||
|
174
src/timers.cc
174
src/timers.cc
@ -1,3 +1,4 @@
|
||||
#include "timers.h"
|
||||
#include "env-inl.h"
|
||||
#include "node_external_reference.h"
|
||||
#include "util-inl.h"
|
||||
@ -6,16 +7,17 @@
|
||||
#include <cstdint>
|
||||
|
||||
namespace node {
|
||||
namespace {
|
||||
namespace timers {
|
||||
|
||||
using v8::Context;
|
||||
using v8::Function;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::Local;
|
||||
using v8::Number;
|
||||
using v8::Object;
|
||||
using v8::Value;
|
||||
|
||||
void SetupTimers(const FunctionCallbackInfo<Value>& args) {
|
||||
void BindingData::SetupTimers(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK(args[0]->IsFunction());
|
||||
CHECK(args[1]->IsFunction());
|
||||
auto env = Environment::GetCurrent(args);
|
||||
@ -24,58 +26,168 @@ void SetupTimers(const FunctionCallbackInfo<Value>& args) {
|
||||
env->set_timers_callback_function(args[1].As<Function>());
|
||||
}
|
||||
|
||||
void GetLibuvNow(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
args.GetReturnValue().Set(env->GetNow());
|
||||
void BindingData::SlowGetLibuvNow(const FunctionCallbackInfo<Value>& args) {
|
||||
double now = GetLibuvNowImpl(Realm::GetBindingData<BindingData>(args));
|
||||
args.GetReturnValue().Set(Number::New(args.GetIsolate(), now));
|
||||
}
|
||||
|
||||
void ScheduleTimer(const FunctionCallbackInfo<Value>& args) {
|
||||
auto env = Environment::GetCurrent(args);
|
||||
env->ScheduleTimer(args[0]->IntegerValue(env->context()).FromJust());
|
||||
double BindingData::FastGetLibuvNow(Local<Object> receiver) {
|
||||
return GetLibuvNowImpl(FromJSObject<BindingData>(receiver));
|
||||
}
|
||||
|
||||
void ToggleTimerRef(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment::GetCurrent(args)->ToggleTimerRef(args[0]->IsTrue());
|
||||
double BindingData::GetLibuvNowImpl(BindingData* data) {
|
||||
return static_cast<double>(data->env()->GetNowUint64());
|
||||
}
|
||||
|
||||
void ToggleImmediateRef(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment::GetCurrent(args)->ToggleImmediateRef(args[0]->IsTrue());
|
||||
void BindingData::SlowScheduleTimer(const FunctionCallbackInfo<Value>& args) {
|
||||
int64_t duration =
|
||||
args[0]->IntegerValue(args.GetIsolate()->GetCurrentContext()).FromJust();
|
||||
ScheduleTimerImpl(Realm::GetBindingData<BindingData>(args), duration);
|
||||
}
|
||||
|
||||
void Initialize(Local<Object> target,
|
||||
Local<Value> unused,
|
||||
Local<Context> context,
|
||||
void* priv) {
|
||||
Environment* env = Environment::GetCurrent(context);
|
||||
void BindingData::FastScheduleTimer(Local<Object> receiver, int64_t duration) {
|
||||
ScheduleTimerImpl(FromJSObject<BindingData>(receiver), duration);
|
||||
}
|
||||
|
||||
void BindingData::ScheduleTimerImpl(BindingData* data, int64_t duration) {
|
||||
data->env()->ScheduleTimer(duration);
|
||||
}
|
||||
|
||||
void BindingData::SlowToggleTimerRef(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
ToggleTimerRefImpl(Realm::GetBindingData<BindingData>(args),
|
||||
args[0]->IsTrue());
|
||||
}
|
||||
|
||||
void BindingData::FastToggleTimerRef(Local<Object> receiver, bool ref) {
|
||||
ToggleTimerRefImpl(FromJSObject<BindingData>(receiver), ref);
|
||||
}
|
||||
|
||||
void BindingData::ToggleTimerRefImpl(BindingData* data, bool ref) {
|
||||
data->env()->ToggleTimerRef(ref);
|
||||
}
|
||||
|
||||
void BindingData::SlowToggleImmediateRef(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
ToggleImmediateRefImpl(Realm::GetBindingData<BindingData>(args),
|
||||
args[0]->IsTrue());
|
||||
}
|
||||
|
||||
void BindingData::FastToggleImmediateRef(Local<Object> receiver, bool ref) {
|
||||
ToggleImmediateRefImpl(FromJSObject<BindingData>(receiver), ref);
|
||||
}
|
||||
|
||||
void BindingData::ToggleImmediateRefImpl(BindingData* data, bool ref) {
|
||||
data->env()->ToggleImmediateRef(ref);
|
||||
}
|
||||
|
||||
BindingData::BindingData(Realm* realm, Local<Object> object)
|
||||
: SnapshotableObject(realm, object, type_int) {}
|
||||
|
||||
bool BindingData::PrepareForSerialization(Local<Context> context,
|
||||
v8::SnapshotCreator* creator) {
|
||||
// Return true because we need to maintain the reference to the binding from
|
||||
// JS land.
|
||||
return true;
|
||||
}
|
||||
|
||||
InternalFieldInfoBase* BindingData::Serialize(int index) {
|
||||
DCHECK_EQ(index, BaseObject::kEmbedderType);
|
||||
InternalFieldInfo* info =
|
||||
InternalFieldInfoBase::New<InternalFieldInfo>(type());
|
||||
return info;
|
||||
}
|
||||
|
||||
void BindingData::Deserialize(Local<Context> context,
|
||||
Local<Object> holder,
|
||||
int index,
|
||||
InternalFieldInfoBase* info) {
|
||||
DCHECK_EQ(index, BaseObject::kEmbedderType);
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
Realm* realm = Realm::GetCurrent(context);
|
||||
// Recreate the buffer in the constructor.
|
||||
BindingData* binding = realm->AddBindingData<BindingData>(context, holder);
|
||||
CHECK_NOT_NULL(binding);
|
||||
}
|
||||
|
||||
v8::CFunction BindingData::fast_get_libuv_now_(
|
||||
v8::CFunction::Make(FastGetLibuvNow));
|
||||
v8::CFunction BindingData::fast_schedule_timers_(
|
||||
v8::CFunction::Make(FastScheduleTimer));
|
||||
v8::CFunction BindingData::fast_toggle_timer_ref_(
|
||||
v8::CFunction::Make(FastToggleTimerRef));
|
||||
v8::CFunction BindingData::fast_toggle_immediate_ref_(
|
||||
v8::CFunction::Make(FastToggleImmediateRef));
|
||||
|
||||
void BindingData::Initialize(Local<Object> target,
|
||||
Local<Value> unused,
|
||||
Local<Context> context,
|
||||
void* priv) {
|
||||
Realm* realm = Realm::GetCurrent(context);
|
||||
Environment* env = realm->env();
|
||||
BindingData* const binding_data =
|
||||
realm->AddBindingData<BindingData>(context, target);
|
||||
if (binding_data == nullptr) return;
|
||||
|
||||
SetMethod(context, target, "getLibuvNow", GetLibuvNow);
|
||||
SetMethod(context, target, "setupTimers", SetupTimers);
|
||||
SetMethod(context, target, "scheduleTimer", ScheduleTimer);
|
||||
SetMethod(context, target, "toggleTimerRef", ToggleTimerRef);
|
||||
SetMethod(context, target, "toggleImmediateRef", ToggleImmediateRef);
|
||||
SetFastMethod(
|
||||
context, target, "getLibuvNow", SlowGetLibuvNow, &fast_get_libuv_now_);
|
||||
SetFastMethod(context,
|
||||
target,
|
||||
"scheduleTimer",
|
||||
SlowScheduleTimer,
|
||||
&fast_schedule_timers_);
|
||||
SetFastMethod(context,
|
||||
target,
|
||||
"toggleTimerRef",
|
||||
SlowToggleTimerRef,
|
||||
&fast_toggle_timer_ref_);
|
||||
SetFastMethod(context,
|
||||
target,
|
||||
"toggleImmediateRef",
|
||||
SlowToggleImmediateRef,
|
||||
&fast_toggle_immediate_ref_);
|
||||
|
||||
// TODO(joyeecheung): move these into BindingData.
|
||||
target
|
||||
->Set(context,
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "immediateInfo"),
|
||||
FIXED_ONE_BYTE_STRING(realm->isolate(), "immediateInfo"),
|
||||
env->immediate_info()->fields().GetJSArray())
|
||||
.Check();
|
||||
|
||||
target
|
||||
->Set(context,
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "timeoutInfo"),
|
||||
FIXED_ONE_BYTE_STRING(realm->isolate(), "timeoutInfo"),
|
||||
env->timeout_info().GetJSArray())
|
||||
.Check();
|
||||
}
|
||||
} // anonymous namespace
|
||||
void RegisterTimerExternalReferences(ExternalReferenceRegistry* registry) {
|
||||
registry->Register(GetLibuvNow);
|
||||
|
||||
void BindingData::RegisterTimerExternalReferences(
|
||||
ExternalReferenceRegistry* registry) {
|
||||
registry->Register(SetupTimers);
|
||||
registry->Register(ScheduleTimer);
|
||||
registry->Register(ToggleTimerRef);
|
||||
registry->Register(ToggleImmediateRef);
|
||||
|
||||
registry->Register(SlowGetLibuvNow);
|
||||
registry->Register(FastGetLibuvNow);
|
||||
registry->Register(fast_get_libuv_now_.GetTypeInfo());
|
||||
|
||||
registry->Register(SlowScheduleTimer);
|
||||
registry->Register(FastScheduleTimer);
|
||||
registry->Register(fast_schedule_timers_.GetTypeInfo());
|
||||
|
||||
registry->Register(SlowToggleTimerRef);
|
||||
registry->Register(FastToggleTimerRef);
|
||||
registry->Register(fast_toggle_timer_ref_.GetTypeInfo());
|
||||
|
||||
registry->Register(SlowToggleImmediateRef);
|
||||
registry->Register(FastToggleImmediateRef);
|
||||
registry->Register(fast_toggle_immediate_ref_.GetTypeInfo());
|
||||
}
|
||||
|
||||
} // namespace timers
|
||||
|
||||
} // namespace node
|
||||
|
||||
NODE_BINDING_CONTEXT_AWARE_INTERNAL(timers, node::Initialize)
|
||||
NODE_BINDING_EXTERNAL_REFERENCE(timers, node::RegisterTimerExternalReferences)
|
||||
NODE_BINDING_CONTEXT_AWARE_INTERNAL(timers,
|
||||
node::timers::BindingData::Initialize)
|
||||
NODE_BINDING_EXTERNAL_REFERENCE(
|
||||
timers, node::timers::BindingData::RegisterTimerExternalReferences)
|
||||
|
68
src/timers.h
Normal file
68
src/timers.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef SRC_TIMERS_H_
|
||||
#define SRC_TIMERS_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include <cinttypes>
|
||||
#include "node_snapshotable.h"
|
||||
|
||||
namespace node {
|
||||
class ExternalReferenceRegistry;
|
||||
|
||||
namespace timers {
|
||||
class BindingData : public SnapshotableObject {
|
||||
public:
|
||||
BindingData(Realm* env, v8::Local<v8::Object> obj);
|
||||
|
||||
using InternalFieldInfo = InternalFieldInfoBase;
|
||||
|
||||
SET_BINDING_ID(timers_binding_data)
|
||||
SERIALIZABLE_OBJECT_METHODS()
|
||||
|
||||
SET_NO_MEMORY_INFO()
|
||||
SET_SELF_SIZE(BindingData)
|
||||
SET_MEMORY_INFO_NAME(BindingData)
|
||||
|
||||
static void SetupTimers(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
static void SlowGetLibuvNow(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static double FastGetLibuvNow(v8::Local<v8::Object> receiver);
|
||||
static double GetLibuvNowImpl(BindingData* data);
|
||||
|
||||
static void SlowScheduleTimer(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
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);
|
||||
static void FastToggleTimerRef(v8::Local<v8::Object> receiver, bool ref);
|
||||
static void ToggleTimerRefImpl(BindingData* data, bool ref);
|
||||
|
||||
static void SlowToggleImmediateRef(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void FastToggleImmediateRef(v8::Local<v8::Object> receiver, bool ref);
|
||||
static void ToggleImmediateRefImpl(BindingData* data, bool ref);
|
||||
|
||||
static void Initialize(v8::Local<v8::Object> target,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv);
|
||||
static void RegisterTimerExternalReferences(
|
||||
ExternalReferenceRegistry* registry);
|
||||
|
||||
private:
|
||||
static v8::CFunction fast_get_libuv_now_;
|
||||
static v8::CFunction fast_schedule_timers_;
|
||||
static v8::CFunction fast_toggle_timer_ref_;
|
||||
static v8::CFunction fast_toggle_immediate_ref_;
|
||||
};
|
||||
|
||||
} // namespace timers
|
||||
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_TIMERS_H_
|
@ -4,7 +4,8 @@
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const { internalBinding } = require('internal/test/binding');
|
||||
const { getLibuvNow } = internalBinding('timers');
|
||||
const binding = internalBinding('timers');
|
||||
|
||||
// Return value of getLibuvNow() should easily fit in a SMI after start-up.
|
||||
assert(getLibuvNow() < 0x3ffffff);
|
||||
// We need to use the binding as the receiver for fast API calls.
|
||||
assert(binding.getLibuvNow() < 0x3ffffff);
|
||||
|
@ -25,7 +25,7 @@
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const { internalBinding } = require('internal/test/binding');
|
||||
const { getLibuvNow } = internalBinding('timers');
|
||||
const binding = internalBinding('timers');
|
||||
|
||||
const N = 30;
|
||||
|
||||
@ -39,7 +39,8 @@ function f(i) {
|
||||
last_i = i;
|
||||
|
||||
// Check that this iteration is fired at least 1ms later than the previous
|
||||
const now = getLibuvNow();
|
||||
// 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`);
|
||||
last_ts = now;
|
||||
|
Loading…
Reference in New Issue
Block a user