Skip to content

Commit b54f5eb

Browse files
committed
Additional changes from review
1 parent 59f27da commit b54f5eb

File tree

3 files changed

+53
-61
lines changed

3 files changed

+53
-61
lines changed

doc/threadsafe.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ construct a no-op `Function` **or** to target N-API 5 and "construct" a
9393
with just a switch of the `NAPI_VERSION` compile-time constant.
9494

9595
The removal of the dynamic call functionality has the following implications:
96-
- The API does _not_ act as a "broker" compared to the non-`Ex`. Once Node.js
97-
finalizes the thread-safe function, the `CallJs` callback will execute with an
98-
empty `Napi::Env` for any remaining items on the queue. This provides the
99-
ability to handle any necessary cleanup of the item's data.
96+
- The API does _not_ act as a "broker" compared to the
97+
`Napi::ThreadSafeFunction`. Once Node.js finalizes the thread-safe function,
98+
the `CallJs` callback will execute with an empty `Napi::Env` for any remaining
99+
items on the queue. This provides the ability to handle any necessary cleanup
100+
of the item's data.
100101
- The callback _does_ receive the context as a parameter, so a call to
101102
`GetContext()` is _not_ necessary. This context type is specified as the
102103
**first template argument** specified to `::New`, ensuring type safety.

doc/threadsafe_function_ex.md

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ Returns one of:
120120
Indicates that an existing thread will stop making use of the thread-safe
121121
function. A thread should call this API when it stops making use of this
122122
thread-safe function. Using any thread-safe APIs after having called this API
123-
has undefined results in the current thread, as the thread-safe function may have been destroyed.
123+
has undefined results in the current thread, as the thread-safe function may
124+
have been destroyed.
124125

125126
```cpp
126127
napi_status Napi::ThreadSafeFunctionEx<ContextType, DataType, Callback>::Release()
@@ -176,7 +177,8 @@ Returns one of:
176177
- `napi_ok`: `data` was successfully added to the queue.
177178
- `napi_queue_full`: The queue was full when trying to call in a non-blocking
178179
method.
179-
- `napi_closing`: The thread-safe function is aborted and no further calls can be made.
180+
- `napi_closing`: The thread-safe function is aborted and no further calls can
181+
be made.
180182
- `napi_invalid_arg`: The thread-safe function is closed.
181183
- `napi_generic_failure`: A generic error occurred when attemping to add to the
182184
queue.
@@ -186,110 +188,99 @@ Returns one of:
186188

187189
```cpp
188190
#include <chrono>
189-
#include <thread>
190191
#include <napi.h>
192+
#include <thread>
191193

192194
using namespace Napi;
193195

194196
using Context = Reference<Value>;
195197
using DataType = int;
196-
void CallJs( Napi::Env env, Function callback, Context* context, DataType* data );
198+
void CallJs(Napi::Env env, Function callback, Context *context, DataType *data);
197199
using TSFN = ThreadSafeFunctionEx<Context, DataType, CallJs>;
198200
using FinalizerDataType = void;
199201

200202
std::thread nativeThread;
201203
TSFN tsfn;
202204

203-
Value Start( const CallbackInfo& info )
204-
{
205+
Value Start(const CallbackInfo &info) {
205206
Napi::Env env = info.Env();
206207

207-
if ( info.Length() < 2 )
208-
{
209-
throw TypeError::New( env, "Expected two arguments" );
210-
}
211-
else if ( !info[0].IsFunction() )
212-
{
213-
throw TypeError::New( env, "Expected first arg to be function" );
214-
}
215-
else if ( !info[1].IsNumber() )
216-
{
217-
throw TypeError::New( env, "Expected second arg to be number" );
208+
if (info.Length() < 2) {
209+
throw TypeError::New(env, "Expected two arguments");
210+
} else if (!info[0].IsFunction()) {
211+
throw TypeError::New(env, "Expected first arg to be function");
212+
} else if (!info[1].IsNumber()) {
213+
throw TypeError::New(env, "Expected second arg to be number");
218214
}
219215

220216
int count = info[1].As<Number>().Int32Value();
221217

222218
// Create a new context set to the the receiver (ie, `this`) of the function
223219
// call
224-
Context* context = new Reference<Value>( Persistent( info.This() ) );
220+
Context *context = new Reference<Value>(Persistent(info.This()));
225221

226222
// Create a ThreadSafeFunction
227-
tsfn = TSFN::New( env,
228-
info[0].As<Function>(), // JavaScript function called asynchronously
229-
"Resource Name", // Name
230-
0, // Unlimited queue
231-
1, // Only one thread will use this initially
232-
context,
233-
[]( Napi::Env, FinalizerDataType*,
234-
Context* ctx ) { // Finalizer used to clean threads up
235-
nativeThread.join();
236-
delete ctx;
237-
} );
223+
tsfn = TSFN::New(
224+
env,
225+
info[0].As<Function>(), // JavaScript function called asynchronously
226+
"Resource Name", // Name
227+
0, // Unlimited queue
228+
1, // Only one thread will use this initially
229+
context,
230+
[](Napi::Env, FinalizerDataType *,
231+
Context *ctx) { // Finalizer used to clean threads up
232+
nativeThread.join();
233+
delete ctx;
234+
});
238235

239236
// Create a native thread
240-
nativeThread = std::thread( [count] {
241-
for ( int i = 0; i < count; i++ )
242-
{
237+
nativeThread = std::thread([count] {
238+
for (int i = 0; i < count; i++) {
243239
// Create new data
244-
int* value = new int( clock() );
240+
int *value = new int(clock());
245241

246242
// Perform a blocking call
247-
napi_status status = tsfn.BlockingCall( value );
248-
if ( status != napi_ok )
249-
{
243+
napi_status status = tsfn.BlockingCall(value);
244+
if (status != napi_ok) {
250245
// Handle error
251246
break;
252247
}
253248

254-
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
249+
std::this_thread::sleep_for(std::chrono::seconds(1));
255250
}
256251

257252
// Release the thread-safe function
258253
tsfn.Release();
259-
} );
254+
});
260255

261-
return Boolean::New( env, true );
256+
return Boolean::New(env, true);
262257
}
263258

264259
// Transform native data into JS data, passing it to the provided
265260
// `callback` -- the TSFN's JavaScript function.
266-
void CallJs( Napi::Env env, Function callback, Context* context, DataType* data )
267-
{
261+
void CallJs(Napi::Env env, Function callback, Context *context,
262+
DataType *data) {
268263
// Is the JavaScript environment still available to call into, eg. the TSFN is
269264
// not aborted
270-
if ( env != nullptr )
271-
{
265+
if (env != nullptr) {
272266
// On N-API 5+, the `callback` parameter is optional; however, this example
273267
// does ensure a callback is provided.
274-
if ( callback != nullptr )
275-
{
276-
callback.Call( context->Value(), {Number::New( env, *data )} );
268+
if (callback != nullptr) {
269+
callback.Call(context->Value(), {Number::New(env, *data)});
277270
}
278271
}
279-
if ( data != nullptr )
280-
{
272+
if (data != nullptr) {
281273
// We're finished with the data.
282274
delete data;
283275
}
284276
}
285277

286-
Napi::Object Init( Napi::Env env, Object exports )
287-
{
288-
exports.Set( "start", Function::New( env, Start ) );
278+
Napi::Object Init(Napi::Env env, Object exports) {
279+
exports.Set("start", Function::New(env, Start));
289280
return exports;
290281
}
291282

292-
NODE_API_MODULE( clock, Init )
283+
NODE_API_MODULE(clock, Init)
293284
```
294285
295286
The above code can be used from JavaScript as follows:
@@ -304,7 +295,7 @@ start.call(new Date(), function (clock) {
304295
```
305296

306297
When executed, the output will show the value of `clock()` five times at one
307-
second intervals, prefixed with the TSFN's context -- `start`'s receiver (ie,
298+
second intervals, prefixed with the TSFN's context -- `start`'s receiver (ie,
308299
`new Date()`):
309300

310301
```

test/threadsafe_function_ex/threadsafe_function.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ const buildType = process.config.target_defaults.default_configuration;
44
const assert = require('assert');
55
const common = require('../common');
66

7-
module.exports = (async function() {
7+
module.exports = (async function () {
88
await test(require(`../build/${buildType}/binding.node`));
99
await test(require(`../build/${buildType}/binding_noexcept.node`));
1010
})();
1111

1212
async function test(binding) {
13-
const expectedArray = (function(arrayLength) {
13+
const expectedArray = (function (arrayLength) {
1414
const result = [];
1515
for (let index = 0; index < arrayLength; index++) {
1616
result.push(arrayLength - 1 - index);
@@ -60,7 +60,7 @@ async function test(binding) {
6060
});
6161
}
6262
}, false /* abort */, false /* launchSecondary */,
63-
binding.threadsafe_function_ex.MAX_QUEUE_SIZE);
63+
binding.threadsafe_function_ex.MAX_QUEUE_SIZE);
6464
});
6565

6666
// Start the thread in blocking mode, and assert that all values are passed.
@@ -191,4 +191,4 @@ async function test(binding) {
191191
})).indexOf(0),
192192
-1,
193193
);
194-
}
194+
}

0 commit comments

Comments
 (0)