-
Notifications
You must be signed in to change notification settings - Fork 465
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tsfn: support direct calls to underlying napi_tsfn
support direct calls to underlying napi_tsfn Fixes: #556 PR-URL: #58 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]> Reviewed-By: Gabriel Schulhof <[email protected]>
- Loading branch information
Showing
7 changed files
with
166 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
test/threadsafe_function/threadsafe_function_existing_tsfn.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#include "napi.h" | ||
#include <cstdlib> | ||
|
||
#if (NAPI_VERSION > 3) | ||
|
||
using namespace Napi; | ||
|
||
namespace { | ||
|
||
struct TestContext { | ||
TestContext(Promise::Deferred &&deferred) | ||
: deferred(std::move(deferred)), callData(nullptr){}; | ||
|
||
napi_threadsafe_function tsfn; | ||
Promise::Deferred deferred; | ||
double *callData; | ||
|
||
~TestContext() { | ||
if (callData != nullptr) | ||
delete callData; | ||
}; | ||
}; | ||
|
||
void FinalizeCB(napi_env env, void * /*finalizeData */, void *context) { | ||
TestContext *testContext = static_cast<TestContext *>(context); | ||
if (testContext->callData != nullptr) { | ||
testContext->deferred.Resolve(Number::New(env, *testContext->callData)); | ||
} else { | ||
testContext->deferred.Resolve(Napi::Env(env).Undefined()); | ||
} | ||
delete testContext; | ||
} | ||
|
||
void CallJSWithData(napi_env env, napi_value /* callback */, void *context, | ||
void *data) { | ||
TestContext *testContext = static_cast<TestContext *>(context); | ||
testContext->callData = static_cast<double *>(data); | ||
|
||
napi_status status = | ||
napi_release_threadsafe_function(testContext->tsfn, napi_tsfn_release); | ||
|
||
NAPI_THROW_IF_FAILED_VOID(env, status); | ||
} | ||
|
||
void CallJSNoData(napi_env env, napi_value /* callback */, void *context, | ||
void * /*data*/) { | ||
TestContext *testContext = static_cast<TestContext *>(context); | ||
testContext->callData = nullptr; | ||
|
||
napi_status status = | ||
napi_release_threadsafe_function(testContext->tsfn, napi_tsfn_release); | ||
|
||
NAPI_THROW_IF_FAILED_VOID(env, status); | ||
} | ||
|
||
static Value TestCall(const CallbackInfo &info) { | ||
Napi::Env env = info.Env(); | ||
bool isBlocking = false; | ||
bool hasData = false; | ||
if (info.Length() > 0) { | ||
Object opts = info[0].As<Object>(); | ||
if (opts.Has("blocking")) { | ||
isBlocking = opts.Get("blocking").ToBoolean(); | ||
} | ||
if (opts.Has("data")) { | ||
hasData = opts.Get("data").ToBoolean(); | ||
} | ||
} | ||
|
||
// Allow optional callback passed from JS. Useful for testing. | ||
Function cb = Function::New(env, [](const CallbackInfo & /*info*/) {}); | ||
|
||
TestContext *testContext = new TestContext(Napi::Promise::Deferred(env)); | ||
|
||
napi_status status = napi_create_threadsafe_function( | ||
env, cb, Object::New(env), String::New(env, "Test"), 0, 1, | ||
nullptr, /*finalize data*/ | ||
FinalizeCB, testContext, hasData ? CallJSWithData : CallJSNoData, | ||
&testContext->tsfn); | ||
|
||
NAPI_THROW_IF_FAILED(env, status, Value()); | ||
|
||
ThreadSafeFunction wrapped = ThreadSafeFunction(testContext->tsfn); | ||
|
||
// Test the four napi_threadsafe_function direct-accessing calls | ||
if (isBlocking) { | ||
if (hasData) { | ||
wrapped.BlockingCall(static_cast<void *>(new double(std::rand()))); | ||
} else { | ||
wrapped.BlockingCall(static_cast<void *>(nullptr)); | ||
} | ||
} else { | ||
if (hasData) { | ||
wrapped.NonBlockingCall(static_cast<void *>(new double(std::rand()))); | ||
} else { | ||
wrapped.NonBlockingCall(static_cast<void *>(nullptr)); | ||
} | ||
} | ||
|
||
return testContext->deferred.Promise(); | ||
} | ||
|
||
} // namespace | ||
|
||
Object InitThreadSafeFunctionExistingTsfn(Env env) { | ||
Object exports = Object::New(env); | ||
exports["testCall"] = Function::New(env, TestCall); | ||
|
||
return exports; | ||
} | ||
|
||
#endif |
19 changes: 19 additions & 0 deletions
19
test/threadsafe_function/threadsafe_function_existing_tsfn.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
'use strict'; | ||
|
||
const assert = require('assert'); | ||
|
||
const buildType = process.config.target_defaults.default_configuration; | ||
|
||
module.exports = Promise.all([ | ||
test(require(`../build/${buildType}/binding.node`)), | ||
test(require(`../build/${buildType}/binding_noexcept.node`)) | ||
]); | ||
|
||
async function test(binding) { | ||
const testCall = binding.threadsafe_function_existing_tsfn.testCall; | ||
|
||
assert(typeof await testCall({ blocking: true, data: true }) === "number"); | ||
assert(typeof await testCall({ blocking: true, data: false }) === "undefined"); | ||
assert(typeof await testCall({ blocking: false, data: true }) === "number"); | ||
assert(typeof await testCall({ blocking: false, data: false }) === "undefined"); | ||
} |