Skip to content

Commit fd530b2

Browse files
committed
wip
1 parent fc339c4 commit fd530b2

4 files changed

Lines changed: 97 additions & 86 deletions

File tree

napi-inl.h

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,98 +4261,94 @@ inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
42614261
////////////////////////////////////////////////////////////////////////////////
42624262

42634263
// static
4264-
template <typename ContextType>
4264+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
42654265
template <typename ResourceString, typename Finalizer, typename FinalizerDataType>
4266-
inline ThreadSafeFunctionEx<ContextType> ThreadSafeFunctionEx<ContextType>::New(napi_env env,
4266+
inline ThreadSafeFunctionEx<ContextType, DataType, CallJs> ThreadSafeFunctionEx<ContextType, DataType, CallJs>::New(napi_env env,
42674267
const Function& callback,
42684268
const Object& resource,
42694269
ResourceString resourceName,
42704270
size_t maxQueueSize,
42714271
size_t initialThreadCount,
42724272
ContextType* context,
42734273
Finalizer finalizeCallback,
4274-
FinalizerDataType* data,
4275-
ThreadSafeFunctionCallJS call_js_cb) {
4274+
FinalizerDataType* data) {
42764275
return New(env, callback, resource, resourceName, maxQueueSize,
42774276
initialThreadCount, context, finalizeCallback, data,
42784277
details::ThreadSafeFinalize<ContextType, Finalizer,
4279-
FinalizerDataType>::FinalizeFinalizeWrapperWithDataAndContext,
4280-
call_js_cb);
4278+
FinalizerDataType>::FinalizeFinalizeWrapperWithDataAndContext);
42814279
}
42824280

4283-
template <typename ContextType>
4284-
inline ThreadSafeFunctionEx<ContextType>::ThreadSafeFunctionEx()
4281+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4282+
inline ThreadSafeFunctionEx<ContextType, DataType, CallJs>::ThreadSafeFunctionEx()
42854283
: _tsfn() {
42864284
}
42874285

4288-
template <typename ContextType>
4289-
inline ThreadSafeFunctionEx<ContextType>::ThreadSafeFunctionEx(
4286+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4287+
inline ThreadSafeFunctionEx<ContextType, DataType, CallJs>::ThreadSafeFunctionEx(
42904288
napi_threadsafe_function tsfn)
42914289
: _tsfn(tsfn) {
42924290
}
42934291

4294-
template <typename ContextType>
4295-
inline ThreadSafeFunctionEx<ContextType>::operator napi_threadsafe_function() const {
4292+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4293+
inline ThreadSafeFunctionEx<ContextType, DataType, CallJs>::operator napi_threadsafe_function() const {
42964294
return _tsfn;
42974295
}
42984296

4299-
template <typename ContextType>
4300-
template <typename DataType>
4301-
inline napi_status ThreadSafeFunctionEx<ContextType>::BlockingCall(
4297+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4298+
inline napi_status ThreadSafeFunctionEx<ContextType, DataType, CallJs>::BlockingCall(
43024299
DataType* data) const {
43034300
return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking);
43044301
}
43054302

4306-
template <typename ContextType>
4307-
template <typename DataType>
4308-
inline napi_status ThreadSafeFunctionEx<ContextType>::NonBlockingCall(
4303+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4304+
inline napi_status ThreadSafeFunctionEx<ContextType, DataType, CallJs>::NonBlockingCall(
43094305
DataType* data) const {
43104306
return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking);
43114307
}
43124308

4313-
template <typename ContextType>
4314-
inline void ThreadSafeFunctionEx<ContextType>::Ref(napi_env env) const {
4309+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4310+
inline void ThreadSafeFunctionEx<ContextType, DataType, CallJs>::Ref(napi_env env) const {
43154311
if (_tsfn != nullptr) {
43164312
napi_status status = napi_ref_threadsafe_function(env, _tsfn);
43174313
NAPI_THROW_IF_FAILED_VOID(env, status);
43184314
}
43194315
}
43204316

4321-
template <typename ContextType>
4322-
inline void ThreadSafeFunctionEx<ContextType>::Unref(napi_env env) const {
4317+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4318+
inline void ThreadSafeFunctionEx<ContextType, DataType, CallJs>::Unref(napi_env env) const {
43234319
if (_tsfn != nullptr) {
43244320
napi_status status = napi_unref_threadsafe_function(env, _tsfn);
43254321
NAPI_THROW_IF_FAILED_VOID(env, status);
43264322
}
43274323
}
43284324

4329-
template <typename ContextType>
4330-
inline napi_status ThreadSafeFunctionEx<ContextType>::Acquire() const {
4325+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4326+
inline napi_status ThreadSafeFunctionEx<ContextType, DataType, CallJs>::Acquire() const {
43314327
return napi_acquire_threadsafe_function(_tsfn);
43324328
}
43334329

4334-
template <typename ContextType>
4335-
inline napi_status ThreadSafeFunctionEx<ContextType>::Release() {
4330+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4331+
inline napi_status ThreadSafeFunctionEx<ContextType, DataType, CallJs>::Release() {
43364332
return napi_release_threadsafe_function(_tsfn, napi_tsfn_release);
43374333
}
43384334

4339-
template <typename ContextType>
4340-
inline napi_status ThreadSafeFunctionEx<ContextType>::Abort() {
4335+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4336+
inline napi_status ThreadSafeFunctionEx<ContextType, DataType, CallJs>::Abort() {
43414337
return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort);
43424338
}
43434339

4344-
template <typename ContextType>
4345-
inline ContextType* ThreadSafeFunctionEx<ContextType>::GetContext() const {
4340+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4341+
inline ContextType* ThreadSafeFunctionEx<ContextType, DataType, CallJs>::GetContext() const {
43464342
void* context;
43474343
napi_status status = napi_get_threadsafe_function_context(_tsfn, &context);
43484344
NAPI_FATAL_IF_FAILED(status, "ThreadSafeFunctionEx::GetContext", "napi_get_threadsafe_function_context");
43494345
return static_cast<ContextType*>(context);
43504346
}
43514347

43524348
// static
4353-
template <typename ContextType>
4349+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
43544350
template <typename ResourceString, typename Finalizer, typename FinalizerDataType>
4355-
inline ThreadSafeFunctionEx<ContextType> ThreadSafeFunctionEx<ContextType>::New(napi_env env,
4351+
inline ThreadSafeFunctionEx<ContextType, DataType, CallJs> ThreadSafeFunctionEx<ContextType, DataType, CallJs>::New(napi_env env,
43564352
const Function& callback,
43574353
const Object& resource,
43584354
ResourceString resourceName,
@@ -4361,13 +4357,14 @@ inline ThreadSafeFunctionEx<ContextType> ThreadSafeFunctionEx<ContextType>::New(
43614357
ContextType* context,
43624358
Finalizer finalizeCallback,
43634359
FinalizerDataType* data,
4364-
napi_finalize wrapper,
4365-
ThreadSafeFunctionCallJS call_js_cb) {
4360+
napi_finalize wrapper) {
43664361
static_assert(details::can_make_string<ResourceString>::value
43674362
|| std::is_convertible<ResourceString, napi_value>::value,
43684363
"Resource name should be convertible to the string type");
43694364

4370-
ThreadSafeFunctionEx<ContextType> tsfn;
4365+
ThreadSafeFunctionEx<ContextType, DataType, CallJs> tsfn;
4366+
// details::ThreadSafeCallJs<ContextType, DataType, ThreadSafeFunctionCallJS> cb{call_js_cb};
4367+
43714368
auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
43724369
FinalizerDataType>({ data, finalizeCallback });
43734370
napi_status status = napi_create_threadsafe_function(env, callback, resource,
@@ -4379,33 +4376,45 @@ inline ThreadSafeFunctionEx<ContextType> ThreadSafeFunctionEx<ContextType>::New(
43794376
// }
43804377
// call_js_cb( Napi::Env(env), Function(env, jsCallback), static_cast<ContextType*>(context), data);
43814378
// },
4382-
CallJS,
4379+
CallJsInternal,
43834380
&tsfn._tsfn);
43844381
if (status != napi_ok) {
43854382
delete finalizeData;
4386-
NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunctionEx<ContextType>());
4383+
NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunctionEx<ContextType, DataType, CallJs>());
43874384
}
43884385

43894386
return tsfn;
43904387
}
43914388

4392-
template <typename ContextType>
4393-
inline void
4394-
ThreadSafeFunctionEx<ContextType>::CallJS(napi_env env, napi_value jsCallback,
4389+
template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4390+
void ThreadSafeFunctionEx<ContextType, DataType, CallJs>::CallJsInternal(napi_env env, napi_value jsCallback,
43954391
void *context, void *data) {
4396-
if (env == nullptr && jsCallback == nullptr) {
4397-
return;
4398-
}
43994392

4400-
if (data != nullptr) {
4401-
auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
4402-
(*callbackWrapper)(env, Function(env, jsCallback));
4403-
delete callbackWrapper;
4404-
} else if (jsCallback != nullptr) {
4405-
Function(env, jsCallback).Call({});
4393+
if (CallJs == nullptr && jsCallback != nullptr) {
4394+
Function(env, jsCallback).Call(0, nullptr);
4395+
} else {
4396+
CallJs(env, Function(env, jsCallback), static_cast<ContextType*>(context), static_cast<DataType*>(data));
44064397
}
44074398
}
44084399

4400+
4401+
// template <typename ContextType, typename DataType, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4402+
// inline void
4403+
// ThreadSafeFunctionEx<ContextType, DataType, CallJs>::CallJS(napi_env env, napi_value jsCallback,
4404+
// void *context, void *data) {
4405+
// if (env == nullptr && jsCallback == nullptr) {
4406+
// return;
4407+
// }
4408+
4409+
// if (data != nullptr) {
4410+
// auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
4411+
// (*callbackWrapper)(env, Function(env, jsCallback));
4412+
// delete callbackWrapper;
4413+
// } else if (jsCallback != nullptr) {
4414+
// Function(env, jsCallback).Call({});
4415+
// }
4416+
// }
4417+
44094418
////////////////////////////////////////////////////////////////////////////////
44104419
// ThreadSafeFunction class
44114420
////////////////////////////////////////////////////////////////////////////////

napi.h

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,29 +2036,24 @@ namespace Napi {
20362036
};
20372037

20382038
#if (NAPI_VERSION > 3)
2039-
2040-
2041-
template <typename ContextType, typename DataType>
2039+
template <typename ContextType = void, typename DataType = void, void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*) = nullptr >
20422040
class ThreadSafeFunctionEx {
20432041
public:
20442042

2045-
using ThreadSafeFunctionCallJS = std::function<void(Napi::Env, Napi::Function, ContextType *context, DataType *data)>;
2046-
20472043
// This API may only be called from the main thread.
20482044
template <typename ResourceString, typename Finalizer, typename FinalizerDataType>
2049-
static ThreadSafeFunctionEx<ContextType> New(napi_env env,
2045+
static ThreadSafeFunctionEx<ContextType, DataType, CallJs> New(napi_env env,
20502046
const Function& callback,
20512047
const Object& resource,
20522048
ResourceString resourceName,
20532049
size_t maxQueueSize,
20542050
size_t initialThreadCount,
20552051
ContextType* context,
20562052
Finalizer finalizeCallback,
2057-
FinalizerDataType* data,
2058-
ThreadSafeFunctionCallJS call_js_cb);
2053+
FinalizerDataType* data);
20592054

2060-
ThreadSafeFunctionEx<ContextType>();
2061-
ThreadSafeFunctionEx<ContextType>(napi_threadsafe_function tsFunctionValue);
2055+
ThreadSafeFunctionEx<ContextType, DataType, CallJs>();
2056+
ThreadSafeFunctionEx<ContextType, DataType, CallJs>(napi_threadsafe_function tsFunctionValue);
20622057

20632058
operator napi_threadsafe_function() const;
20642059

@@ -2093,11 +2088,10 @@ namespace Napi {
20932088
ContextType* GetContext() const;
20942089

20952090
private:
2096-
// using CallbackWrapper = std::function<void(Napi::Env, Napi::Function, ContextType* context)>;
20972091

20982092
template <typename ResourceString,
20992093
typename Finalizer, typename FinalizerDataType>
2100-
static ThreadSafeFunctionEx<ContextType> New(napi_env env,
2094+
static ThreadSafeFunctionEx<ContextType, DataType, CallJs> New(napi_env env,
21012095
const Function& callback,
21022096
const Object& resource,
21032097
ResourceString resourceName,
@@ -2106,17 +2100,13 @@ namespace Napi {
21062100
ContextType* context,
21072101
Finalizer finalizeCallback,
21082102
FinalizerDataType* data,
2109-
napi_finalize wrapper,
2110-
ThreadSafeFunctionCallJS call_js_cb);
2111-
2112-
static void CallJS(napi_env env,
2113-
napi_value jsCallback,
2114-
void* context,
2115-
void* data);
2103+
napi_finalize wrapper);
21162104

2105+
static void CallJsInternal(napi_env env,
2106+
napi_value jsCallback,
2107+
void* context,
2108+
void* data);
21172109
protected:
2118-
void CallJS
2119-
21202110
napi_threadsafe_function _tsfn;
21212111
};
21222112

test/threadsafe_function/threadsafe_function_ex.cc

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,28 @@
44

55
using namespace Napi;
66

7-
using TSFNContext = Reference<Napi::Value>;
8-
97
namespace {
108

9+
// Context of our TSFN.
10+
using TSFNContext = Reference<Napi::Value>;
11+
12+
// Data passed to ThreadSafeFunctionEx::[Non]BlockingCall
1113
struct CallJsData {
12-
CallJsData(Napi::Env env) : deferred(Promise::Deferred::New(env)) { };
14+
CallJsData(Napi::Env env) : deferred(Promise::Deferred::New(env)){};
1315

14-
void resolve(TSFNContext* context) {
15-
deferred.Resolve(context->Value());
16-
};
1716
Promise::Deferred deferred;
1817
};
1918

19+
// CallJs callback function
20+
static void CallJs(Napi::Env /*env*/, Napi::Function /*jsCallback*/,
21+
TSFNContext *context, CallJsData *data) {
22+
data->deferred.Resolve(context->Value());
23+
}
24+
25+
// Full type of our ThreadSafeFunctionEx
26+
using TSFN = ThreadSafeFunctionEx<TSFNContext, CallJsData, CallJs>;
27+
28+
// A JS-accessible wrap that holds a TSFN.
2029
class TSFNWrap : public ObjectWrap<TSFNWrap> {
2130
public:
2231
static Object Init(Napi::Env env, Object exports);
@@ -25,7 +34,7 @@ class TSFNWrap : public ObjectWrap<TSFNWrap> {
2534
Napi::Value GetContextByCall(const CallbackInfo &info) {
2635
Napi::Env env = info.Env();
2736
std::unique_ptr<CallJsData> callData = std::make_unique<CallJsData>(env);
28-
auto& deferred = callData->deferred;
37+
auto &deferred = callData->deferred;
2938
_tsfn.BlockingCall(callData.release());
3039
return deferred.Promise();
3140
};
@@ -40,7 +49,7 @@ class TSFNWrap : public ObjectWrap<TSFNWrap> {
4049
};
4150

4251
private:
43-
ThreadSafeFunctionEx<TSFNContext> _tsfn;
52+
TSFN _tsfn;
4453
Promise::Deferred _deferred;
4554
};
4655

@@ -63,7 +72,7 @@ TSFNWrap::TSFNWrap(const CallbackInfo &info)
6372
TSFNContext *ctx = new Reference<Napi::Value>;
6473
*ctx = Persistent(info[0]);
6574

66-
_tsfn = ThreadSafeFunctionEx<TSFNContext>::New(
75+
_tsfn = ThreadSafeFunctionEx<TSFNContext, CallJsData, CallJs>::New(
6776
info.Env(), // napi_env env,
6877
Function::New(
6978
env,
@@ -74,15 +83,13 @@ TSFNWrap::TSFNWrap(const CallbackInfo &info)
7483
1, // size_t initialThreadCount,
7584
ctx, // ContextType* context,
7685

77-
[this](Napi::Env env, void*, TSFNContext *ctx) { // Finalizer finalizeCallback,
86+
[this](Napi::Env env, void *,
87+
TSFNContext *ctx) { // Finalizer finalizeCallback,
7888
_deferred.Resolve(env.Undefined());
7989
delete ctx;
8090
},
81-
static_cast<void*>(nullptr), // FinalizerDataType* data,
82-
[](Napi::Env, Napi::Value, TSFNContext *context, void *data) { // call_js_cb
83-
std::unique_ptr<CallJsData> callData(static_cast<CallJsData*>(data));
84-
callData->resolve(context);
85-
});
91+
static_cast<void *>(nullptr) // FinalizerDataType* data,
92+
);
8693
}
8794
} // namespace
8895

test/threadsafe_function/threadsafe_function_ex.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ const buildType = process.config.target_defaults.default_configuration;
55

66
module.exports = Promise.all([
77
test(require(`../build/${buildType}/binding.node`)),
8-
test(require(`../build/${buildType}/binding_noexcept.node`))
8+
// test(require(`../build/${buildType}/binding_noexcept.node`))
99
]);
1010

1111
async function test(binding) {
1212
const ctx = { };
1313
const tsfn = new binding.threadsafe_function_ex.TSFNWrap(ctx);
14+
console.log("1");
1415
assert(ctx === await tsfn.getContextByCall(),"getContextByCall context not equal");
16+
console.log("2");
1517
assert(ctx === tsfn.getContextFromTsfn(),"getContextFromTsfn context not equal");
18+
console.log("3");
19+
console.log("releasing");
1620
await tsfn.release();
21+
console.log("released!");
1722
}

0 commit comments

Comments
 (0)