@@ -43,17 +43,22 @@ class TSFNWrap;
43
43
// Context of the TSFN.
44
44
using Context = TSFNWrap;
45
45
46
- // Data passed (as pointer) to [Non]BlockingCall
47
- using DataType = std::unique_ptr<std::promise<int >>;
46
+ struct Data {
47
+ // Data passed (as pointer) to [Non]BlockingCall
48
+ std::promise<int > promise;
49
+ uint32_t base;
50
+ };
51
+ using DataType = std::unique_ptr<Data>;
48
52
49
53
// CallJs callback function
50
54
static void CallJs (Napi::Env env, Napi::Function /* jsCallback*/ ,
51
- Context *context, DataType *data) {
52
- if (data != nullptr ) {
55
+ Context *context, DataType *dataPtr) {
56
+ if (dataPtr != nullptr ) {
57
+ auto &data = *dataPtr;
53
58
if (env != nullptr ) {
54
- (* data)-> set_value (clock () );
59
+ data-> promise . set_value (data-> base * data-> base );
55
60
} else {
56
- (* data)-> set_exception (std::make_exception_ptr (
61
+ data-> promise . set_exception (std::make_exception_ptr (
57
62
std::runtime_error (" TSFN has been finalized." )));
58
63
}
59
64
}
@@ -92,42 +97,54 @@ class TSFNWrap : public base {
92
97
}
93
98
}
94
99
95
- struct FinalizerDataType {
100
+ struct FinalizerData {
96
101
std::vector<std::thread> threads;
97
102
std::unique_ptr<Promise::Deferred> deferred;
98
103
};
99
104
100
105
// The finalizer data is shared, because we want to join the threads if our
101
106
// TSFNWrap object gets garbage-collected and there are still active threads.
102
- using SharedFinalizerDataType = std::shared_ptr<FinalizerDataType >;
107
+ using FinalizerDataType = std::shared_ptr<FinalizerData >;
103
108
109
+ #define THREADLOG (X ) if (context->logThread) {\
110
+ std::cout << X;\
111
+ }
104
112
static void threadEntry (size_t threadId, TSFN tsfn, uint32_t callCount,
105
- bool logThread ) {
113
+ Context *context ) {
106
114
using namespace std ::chrono_literals;
115
+
116
+ THREADLOG (" Thread " << threadId << " starting...\n " )
117
+
107
118
for (auto i = 0U ; i < callCount; ++i) {
108
- auto promise = std::make_unique<std::promise<int >>();
109
- tsfn.NonBlockingCall (&promise);
110
- auto future = promise->get_future ();
119
+ auto data = std::make_unique<Data>();
120
+ data->base = threadId + 1 ;
121
+ THREADLOG (" Thread " << threadId << " making call, base = " << data->base << " \n " )
122
+
123
+ tsfn.NonBlockingCall (&data);
124
+ auto future = data->promise .get_future ();
111
125
auto result = future.get ();
112
- if (logThread) {
113
- std::cout << " Thread " << threadId << " got result " << result << " \n " ;
114
- }
115
- }
116
- if (logThread) {
117
- std::cout << " Thread " << threadId << " finished\n " ;
126
+ context->callSucceeded (result);
127
+ THREADLOG (" Thread " << threadId << " got result: " << result << " \n " )
118
128
}
129
+
130
+ THREADLOG (" Thread " << threadId << " finished.\n\n " )
119
131
tsfn.Release ();
120
132
}
133
+ #undef THREADLOG
121
134
122
- static std::array<ClassPropertyDescriptor<TSFNWrap>, 3 > InstanceMethods () {
123
- return {InstanceMethod (" call " , &TSFNWrap::Call ),
135
+ static std::array<ClassPropertyDescriptor<TSFNWrap>, 4 > InstanceMethods () {
136
+ return {InstanceMethod (" getContext " , &TSFNWrap::GetContext ),
124
137
InstanceMethod (" start" , &TSFNWrap::Start),
138
+ InstanceMethod (" callCount" , &TSFNWrap::CallCount),
125
139
InstanceMethod (" release" , &TSFNWrap::Release)};
126
140
}
127
141
128
142
bool cppExceptions = false ;
129
143
bool logThread;
130
- std::shared_ptr<FinalizerDataType> finalizerData;
144
+ std::atomic_uint succeededCalls;
145
+ std::atomic_int aggregate;
146
+
147
+ FinalizerDataType finalizerData;
131
148
132
149
Napi::Value Start (const CallbackInfo &info) {
133
150
Napi::Env env = info.Env ();
@@ -143,7 +160,7 @@ class TSFNWrap : public base {
143
160
// The JS-provided callback to execute for each call (if provided)
144
161
Function callback;
145
162
146
- finalizerData = std::make_shared<FinalizerDataType >();
163
+ finalizerData = std::make_shared<FinalizerData >();
147
164
148
165
logThread = DefaultOptions.logThread ;
149
166
bool logCall = DefaultOptions.logCall ;
@@ -217,8 +234,10 @@ class TSFNWrap : public base {
217
234
218
235
const auto threadCount = callCounts.size ();
219
236
220
- auto *finalizerDataPtr = new SharedFinalizerDataType (finalizerData);
237
+ auto *finalizerDataPtr = new FinalizerDataType (finalizerData);
221
238
239
+ succeededCalls = 0 ;
240
+ aggregate = 0 ;
222
241
_tsfn = TSFN::New (
223
242
env, // napi_env env,
224
243
TSFN::DefaultFunctionFactory (env), // const Function& callback,
@@ -232,16 +251,16 @@ class TSFNWrap : public base {
232
251
);
233
252
234
253
for (auto threadId = 0U ; threadId < threadCount; ++threadId) {
235
- finalizerData->threads .push_back (std::thread (
236
- threadEntry, threadId, _tsfn, callCounts[threadId], logThread ));
254
+ finalizerData->threads .push_back (std::thread (threadEntry, threadId, _tsfn,
255
+ callCounts[threadId], this ));
237
256
}
238
257
239
258
return String::New (env, " started" );
240
259
};
241
260
242
261
// TSFN finalizer. Joins the threads and resolves the Promise returned by
243
262
// `Release()` above.
244
- static void Finalizer (Napi::Env env, SharedFinalizerDataType *finalizeData,
263
+ static void Finalizer (Napi::Env env, FinalizerDataType *finalizeData,
245
264
Context *ctx) {
246
265
247
266
if (ctx->logThread ) {
@@ -254,7 +273,7 @@ class TSFNWrap : public base {
254
273
}
255
274
ctx->clearTSFN ();
256
275
if (ctx->logThread ) {
257
- std::cout << " Finished\n " ;
276
+ std::cout << " Finished finalizing threads. \n " ;
258
277
}
259
278
260
279
(*finalizeData)->deferred ->Resolve (Boolean::New (env, true ));
@@ -265,26 +284,33 @@ class TSFNWrap : public base {
265
284
if (finalizerData->deferred ) {
266
285
return finalizerData->deferred ->Promise ();
267
286
}
268
- // return finalizerData->deferred.Promise();
269
- auto env = info.Env ();
270
287
finalizerData->deferred .reset (
271
- new Promise::Deferred (Promise::Deferred::New (env )));
288
+ new Promise::Deferred (Promise::Deferred::New (info. Env () )));
272
289
_tsfn.Release ();
273
290
return finalizerData->deferred ->Promise ();
274
291
};
275
292
276
- Napi::Value Call (const CallbackInfo &info) {
277
- // auto *callData = new DataType(info.Env());
278
- // _tsfn.NonBlockingCall(callData); return callData->Promise();
279
- return info.Env ().Undefined ();
293
+ Napi::Value CallCount (const CallbackInfo &info) {
294
+ Napi::Env env (info.Env ());
295
+
296
+ auto results = Array::New (env, 2 );
297
+ results.Set (" 0" , Number::New (env, succeededCalls));
298
+ results.Set (" 1" , Number::New (env, aggregate));
299
+ return results;
280
300
};
281
301
282
302
Napi::Value GetContext (const CallbackInfo &) {
283
303
return _tsfn.GetContext ()->Value ();
284
304
};
285
305
286
- // This does not run on the node thread.
306
+ // This method does not run on the Node thread.
287
307
void clearTSFN () { _tsfn = TSFN (); }
308
+
309
+ // This method does not run on the Node thread.
310
+ void callSucceeded (int result) {
311
+ succeededCalls++;
312
+ aggregate += result;
313
+ }
288
314
};
289
315
} // namespace example
290
316
0 commit comments