mirror of https://github.com/lukechilds/node.git
Browse Source
PR-URL: https://github.com/nodejs/node/pull/13142 Reviewed-By: Matthew Loring <mattloring@google.com> Reviewed-By: Andreas Madsen <amwebdk@gmail.com>v6
Anna Henningsen
8 years ago
3 changed files with 201 additions and 0 deletions
@ -0,0 +1,112 @@ |
|||
#include "node.h" |
|||
|
|||
#include <assert.h> |
|||
#include <vector> |
|||
|
|||
namespace { |
|||
|
|||
using node::AsyncResource; |
|||
using v8::External; |
|||
using v8::Function; |
|||
using v8::FunctionCallbackInfo; |
|||
using v8::Integer; |
|||
using v8::Isolate; |
|||
using v8::Local; |
|||
using v8::MaybeLocal; |
|||
using v8::Object; |
|||
using v8::String; |
|||
using v8::Value; |
|||
|
|||
void CreateAsyncResource(const FunctionCallbackInfo<Value>& args) { |
|||
Isolate* isolate = args.GetIsolate(); |
|||
assert(args[0]->IsObject()); |
|||
AsyncResource* r; |
|||
if (args[1]->IsInt32()) { |
|||
r = new AsyncResource(isolate, args[0].As<Object>(), "foobär", |
|||
args[1].As<Integer>()->Value()); |
|||
} else { |
|||
r = new AsyncResource(isolate, args[0].As<Object>(), "foobär"); |
|||
} |
|||
|
|||
args.GetReturnValue().Set( |
|||
External::New(isolate, static_cast<void*>(r))); |
|||
} |
|||
|
|||
void DestroyAsyncResource(const FunctionCallbackInfo<Value>& args) { |
|||
assert(args[0]->IsExternal()); |
|||
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value()); |
|||
delete r; |
|||
} |
|||
|
|||
void CallViaFunction(const FunctionCallbackInfo<Value>& args) { |
|||
Isolate* isolate = args.GetIsolate(); |
|||
assert(args[0]->IsExternal()); |
|||
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value()); |
|||
|
|||
Local<String> name = |
|||
String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal) |
|||
.ToLocalChecked(); |
|||
Local<Value> fn = |
|||
r->get_resource()->Get(isolate->GetCurrentContext(), name) |
|||
.ToLocalChecked(); |
|||
assert(fn->IsFunction()); |
|||
|
|||
Local<Value> arg = Integer::New(isolate, 42); |
|||
MaybeLocal<Value> ret = r->MakeCallback(fn.As<Function>(), 1, &arg); |
|||
args.GetReturnValue().Set(ret.FromMaybe(Local<Value>())); |
|||
} |
|||
|
|||
void CallViaString(const FunctionCallbackInfo<Value>& args) { |
|||
Isolate* isolate = args.GetIsolate(); |
|||
assert(args[0]->IsExternal()); |
|||
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value()); |
|||
|
|||
Local<String> name = |
|||
String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal) |
|||
.ToLocalChecked(); |
|||
|
|||
Local<Value> arg = Integer::New(isolate, 42); |
|||
MaybeLocal<Value> ret = r->MakeCallback(name, 1, &arg); |
|||
args.GetReturnValue().Set(ret.FromMaybe(Local<Value>())); |
|||
} |
|||
|
|||
void CallViaUtf8Name(const FunctionCallbackInfo<Value>& args) { |
|||
Isolate* isolate = args.GetIsolate(); |
|||
assert(args[0]->IsExternal()); |
|||
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value()); |
|||
|
|||
Local<Value> arg = Integer::New(isolate, 42); |
|||
MaybeLocal<Value> ret = r->MakeCallback("methöd", 1, &arg); |
|||
args.GetReturnValue().Set(ret.FromMaybe(Local<Value>())); |
|||
} |
|||
|
|||
void GetUid(const FunctionCallbackInfo<Value>& args) { |
|||
assert(args[0]->IsExternal()); |
|||
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value()); |
|||
args.GetReturnValue().Set(r->get_uid()); |
|||
} |
|||
|
|||
void GetResource(const FunctionCallbackInfo<Value>& args) { |
|||
assert(args[0]->IsExternal()); |
|||
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value()); |
|||
args.GetReturnValue().Set(r->get_resource()); |
|||
} |
|||
|
|||
void GetCurrentId(const FunctionCallbackInfo<Value>& args) { |
|||
args.GetReturnValue().Set(node::AsyncHooksGetCurrentId(args.GetIsolate())); |
|||
} |
|||
|
|||
void Initialize(Local<Object> exports) { |
|||
NODE_SET_METHOD(exports, "createAsyncResource", CreateAsyncResource); |
|||
NODE_SET_METHOD(exports, "destroyAsyncResource", DestroyAsyncResource); |
|||
NODE_SET_METHOD(exports, "callViaFunction", CallViaFunction); |
|||
NODE_SET_METHOD(exports, "callViaString", CallViaString); |
|||
NODE_SET_METHOD(exports, "callViaUtf8Name", CallViaUtf8Name); |
|||
NODE_SET_METHOD(exports, "getUid", GetUid); |
|||
NODE_SET_METHOD(exports, "getResource", GetResource); |
|||
NODE_SET_METHOD(exports, "getCurrentId", GetCurrentId); |
|||
} |
|||
|
|||
} // namespace
|
|||
|
|||
NODE_MODULE(binding, Initialize) |
@ -0,0 +1,9 @@ |
|||
{ |
|||
'targets': [ |
|||
{ |
|||
'target_name': 'binding', |
|||
'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], |
|||
'sources': [ 'binding.cc' ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,80 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const binding = require(`./build/${common.buildType}/binding`); |
|||
const async_hooks = require('async_hooks'); |
|||
|
|||
const kObjectTag = Symbol('kObjectTag'); |
|||
|
|||
const bindingUids = []; |
|||
let expectedTriggerId; |
|||
let before = 0; |
|||
let after = 0; |
|||
let destroy = 0; |
|||
|
|||
async_hooks.createHook({ |
|||
init(id, type, triggerId, resource) { |
|||
assert.strictEqual(typeof id, 'number'); |
|||
assert.strictEqual(typeof resource, 'object'); |
|||
assert(id > 1); |
|||
if (type === 'foobär') { |
|||
assert.strictEqual(resource.kObjectTag, kObjectTag); |
|||
assert.strictEqual(triggerId, expectedTriggerId); |
|||
bindingUids.push(id); |
|||
} |
|||
}, |
|||
|
|||
before(id) { |
|||
if (bindingUids.includes(id)) before++; |
|||
}, |
|||
|
|||
after(id) { |
|||
if (bindingUids.includes(id)) after++; |
|||
}, |
|||
|
|||
destroy(id) { |
|||
if (bindingUids.includes(id)) destroy++; |
|||
} |
|||
}).enable(); |
|||
|
|||
assert.strictEqual(binding.getCurrentId(), 1); |
|||
|
|||
for (const call of [binding.callViaFunction, |
|||
binding.callViaString, |
|||
binding.callViaUtf8Name]) { |
|||
for (const passedTriggerId of [undefined, 12345]) { |
|||
let uid; |
|||
const object = { |
|||
methöd(arg) { |
|||
assert.strictEqual(this, object); |
|||
assert.strictEqual(arg, 42); |
|||
assert.strictEqual(binding.getCurrentId(), uid); |
|||
return 'baz'; |
|||
}, |
|||
kObjectTag |
|||
}; |
|||
|
|||
if (passedTriggerId === undefined) |
|||
expectedTriggerId = 1; |
|||
else |
|||
expectedTriggerId = passedTriggerId; |
|||
|
|||
const resource = binding.createAsyncResource(object, passedTriggerId); |
|||
uid = bindingUids[bindingUids.length - 1]; |
|||
|
|||
const ret = call(resource); |
|||
assert.strictEqual(ret, 'baz'); |
|||
assert.strictEqual(binding.getResource(resource), object); |
|||
assert.strictEqual(binding.getUid(resource), uid); |
|||
|
|||
binding.destroyAsyncResource(resource); |
|||
} |
|||
} |
|||
|
|||
setImmediate(common.mustCall(() => { |
|||
assert.strictEqual(bindingUids.length, 6); |
|||
assert.strictEqual(before, bindingUids.length); |
|||
assert.strictEqual(after, bindingUids.length); |
|||
assert.strictEqual(destroy, bindingUids.length); |
|||
})); |
Loading…
Reference in new issue