Skip to content

Commit

Permalink
adding support to test nextTick() by reading int values from a javasc…
Browse files Browse the repository at this point in the history
…ript array, as opposed to returning a new v8::Integer each time
  • Loading branch information
trevnorris authored and Mike Kaufman committed Apr 13, 2016
1 parent 7f2d1b3 commit 6086ed7
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 24 deletions.
47 changes: 47 additions & 0 deletions lib/internal/async_wrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

const async_wrap = process.binding('async_wrap');

const nextIdArray = async_wrap.getNextAsyncId2();
const currentIdArray = async_wrap.getCurrentAsyncId2();

function getLittleEndian(a) {
if (a[0] === 0xffffffff) {
a[0] = 0;
a[1]++;
}
return a[0] + a[1] * 0x100000000;
}

function getBigEndian(a) {
if (a[1] === 0xffffffff) {
a[1] = 0;
a[0]++;
}
return a[1] + a[0] * 0x100000000;
}

function getCurrentIdLittleEndian() {
return getLittleEndian(currentIdArray);
}

function getCurrentIdBigEndian() {
return getBigEndian(currentIdArray);
}

function getNextIdLittleEndian() {
return getLittleEndian(nextIdArray);
}

function getNextIdBigEndian() {
return getBigEndian(nextIdArray);
}

module.exports.getCurrentAsyncWrapId = async_wrap.getCurrentAsyncId;
module.exports.getNextAsyncWrapId = async_wrap.getNextAsyncId;

module.exports.getCurrentAsyncWrapId2 =
process.binding('os').isBigEndian ? getCurrentIdBigEndian : getCurrentIdLittleEndian;

module.exports.getNextAsyncWrapId2 =
process.binding('os').isBigEndian ? getNextIdBigEndian : getNextIdLittleEndian;
37 changes: 35 additions & 2 deletions lib/internal/process/next_tick.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ exports.setup = setupNextTick;
function setupNextTick() {

var asyncWrap = process.binding('async_wrap');
const async_wrap = require('internal/async_wrap');

const promises = require('internal/process/promises');
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
var nextTickQueue = [];
Expand All @@ -18,6 +20,7 @@ function setupNextTick() {
var kLength = 1;

process.nextTick = nextTick;
process.nextTickTemp = nextTickTemp;
// Needs to be accessible from beyond this scope.
process._tickCallback = _tickCallback;
process._tickDomainCallback = _tickDomainCallback;
Expand Down Expand Up @@ -152,14 +155,26 @@ function setupNextTick() {
this.callback = c;
this.domain = process.domain || null;
this.args = args;
this.parentAsyncId = asyncWrap.getCurrentAsyncId();
this.asyncId = asyncWrap.getNextAsyncId();
this.parentAsyncId = async_wrap.getCurrentAsyncWrapId();
this.asyncId = async_wrap.getNextAsyncWrapId();
this.asyncState = {};
this.ranInitCallback = asyncWrap.notifyAsyncEnqueue(
this.asyncId, this.asyncState, undefined, undefined,
asyncWrap.Providers.NEXTTICK);
}

function TickObjectTemp(c, args) {
this.callback = c;
this.domain = process.domain || null;
this.args = args;
this.parentAsyncId = async_wrap.getCurrentAsyncWrapId2();
this.asyncId = async_wrap.getNextAsyncWrapId2();
this.asyncState = {};
this.ranInitCallback = asyncWrap.notifyAsyncEnqueue(
this.asyncId, this.asyncState, undefined, undefined,
asyncWrap.Providers.NEXTTICK);
}

function nextTick(callback) {
if (typeof callback !== 'function')
throw new TypeError('callback is not a function');
Expand All @@ -177,4 +192,22 @@ function setupNextTick() {
nextTickQueue.push(new TickObject(callback, args));
tickInfo[kLength]++;
}

function nextTickTemp(callback) {
if (typeof callback !== 'function')
throw new TypeError('callback is not a function');
// on the way out, don't bother. it won't get fired anyway.
if (process._exiting)
return;

var args;
if (arguments.length > 1) {
args = new Array(arguments.length - 1);
for (var i = 1; i < arguments.length; i++)
args[i - 1] = arguments[i];
}

nextTickQueue.push(new TickObjectTemp(callback, args));
tickInfo[kLength]++;
}
}
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
'lib/v8.js',
'lib/vm.js',
'lib/zlib.js',
'lib/internal/async_wrap.js',
'lib/internal/child_process.js',
'lib/internal/cluster.js',
'lib/internal/freelist.js',
Expand Down
2 changes: 1 addition & 1 deletion src/async-wrap-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ inline AsyncWrap::AsyncWrap(Environment* env,
ProviderType provider,
AsyncWrap* parent)
: BaseObject(env, object), bits_(static_cast<uint32_t>(provider) << 1),
uid_(env->get_next_async_wrap_uid()) {
uid_(env->async_hooks()->get_next_async_wrap_uid()) {
CHECK_NE(provider, PROVIDER_NONE);
CHECK_GE(object->InternalFieldCount(), 1);

Expand Down
25 changes: 18 additions & 7 deletions src/async-wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,26 @@ static void DisableHooksJS(const FunctionCallbackInfo<Value>& args) {

static void GetCurrentAsyncId(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
v8::Local<v8::Value> uid = v8::Integer::New(env->isolate(), env->get_current_async_wrap_uid());
v8::Local<v8::Value> uid = v8::Integer::New(env->isolate(), env->async_hooks()->get_current_async_wrap_uid());
args.GetReturnValue().Set(uid);
}

static void GetNextAsyncId(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
v8::Local<v8::Integer> uid = v8::Integer::New(env->isolate(), env->get_next_async_wrap_uid());
v8::Local<v8::Integer> uid = v8::Integer::New(env->isolate(), env->async_hooks()->get_next_async_wrap_uid());
args.GetReturnValue().Set(uid);
}

static void GetCurrentAsyncId2(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
args.GetReturnValue().Set(env->async_hooks()->get_current_async_id_array());
}

static void GetNextAsyncId2(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
args.GetReturnValue().Set(env->async_hooks()->get_next_async_id_array());
}

static bool FireAsyncInitCallbacksInternal(
Environment* env,
int64_t uid,
Expand Down Expand Up @@ -243,7 +253,7 @@ void AsyncWrap::FireAsyncPreCallbacks(
v8::Local<v8::Number> uid,
v8::Local<v8::Object> obj)
{
env->set_current_async_wrap_uid(uid->IntegerValue());
env->async_hooks()->set_current_async_wrap_uid(uid->IntegerValue());

if (ranInitCallbacks) {
Local<Function> pre_fn = env->async_hooks_pre_function();
Expand Down Expand Up @@ -283,7 +293,7 @@ void AsyncWrap::FireAsyncPostCallbacks(Environment* env, bool ranInitCallback, v
}
}

env->set_current_async_wrap_uid(0);
env->async_hooks()->set_current_async_wrap_uid(0);
}

static void NotifyAsyncEndFromJS(const FunctionCallbackInfo<Value>& args) {
Expand Down Expand Up @@ -351,10 +361,9 @@ static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
env->set_async_hooks_destroy_function(destroy_v.As<Function>());
}


static void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
Local<Value> unused,
Local<Context> context) {
Environment* env = Environment::GetCurrent(context);
Isolate* isolate = env->isolate();
HandleScope scope(isolate);
Expand All @@ -364,6 +373,8 @@ static void Initialize(Local<Object> target,
env->SetMethod(target, "enable", EnableHooksJS);
env->SetMethod(target, "getCurrentAsyncId", GetCurrentAsyncId);
env->SetMethod(target, "getNextAsyncId", GetNextAsyncId);
env->SetMethod(target, "getCurrentAsyncId2", GetCurrentAsyncId2);
env->SetMethod(target, "getNextAsyncId2", GetNextAsyncId2);
env->SetMethod(target, "notifyAsyncEnqueue", NotifyAsyncEnqueueFromJS);
env->SetMethod(target, "notifyAsyncStart", NotifyAsyncStartFromJS);
env->SetMethod(target, "notifyAsyncEnd", NotifyAsyncEndFromJS);
Expand Down
48 changes: 41 additions & 7 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,34 @@ inline v8::Isolate* Environment::IsolateData::isolate() const {
return isolate_;
}

inline Environment::AsyncHooks::AsyncHooks() {
for (int i = 0; i < kFieldsCount; i++) fields_[i] = 0;
inline Environment::AsyncHooks::AsyncHooks(Environment* env)
: async_wrap_current_uid_(0),
async_wrap_counter_uid_(0),
env_(env) {

for (int i = 0; i < kFieldsCount; i++) {
fields_[i] = 0;
}

v8::HandleScope handle_scope(env_->isolate());

// set up int array for returing async_wrap_counter_uid_ value
const size_t array_length = sizeof(async_wrap_counter_uid_) / sizeof(int32_t);
static_assert(array_length == 2, "async_wrap_counter_uid_ unexpected size");
v8::Local<v8::ArrayBuffer> ab =
v8::ArrayBuffer::New(this->env_->isolate(), &async_wrap_counter_uid_, array_length);
v8::Local<v8::Uint32Array> ua =
v8::Uint32Array::New(ab, 0, array_length);
this->async_wrap_next_id_array_.Reset(this->env_->isolate(), ua);

// set up int array for returing async_wrap_current_uid_ value
const size_t array_length2 = sizeof(async_wrap_current_uid_) / sizeof(int32_t);
v8::Local<v8::ArrayBuffer> ab2 =
v8::ArrayBuffer::New(this->env_->isolate(), &async_wrap_current_uid_, array_length);
v8::Local<v8::Uint32Array> ua2 =
v8::Uint32Array::New(ab2, 0, array_length);
this->async_wrap_current_id_array_.Reset(this->env_->isolate(), ua2);

}

inline uint32_t* Environment::AsyncHooks::fields() {
Expand Down Expand Up @@ -216,13 +242,12 @@ inline Environment::Environment(v8::Local<v8::Context> context,
uv_loop_t* loop)
: isolate_(context->GetIsolate()),
isolate_data_(IsolateData::GetOrCreate(context->GetIsolate(), loop)),
async_hooks_(this),
timer_base_(uv_now(loop)),
using_domains_(false),
printed_error_(false),
trace_sync_io_(false),
makecallback_cntr_(0),
async_wrap_counter_uid_(0),
async_wrap_current_uid_(0),
debugger_agent_(this),
http_parser_buffer_(nullptr),
context_(context->GetIsolate(), context) {
Expand Down Expand Up @@ -373,15 +398,24 @@ inline void Environment::set_trace_sync_io(bool value) {
trace_sync_io_ = value;
}

inline int64_t Environment::get_next_async_wrap_uid() {
inline int64_t Environment::AsyncHooks::get_next_async_wrap_uid() {
return ++async_wrap_counter_uid_;
}

inline int64_t Environment::get_current_async_wrap_uid() {
inline int64_t Environment::AsyncHooks::get_current_async_wrap_uid() {
return this->async_wrap_current_uid_;
}

inline void Environment::set_current_async_wrap_uid(int64_t value) {
inline v8::Local<v8::Uint32Array> Environment::AsyncHooks::get_current_async_id_array() {
return async_wrap_current_id_array_.Get(this->env_->isolate());
}

inline v8::Local<v8::Uint32Array> Environment::AsyncHooks::get_next_async_id_array() {
return async_wrap_next_id_array_.Get(this->env_->isolate());
}


inline void Environment::AsyncHooks::set_current_async_wrap_uid(int64_t value) {
this->async_wrap_current_uid_ = value;
}

Expand Down
20 changes: 13 additions & 7 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,20 @@ class Environment {
inline int fields_count() const;
inline bool callbacks_enabled();
inline void set_enable_callbacks(uint32_t flag);
inline int64_t get_next_async_wrap_uid();
inline int64_t get_current_async_wrap_uid();
inline void set_current_async_wrap_uid(int64_t value);
inline v8::Local<v8::Uint32Array> get_current_async_id_array();
inline v8::Local<v8::Uint32Array> get_next_async_id_array();

private:
friend class Environment; // So we can call the constructor.
inline AsyncHooks();
inline AsyncHooks(Environment* env);

int64_t async_wrap_counter_uid_;
int64_t async_wrap_current_uid_;
v8::Persistent<v8::Uint32Array> async_wrap_current_id_array_;
v8::Persistent<v8::Uint32Array> async_wrap_next_id_array_;

enum Fields {
// Set this to not zero if the init hook should be called.
Expand All @@ -312,6 +322,7 @@ class Environment {
};

uint32_t fields_[kFieldsCount];
Environment* env_;

DISALLOW_COPY_AND_ASSIGN(AsyncHooks);
};
Expand Down Expand Up @@ -473,10 +484,6 @@ class Environment {
void PrintSyncTrace() const;
inline void set_trace_sync_io(bool value);

inline int64_t get_next_async_wrap_uid();
inline int64_t get_current_async_wrap_uid();
inline void set_current_async_wrap_uid(int64_t value);

inline uint32_t* heap_statistics_buffer() const;
inline void set_heap_statistics_buffer(uint32_t* pointer);

Expand Down Expand Up @@ -579,8 +586,7 @@ class Environment {
bool printed_error_;
bool trace_sync_io_;
size_t makecallback_cntr_;
int64_t async_wrap_counter_uid_;
int64_t async_wrap_current_uid_;

debugger::Agent debugger_agent_;

HandleWrapQueue handle_wrap_queue_;
Expand Down

0 comments on commit 6086ed7

Please sign in to comment.