Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
93 changes: 2 additions & 91 deletions lib/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const {
} = require('internal/validators');
const internal_async_hooks = require('internal/async_hooks');

const { AsyncLocalStorage } = internalBinding('async_local_storage');

// Get functions
// For userland AsyncResources, make sure to emit a destroy event when the
// resource gets gced.
Expand Down Expand Up @@ -262,97 +264,6 @@ class AsyncResource {
}
}

const storageList = [];
const storageHook = createHook({
init(asyncId, type, triggerAsyncId, resource) {
const currentResource = executionAsyncResource();
// Value of currentResource is always a non null object
for (let i = 0; i < storageList.length; ++i) {
storageList[i]._propagate(resource, currentResource);
}
}
});

class AsyncLocalStorage {
constructor() {
this.kResourceStore = Symbol('kResourceStore');
this.enabled = false;
}

disable() {
if (this.enabled) {
this.enabled = false;
// If this.enabled, the instance must be in storageList
ArrayPrototypeSplice(storageList,
ArrayPrototypeIndexOf(storageList, this), 1);
if (storageList.length === 0) {
storageHook.disable();
}
}
}

_enable() {
if (!this.enabled) {
this.enabled = true;
ArrayPrototypePush(storageList, this);
storageHook.enable();
}
}

// Propagate the context from a parent resource to a child one
_propagate(resource, triggerResource) {
const store = triggerResource[this.kResourceStore];
if (this.enabled) {
resource[this.kResourceStore] = store;
}
}

enterWith(store) {
this._enable();
const resource = executionAsyncResource();
resource[this.kResourceStore] = store;
}

run(store, callback, ...args) {
// Avoid creation of an AsyncResource if store is already active
if (ObjectIs(store, this.getStore())) {
return ReflectApply(callback, null, args);
}

this._enable();

const resource = executionAsyncResource();
const oldStore = resource[this.kResourceStore];

resource[this.kResourceStore] = store;

try {
return ReflectApply(callback, null, args);
} finally {
resource[this.kResourceStore] = oldStore;
}
}

exit(callback, ...args) {
if (!this.enabled) {
return ReflectApply(callback, null, args);
}
this.disable();
try {
return ReflectApply(callback, null, args);
} finally {
this._enable();
}
}

getStore() {
if (this.enabled) {
const resource = executionAsyncResource();
return resource[this.kResourceStore];
}
}
}

// Placing all exports down here because the exported classes won't export
// otherwise.
module.exports = {
Expand Down
4 changes: 4 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -469,10 +469,12 @@
'src/api/exceptions.cc',
'src/api/hooks.cc',
'src/api/utils.cc',
'src/async_local_storage.cc',
'src/async_wrap.cc',
'src/cares_wrap.cc',
'src/connect_wrap.cc',
'src/connection_wrap.cc',
'src/context_storage.cc',
'src/debug_utils.cc',
'src/env.cc',
'src/fs_event_wrap.cc',
Expand Down Expand Up @@ -564,6 +566,7 @@
'src/aliased_buffer.h',
'src/aliased_struct.h',
'src/aliased_struct-inl.h',
'src/async_local_storage.h',
'src/async_wrap.h',
'src/async_wrap-inl.h',
'src/base_object.h',
Expand All @@ -574,6 +577,7 @@
'src/callback_queue-inl.h',
'src/connect_wrap.h',
'src/connection_wrap.h',
'src/context_storage.h',
'src/debug_utils.h',
'src/debug_utils-inl.h',
'src/env.h',
Expand Down
4 changes: 3 additions & 1 deletion src/api/callback.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "node.h"
#include "async_local_storage.h"
#include "async_wrap-inl.h"
#include "env-inl.h"
#include "v8.h"
Expand Down Expand Up @@ -52,7 +53,8 @@ InternalCallbackScope::InternalCallbackScope(Environment* env,
async_context_(asyncContext),
object_(object),
skip_hooks_(flags & kSkipAsyncHooks),
skip_task_queues_(flags & kSkipTaskQueues) {
skip_task_queues_(flags & kSkipTaskQueues),
context_storage_scope_(AsyncLocalStorage::GetState(object)) {
CHECK_NOT_NULL(env);
env->PushAsyncCallbackScope();

Expand Down
Loading