Skip to content
This repository has been archived by the owner on Oct 15, 2020. It is now read-only.

Commit

Permalink
napi: Fix jsrt implementation of napi_create_async_work
Browse files Browse the repository at this point in the history
napi_create_async_work has had a few changes. Implemented the following:
- Updated to the new signature
- Fixed support for async hooks
  • Loading branch information
digitalinfinity authored and MSLaguana committed Sep 27, 2017
1 parent fb77947 commit 1daa223
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 4 deletions.
8 changes: 8 additions & 0 deletions deps/chakrashim/include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@
*(static_cast<T* volatile*>(0)) = static_cast<S*>(0); \
}

// Used to allow n-api constructs access to shim internals
// This is a temporary workaround and should go away once
// node-core has less of a dependency on the shim
namespace uvimpl {
class Work;
};

namespace v8 {

class AccessorSignature;
Expand Down Expand Up @@ -329,6 +336,7 @@ class Local {
friend class UnboundScript;
friend class Value;
friend class JSON;
friend class uvimpl::Work;
template <class F> friend class FunctionCallbackInfo;
template <class F> friend class MaybeLocal;
template <class F> friend class PersistentBase;
Expand Down
84 changes: 80 additions & 4 deletions src/node_api_jsrt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@

#include "src/jsrtutils.h"

// Forward declare a dependency on an internal node helper
// This is so that we don't take an additional dependency on
// the chakrashim (v8::trycatch) and so that node doesn't
// have to expose another public API
namespace node {
extern void FatalException(v8::Isolate* isolate,
v8::Local<v8::Value> error,
v8::Local<v8::Message> message);
}

#ifndef CALLBACK
#define CALLBACK
#endif
Expand Down Expand Up @@ -2570,13 +2580,16 @@ napi_status ConvertUVErrorCode(int code) {
}

// Wrapper around uv_work_t which calls user-provided callbacks.
class Work {
class Work: public node::AsyncResource {
private:
explicit Work(napi_env env,
v8::Local<v8::Object> async_resource,
v8::Local<v8::String> async_resource_name,
napi_async_execute_callback execute = nullptr,
napi_async_complete_callback complete = nullptr,
void* data = nullptr)
: _env(env),
: AsyncResource(env->isolate, async_resource, async_resource_name),
_env(env),
_data(data),
_execute(execute),
_complete(complete) {
Expand All @@ -2588,10 +2601,18 @@ class Work {

public:
static Work* New(napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_execute_callback execute,
napi_async_complete_callback complete,
void* data) {
return new Work(env, execute, complete, data);
v8::Local<v8::Object> async_resource_local =
v8impl::V8LocalValueFromJsValue(async_resource).As<v8::Object>();
v8::Local<v8::String> async_resource_name_local =
v8impl::V8LocalValueFromJsValue(async_resource_name).As<v8::String>();

return new Work(env, async_resource_local, async_resource_name_local,
execute, complete, data);
}

static void Delete(Work* work) {
Expand All @@ -2603,11 +2624,54 @@ class Work {
work->_execute(work->_env, work->_data);
}

static void Fatal() {
napi_fatal_error(nullptr, "[napi] CompleteCallback failed "
"but exception could not be propagated");
}

static void CompleteCallback(uv_work_t* req, int status) {
Work* work = static_cast<Work*>(req->data);

if (work->_complete != nullptr) {
CallbackScope callback_scope(work);

work->_complete(work->_env, ConvertUVErrorCode(status), work->_data);

bool hasException;
JsErrorCode errorCode = JsHasException(&hasException);
if (errorCode != JsNoError || !hasException) {
return;
}

JsValueRef metadata;
if (JsGetAndClearExceptionWithMetadata(&metadata) != JsNoError) {
Fatal();
return;
}

JsValueRef exception;
JsPropertyIdRef exProp;

if (JsCreatePropertyId("exception", -1, &exProp) != JsNoError) {
Fatal();
return;
}

if (JsGetProperty(metadata, exProp, &exception) != JsNoError) {
Fatal();
return;
}

// TODO(digitalinfinity):
// Taking a dependency on v8::Local::New for expediency here
// Remove this once node::FatalException is clean
v8::Local<v8::Message> message =
v8::Local<v8::Message>::New(metadata);
v8::Local<v8::Object> exceptionObject =
v8impl::V8LocalValueFromJsValue(
reinterpret_cast<napi_value>(exception)).As<v8::Object>();

node::FatalException(work->_env->isolate, exceptionObject, message);
}
}

Expand Down Expand Up @@ -2635,14 +2699,26 @@ class Work {
} while (0)

napi_status napi_create_async_work(napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_execute_callback execute,
napi_async_complete_callback complete,
void* data,
napi_async_work* result) {
CHECK_ARG(execute);
CHECK_ARG(result);

uvimpl::Work* work = uvimpl::Work::New(env, execute, complete, data);
napi_value resource;
if (async_resource != nullptr) {
CHECK_NAPI(napi_coerce_to_object(env, async_resource, &resource));
} else {
CHECK_NAPI(napi_create_object(env, &resource));
}

napi_value resource_name;
CHECK_NAPI(napi_coerce_to_string(env, async_resource_name, &resource_name));

uvimpl::Work* work = uvimpl::Work::New(env, resource, resource_name, execute, complete, data);

*result = reinterpret_cast<napi_async_work>(work);

Expand Down

0 comments on commit 1daa223

Please sign in to comment.