Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5d75ba4
test: remove async_wrap tests
trevnorris Oct 31, 2016
53a85f1
stream_base,tls_wrap: notify on destruct
trevnorris Oct 31, 2016
757ac35
crypto: use named FunctionTemplate
trevnorris Sep 28, 2016
29e9d09
async_wrap: use more specific providers
trevnorris Nov 2, 2016
82d8606
async_wrap: use double, not int64_t, for uid
trevnorris Dec 13, 2016
4a427e3
async_wrap: add GetAsyncId() method
trevnorris Nov 2, 2016
f5d6056
src: add AsyncWrap::GetAsyncId() to all children
trevnorris Sep 28, 2016
1c9154c
async_wrap: only call SetupHooks() once
trevnorris Nov 2, 2016
4c809dd
async_hooks: introduce async_hooks.js
trevnorris Nov 2, 2016
3611f6a
async_hooks: check correct array
trevnorris Nov 17, 2016
d244d55
next_tick: add async_hooks support
trevnorris Nov 14, 2016
977718e
timers: initial timers support
trevnorris Nov 16, 2016
3e5ef64
fs: add initial async_hooks support
trevnorris Nov 17, 2016
955d390
net: add initial async_hooks net support
trevnorris Nov 16, 2016
da7c67c
lib: add triggerId support to various modules
trevnorris Nov 17, 2016
b3721ba
http: reset Agents on free pool
trevnorris Nov 17, 2016
78a2a7f
src: properly propagate triggerId in more places
trevnorris Nov 17, 2016
eab9e86
timers: manually set ids if no hooks exist
trevnorris Nov 18, 2016
4399547
fs: add AsyncReset to TSLWrap
trevnorris Nov 22, 2016
830428a
async_hooks: allow enable/disable while processing
trevnorris Dec 15, 2016
ad382c5
async_hooks: run after() in case of exception
trevnorris Dec 20, 2016
6e5af4a
streams: set initTriggerId before nextTick()
trevnorris Dec 20, 2016
32b5288
next_tick: set MicrotaskCallback to the void
trevnorris Dec 20, 2016
bd660a4
test: allow running with async_hook noops
trevnorris Dec 20, 2016
e8c27f8
async_hooks: move location of restoreTmpHooks()
trevnorris Dec 22, 2016
0ab9547
async_wrap: use v8::Eternal for provider strings
trevnorris Dec 27, 2016
352c89a
fs: use preallocated Float64Array
trevnorris Dec 29, 2016
e9ae576
PARTIAL remove all applicable TODOs
trevnorris Jan 3, 2017
015e665
async_hooks: verify stack integrity
trevnorris Jan 11, 2017
e2af82f
async_hooks: place destroy ids on native list
trevnorris Jan 17, 2017
1b7438f
test: add more async hook tests
trevnorris Jan 17, 2017
ca8d6db
timers: don't reset _asyncId/_triggerId
trevnorris Jan 17, 2017
ac2e137
async_hooks: return early if emitting the void
trevnorris Jan 17, 2017
da138cf
async_hooks: really always exit on exception
trevnorris Jan 18, 2017
25dd8af
async_wrap: don't allow exports to be overwritten
trevnorris Jan 18, 2017
2d98170
fix bug in array buffer size in fs
trevnorris Jan 20, 2017
7bc7d3c
PARTIAL implement new stack tracker
trevnorris Jan 20, 2017
edf67a7
timers: don't emit destroy() on same id twice
trevnorris Jan 26, 2017
90f0a63
test: make async hooks test better
trevnorris Jan 26, 2017
1ff2dfb
async_wrap: print msg on error instead of abort
trevnorris Feb 1, 2017
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
Prev Previous commit
Next Next commit
next_tick: add async_hooks support
Also did:
* Turn TickObject() into a function
* Split the function in half so it can be inlined
* Fix how uid flags are set
* Export kScopedTriggerId for use in setupInit()
  • Loading branch information
trevnorris committed Jan 27, 2017
commit d244d55d53e75e3a83db354ce96e0f893c06155a
2 changes: 1 addition & 1 deletion lib/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const destroy_symbol = Symbol('destroy');
// The exception is kActiveHooks. Which tracks the total number of AsyncEvents
// that exist on "active_hooks_array".
const { kInit, kBefore, kAfter, kDestroy, kActiveHooks, kAsyncUidCntr,
kCurrentId, kTriggerId, kScopedTriggerId, kInitTriggerId } =
kCurrentId, kTriggerId, kInitTriggerId, kScopedTriggerId } =
async_wrap.constants;

// Setup the callbacks that node::AsyncWrap will call when there are hooks to
Expand Down
94 changes: 85 additions & 9 deletions lib/internal/process/next_tick.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
exports.setup = setupNextTick;

function setupNextTick() {
const async_wrap = process.binding('async_wrap');
const async_hooks = require('async_hooks');
const promises = require('internal/process/promises');
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
const initTriggerId = async_hooks.initTriggerId;
// Two arrays that share state between C++ and JS.
const { async_uid_fields, async_hook_fields } = async_wrap;
// Grab the constants necessary for working with internal arrays.
const { kInit, kBefore, kAfter, kDestroy, kActiveHooks, kAsyncUidCntr,
kCurrentId, kTriggerId } = async_wrap.constants;
var nextTickQueue = [];
var microtasksScheduled = false;

Expand Down Expand Up @@ -44,10 +52,8 @@ function setupNextTick() {
if (microtasksScheduled)
return;

nextTickQueue.push({
callback: runMicrotasksCallback,
domain: null
});
nextTickQueue.push(
new TickObject(runMicrotasksCallback, undefined, null, true));

tickInfo[kLength]++;
microtasksScheduled = true;
Expand Down Expand Up @@ -89,13 +95,40 @@ function setupNextTick() {

do {
while (tickInfo[kIndex] < tickInfo[kLength]) {
const has_hooks = async_hook_fields[kActiveHooks] > 0;
// TODO(trevnorris): These should always be zero if at the bottom of
// the stack. Add check somewhere cheaper than here to make sure that's
// the case.
const prev_id = async_uid_fields[kCurrentId];
const prev_trigger_id = async_uid_fields[kTriggerId];

tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
args = tock.args;

// Setting these fields manually with the expectation that has_hooks
// will almost always be false. Overhead for doing it twice if it is
// true is negligible anyway.
async_uid_fields[kCurrentId] = tock._asyncId;
async_uid_fields[kTriggerId] = tock._triggerId;
if (has_hooks && async_hook_fields[kBefore])
async_hooks.emitBefore(tock._asyncId, tock._triggerId);

// Using separate callback execution functions allows direct
// callback invocation with small numbers of arguments to avoid the
// performance hit associated with using `fn.apply()`
_combinedTickCallback(args, callback);

if (has_hooks) {
if (async_hook_fields[kAfter])
async_hooks.emitAfter(tock._asyncId);
if (async_hook_fields[kDestroy])
async_hooks.emitDestroy(tock._asyncId);
}
// TODO(trevnorris): A caught uncaught exception will mess this up.
async_uid_fields[kCurrentId] = prev_id;
async_uid_fields[kTriggerId] = prev_trigger_id;

if (1e4 < tickInfo[kIndex])
tickDone();
}
Expand All @@ -110,16 +143,42 @@ function setupNextTick() {

do {
while (tickInfo[kIndex] < tickInfo[kLength]) {
const has_hooks = async_hook_fields[kActiveHooks] > 0;
// TODO(trevnorris): These should always be zero if at the bottom of
// the stack. Add check somewhere cheaper than here to make sure that's
// the case.
const prev_id = async_uid_fields[kCurrentId];
const prev_trigger_id = async_uid_fields[kTriggerId];

tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
domain = tock.domain;
args = tock.args;
if (domain)
domain.enter();

// Setting these fields manually with the expectation that has_hooks
// will almost always be false. Overhead for doing it twice if it is
// true is negligible anyway.
async_uid_fields[kCurrentId] = tock._asyncId;
async_uid_fields[kTriggerId] = tock._triggerId;
if (has_hooks && async_hook_fields[kBefore])
async_hooks.emitBefore(tock._asyncId, tock._triggerId);

// Using separate callback execution functions allows direct
// callback invocation with small numbers of arguments to avoid the
// performance hit associated with using `fn.apply()`
_combinedTickCallback(args, callback);

if (has_hooks) {
if (async_hook_fields[kAfter])
async_hooks.emitAfter(tock._asyncId);
if (async_hook_fields[kDestroy])
async_hooks.emitDestroy(tock._asyncId);
}
async_uid_fields[kCurrentId] = prev_id;
async_uid_fields[kTriggerId] = prev_trigger_id;

if (1e4 < tickInfo[kIndex])
tickDone();
if (domain)
Expand All @@ -131,6 +190,26 @@ function setupNextTick() {
} while (tickInfo[kLength] !== 0);
}

function TickObject(callback, args, domain, isMicrotask) {
this.callback = callback;
this.domain = domain;
this.args = args;
this._asyncId = -1;
this._triggerId = -1;
if (!isMicrotask)
setupInit(this);
}

// This function is for performance reasons. If the code here is placed
// directly in TickObject it would be over the maximum character count
// to be inlined, and it would suffer a penalty lose.
function setupInit(self) {
self._asyncId = ++async_uid_fields[kAsyncUidCntr];
self._triggerId = initTriggerId();
if (async_hook_fields[kInit] > 0)
async_hooks.emitInit(self._asyncId, 'TickObject', self._triggerId, self);
}

function nextTick(callback) {
if (typeof callback !== 'function')
throw new TypeError('callback is not a function');
Expand All @@ -145,11 +224,8 @@ function setupNextTick() {
args[i - 1] = arguments[i];
}

nextTickQueue.push({
callback,
domain: process.domain || null,
args
});
nextTickQueue.push(
new TickObject(callback, args, process.domain || null, false));
tickInfo[kLength]++;
}
}