Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async-wrap: always call before and after hooks #665

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/async-wrap-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ inline AsyncWrap::AsyncWrap(Environment* env,
: BaseObject(env, object),
has_async_queue_(false),
provider_type_(provider) {
// Check user controlled flag to see if the init callback should run.
if (!env->call_async_init_hook())
// Check user controlled flag to see if the async hooks should be called.
if (!env->use_async_hook())
return;

// TODO(trevnorris): Until it's verified all passed object's are not weak,
Expand All @@ -42,11 +42,13 @@ inline AsyncWrap::AsyncWrap(Environment* env,
FatalError("node::AsyncWrap::AsyncWrap", "parent pre hook threw");
}

env->async_hooks_init_function()->Call(object, 0, nullptr);

if (try_catch.HasCaught())
FatalError("node::AsyncWrap::AsyncWrap", "init hook threw");
// Check user controlled flag to see if the init callback should run.
if (env->call_async_init_hook()) {
env->async_hooks_init_function()->Call(object, 0, nullptr);

if (try_catch.HasCaught())
FatalError("node::AsyncWrap::AsyncWrap", "init hook threw");
}
has_async_queue_ = true;

if (parent != nullptr) {
Expand Down
2 changes: 2 additions & 0 deletions src/async-wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
kExternalUint32Array,
async_hooks->fields_count());

async_hooks->enabled = true;

env->set_async_hooks_init_function(args[1].As<Function>());
env->set_async_hooks_pre_function(args[2].As<Function>());
env->set_async_hooks_post_function(args[3].As<Function>());
Expand Down
6 changes: 6 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ inline v8::Isolate* Environment::IsolateData::isolate() const {
}

inline Environment::AsyncHooks::AsyncHooks() {
enabled = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize with : enabled_(false).

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

Expand Down Expand Up @@ -214,6 +215,11 @@ inline v8::Isolate* Environment::isolate() const {
return isolate_;
}

inline bool Environment::use_async_hook() const {
// The const_cast is okay, it doesn't violate conceptual const-ness.
return const_cast<Environment*>(this)->async_hooks()->enabled;
}

inline bool Environment::call_async_init_hook() const {
// The const_cast is okay, it doesn't violate conceptual const-ness.
return const_cast<Environment*>(this)->async_hooks()->call_init_hook();
Expand Down
2 changes: 2 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class Environment {
inline uint32_t* fields();
inline int fields_count() const;
inline bool call_init_hook();
bool enabled;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: at the very least, rename it to enabled_, make it private and only accessible through a getter and setter. The getter should be const.

That said, I believe AsyncHooks is exposed to JS land. In that case, enabled should be a new element in the fields_ array.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have exposed it though the fields_ array as you sugested. Is this something there should be tested? It looks like async-wrap have a different testing policy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I brought it up mostly because it looked incongruous. I'll defer to @trevnorris here.


private:
friend class Environment; // So we can call the constructor.
Expand Down Expand Up @@ -358,6 +359,7 @@ class Environment {

inline v8::Isolate* isolate() const;
inline uv_loop_t* event_loop() const;
inline bool use_async_hook() const;
inline bool call_async_init_hook() const;
inline bool in_domain() const;
inline uint32_t watched_providers() const;
Expand Down
33 changes: 33 additions & 0 deletions test/parallel/test-async-wrap-init-hook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
var common = require('../common');
var assert = require('assert');

var asyncWrap = process.binding('async_wrap');

var asyncHooksObject = {};
var kCallInitHook = 0;
asyncWrap.setupHooks(asyncHooksObject, init, before, after);
asyncHooksObject[kCallInitHook] = 1;

var order = [];

function init() {
order.push('init ' + this.constructor.name);
}

function before() {
order.push('before ' + this.constructor.name);
}

function after() {
order.push('after ' + this.constructor.name);
}

setTimeout(function () {
order.push('callback');
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for a future note, this may be spotty because there's incomplete timer support. Because only a single TimerWrap is instantiated for many timers. Still need to implement the JS side for proper full support.


process.once('exit', function () {
assert.deepEqual(order, [
'init Timer', 'before Timer', 'callback', 'after Timer'
]);
});
31 changes: 31 additions & 0 deletions test/parallel/test-async-wrap-no-init-hook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
var common = require('../common');
var assert = require('assert');

var asyncWrap = process.binding('async_wrap');

var asyncHooksObject = {};
asyncWrap.setupHooks(asyncHooksObject, init, before, after);

var order = [];

function init() {
order.push('init ' + this.constructor.name);
}

function before() {
order.push('before ' + this.constructor.name);
}

function after() {
order.push('after ' + this.constructor.name);
}

setTimeout(function () {
order.push('callback');
});

process.once('exit', function () {
assert.deepEqual(order, [
'before Timer', 'callback', 'after Timer'
]);
});