mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
Changes in the native code for the upcoming async_hooks module. These have been separated to help with review and testing. Changes include: * Introduce an async id stack that tracks recursive calls into async execution contexts. For performance reasons the id stack is held as a double* and assigned to a Float64Array. If the stack grows too large it is then placed in it's own stack and replaced with a new double*. This should accommodate arbitrarily large stacks. I'm not especially happy with the complexity involved with this async id stack, but it's also the fastest and most full proof way of handling it that I have found. * Add helper functions in Environment and AsyncWrap to work with the async id stack. * Add AsyncWrap::Reset() to allow AsyncWrap instances that have been placed in a resource pool, instead of being released, to be reinitialized. AsyncWrap::AsyncWrap() also now uses Reset() for initialization. * AsyncWrap* parent no longer needs to be passed via the constructor. * Introduce Environment::AsyncHooks class to contain the needed native functionality. This includes the pointer to the async id stack, and array of v8::Eternal<v8::String>'s that hold the names of all providers, mechanisms for storing/retrieving the trigger id, etc. * Introduce Environment::AsyncHooks::ExecScope as a way to track the current id and trigger id of function execution via RAII. * If the user passes --abort-on-uncaught-exception then instead of throwing the application will print a stack trace and abort. PR-URL: https://github.com/nodejs/node/pull/12892 Ref: https://github.com/nodejs/node/pull/11883 Ref: https://github.com/nodejs/node/pull/8531 Reviewed-By: Andreas Madsen <amwebdk@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
232 lines
5.5 KiB
C++
232 lines
5.5 KiB
C++
#include "js_stream.h"
|
|
|
|
#include "async-wrap.h"
|
|
#include "env.h"
|
|
#include "env-inl.h"
|
|
#include "node_buffer.h"
|
|
#include "stream_base.h"
|
|
#include "stream_base-inl.h"
|
|
#include "v8.h"
|
|
|
|
namespace node {
|
|
|
|
using v8::Array;
|
|
using v8::Context;
|
|
using v8::FunctionCallbackInfo;
|
|
using v8::FunctionTemplate;
|
|
using v8::HandleScope;
|
|
using v8::Local;
|
|
using v8::Object;
|
|
using v8::Value;
|
|
|
|
|
|
JSStream::JSStream(Environment* env, Local<Object> obj)
|
|
: AsyncWrap(env, obj, AsyncWrap::PROVIDER_JSSTREAM),
|
|
StreamBase(env) {
|
|
node::Wrap(obj, this);
|
|
MakeWeak<JSStream>(this);
|
|
}
|
|
|
|
|
|
JSStream::~JSStream() {
|
|
}
|
|
|
|
|
|
void* JSStream::Cast() {
|
|
return static_cast<void*>(this);
|
|
}
|
|
|
|
|
|
AsyncWrap* JSStream::GetAsyncWrap() {
|
|
return static_cast<AsyncWrap*>(this);
|
|
}
|
|
|
|
|
|
bool JSStream::IsAlive() {
|
|
v8::Local<v8::Value> fn = object()->Get(env()->isalive_string());
|
|
if (!fn->IsFunction())
|
|
return false;
|
|
return MakeCallback(fn.As<v8::Function>(), 0, nullptr)->IsTrue();
|
|
}
|
|
|
|
|
|
bool JSStream::IsClosing() {
|
|
return MakeCallback(env()->isclosing_string(), 0, nullptr)->IsTrue();
|
|
}
|
|
|
|
|
|
int JSStream::ReadStart() {
|
|
return MakeCallback(env()->onreadstart_string(), 0, nullptr)->Int32Value();
|
|
}
|
|
|
|
|
|
int JSStream::ReadStop() {
|
|
return MakeCallback(env()->onreadstop_string(), 0, nullptr)->Int32Value();
|
|
}
|
|
|
|
|
|
int JSStream::DoShutdown(ShutdownWrap* req_wrap) {
|
|
HandleScope scope(env()->isolate());
|
|
|
|
Local<Value> argv[] = {
|
|
req_wrap->object()
|
|
};
|
|
|
|
req_wrap->Dispatched();
|
|
Local<Value> res =
|
|
MakeCallback(env()->onshutdown_string(), arraysize(argv), argv);
|
|
|
|
return res->Int32Value();
|
|
}
|
|
|
|
|
|
int JSStream::DoWrite(WriteWrap* w,
|
|
uv_buf_t* bufs,
|
|
size_t count,
|
|
uv_stream_t* send_handle) {
|
|
CHECK_EQ(send_handle, nullptr);
|
|
|
|
HandleScope scope(env()->isolate());
|
|
|
|
Local<Array> bufs_arr = Array::New(env()->isolate(), count);
|
|
Local<Object> buf;
|
|
for (size_t i = 0; i < count; i++) {
|
|
buf = Buffer::Copy(env(), bufs[i].base, bufs[i].len).ToLocalChecked();
|
|
bufs_arr->Set(i, buf);
|
|
}
|
|
|
|
Local<Value> argv[] = {
|
|
w->object(),
|
|
bufs_arr
|
|
};
|
|
|
|
w->Dispatched();
|
|
Local<Value> res =
|
|
MakeCallback(env()->onwrite_string(), arraysize(argv), argv);
|
|
|
|
return res->Int32Value();
|
|
}
|
|
|
|
|
|
void JSStream::New(const FunctionCallbackInfo<Value>& args) {
|
|
// This constructor should not be exposed to public javascript.
|
|
// Therefore we assert that we are not trying to call this as a
|
|
// normal function.
|
|
CHECK(args.IsConstructCall());
|
|
Environment* env = Environment::GetCurrent(args);
|
|
new JSStream(env, args.This());
|
|
}
|
|
|
|
|
|
static void FreeCallback(char* data, void* hint) {
|
|
// Intentional no-op
|
|
}
|
|
|
|
|
|
void JSStream::DoAlloc(const FunctionCallbackInfo<Value>& args) {
|
|
JSStream* wrap;
|
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
|
|
uv_buf_t buf;
|
|
wrap->OnAlloc(args[0]->Int32Value(), &buf);
|
|
Local<Object> vbuf = Buffer::New(
|
|
wrap->env(),
|
|
buf.base,
|
|
buf.len,
|
|
FreeCallback,
|
|
nullptr).ToLocalChecked();
|
|
return args.GetReturnValue().Set(vbuf);
|
|
}
|
|
|
|
|
|
void JSStream::DoRead(const FunctionCallbackInfo<Value>& args) {
|
|
JSStream* wrap;
|
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
|
|
CHECK(Buffer::HasInstance(args[1]));
|
|
uv_buf_t buf = uv_buf_init(Buffer::Data(args[1]), Buffer::Length(args[1]));
|
|
wrap->OnRead(args[0]->Int32Value(), &buf);
|
|
}
|
|
|
|
|
|
void JSStream::DoAfterWrite(const FunctionCallbackInfo<Value>& args) {
|
|
JSStream* wrap;
|
|
CHECK(args[0]->IsObject());
|
|
WriteWrap* w;
|
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
ASSIGN_OR_RETURN_UNWRAP(&w, args[0].As<Object>());
|
|
|
|
wrap->OnAfterWrite(w);
|
|
}
|
|
|
|
|
|
template <class Wrap>
|
|
void JSStream::Finish(const FunctionCallbackInfo<Value>& args) {
|
|
Wrap* w;
|
|
CHECK(args[0]->IsObject());
|
|
ASSIGN_OR_RETURN_UNWRAP(&w, args[0].As<Object>());
|
|
|
|
w->Done(args[1]->Int32Value());
|
|
}
|
|
|
|
|
|
void JSStream::ReadBuffer(const FunctionCallbackInfo<Value>& args) {
|
|
JSStream* wrap;
|
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
|
|
CHECK(Buffer::HasInstance(args[0]));
|
|
char* data = Buffer::Data(args[0]);
|
|
int len = Buffer::Length(args[0]);
|
|
|
|
do {
|
|
uv_buf_t buf;
|
|
ssize_t avail = len;
|
|
wrap->OnAlloc(len, &buf);
|
|
if (static_cast<ssize_t>(buf.len) < avail)
|
|
avail = buf.len;
|
|
|
|
memcpy(buf.base, data, avail);
|
|
data += avail;
|
|
len -= avail;
|
|
wrap->OnRead(avail, &buf);
|
|
} while (len != 0);
|
|
}
|
|
|
|
|
|
void JSStream::EmitEOF(const FunctionCallbackInfo<Value>& args) {
|
|
JSStream* wrap;
|
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
|
|
wrap->OnRead(UV_EOF, nullptr);
|
|
}
|
|
|
|
|
|
void JSStream::Initialize(Local<Object> target,
|
|
Local<Value> unused,
|
|
Local<Context> context) {
|
|
Environment* env = Environment::GetCurrent(context);
|
|
|
|
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
|
|
t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "JSStream"));
|
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
|
|
|
env->SetProtoMethod(t, "getAsyncId", AsyncWrap::GetAsyncId);
|
|
|
|
env->SetProtoMethod(t, "doAlloc", DoAlloc);
|
|
env->SetProtoMethod(t, "doRead", DoRead);
|
|
env->SetProtoMethod(t, "doAfterWrite", DoAfterWrite);
|
|
env->SetProtoMethod(t, "finishWrite", Finish<WriteWrap>);
|
|
env->SetProtoMethod(t, "finishShutdown", Finish<ShutdownWrap>);
|
|
env->SetProtoMethod(t, "readBuffer", ReadBuffer);
|
|
env->SetProtoMethod(t, "emitEOF", EmitEOF);
|
|
|
|
StreamBase::AddMethods<JSStream>(env, t, StreamBase::kFlagHasWritev);
|
|
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "JSStream"),
|
|
t->GetFunction());
|
|
env->set_jsstream_constructor_template(t);
|
|
}
|
|
|
|
} // namespace node
|
|
|
|
NODE_MODULE_CONTEXT_AWARE_BUILTIN(js_stream, node::JSStream::Initialize)
|