18c339a94Sopenharmony_ci# ThreadSafeFunction
28c339a94Sopenharmony_ci
38c339a94Sopenharmony_ciThe `Napi::ThreadSafeFunction` type provides APIs for threads to communicate
48c339a94Sopenharmony_ciwith the addon's main thread to invoke JavaScript functions on their behalf.
58c339a94Sopenharmony_ciDocumentation can be found for an [overview of the API](threadsafe.md), as well
68c339a94Sopenharmony_cias [differences between the two thread-safe function
78c339a94Sopenharmony_ciAPIs](threadsafe.md#implementation-differences).
88c339a94Sopenharmony_ci
98c339a94Sopenharmony_ci## Methods
108c339a94Sopenharmony_ci
118c339a94Sopenharmony_ci### Constructor
128c339a94Sopenharmony_ci
138c339a94Sopenharmony_ciCreates a new empty instance of `Napi::ThreadSafeFunction`.
148c339a94Sopenharmony_ci
158c339a94Sopenharmony_ci```cpp
168c339a94Sopenharmony_ciNapi::Function::ThreadSafeFunction();
178c339a94Sopenharmony_ci```
188c339a94Sopenharmony_ci
198c339a94Sopenharmony_ci### Constructor
208c339a94Sopenharmony_ci
218c339a94Sopenharmony_ciCreates a new instance of the `Napi::ThreadSafeFunction` object.
228c339a94Sopenharmony_ci
238c339a94Sopenharmony_ci```cpp
248c339a94Sopenharmony_ciNapi::ThreadSafeFunction::ThreadSafeFunction(napi_threadsafe_function tsfn);
258c339a94Sopenharmony_ci```
268c339a94Sopenharmony_ci
278c339a94Sopenharmony_ci- `tsfn`: The `napi_threadsafe_function` which is a handle for an existing
288c339a94Sopenharmony_ci  thread-safe function.
298c339a94Sopenharmony_ci
308c339a94Sopenharmony_ciReturns a non-empty `Napi::ThreadSafeFunction` instance. When using this
318c339a94Sopenharmony_ciconstructor, only use the `Blocking(void*)` / `NonBlocking(void*)` overloads;
328c339a94Sopenharmony_cithe `Callback` and templated `data*` overloads should _not_ be used. See below
338c339a94Sopenharmony_cifor additional details.
348c339a94Sopenharmony_ci
358c339a94Sopenharmony_ci### New
368c339a94Sopenharmony_ci
378c339a94Sopenharmony_ciCreates a new instance of the `Napi::ThreadSafeFunction` object. The `New`
388c339a94Sopenharmony_cifunction has several overloads for the various optional parameters: skip the
398c339a94Sopenharmony_cioptional parameter for that specific overload.
408c339a94Sopenharmony_ci
418c339a94Sopenharmony_ci```cpp
428c339a94Sopenharmony_ciNew(napi_env env,
438c339a94Sopenharmony_ci    const Function& callback,
448c339a94Sopenharmony_ci    const Object& resource,
458c339a94Sopenharmony_ci    ResourceString resourceName,
468c339a94Sopenharmony_ci    size_t maxQueueSize,
478c339a94Sopenharmony_ci    size_t initialThreadCount,
488c339a94Sopenharmony_ci    ContextType* context,
498c339a94Sopenharmony_ci    Finalizer finalizeCallback,
508c339a94Sopenharmony_ci    FinalizerDataType* data);
518c339a94Sopenharmony_ci```
528c339a94Sopenharmony_ci
538c339a94Sopenharmony_ci- `env`: The `napi_env` environment in which to construct the
548c339a94Sopenharmony_ci  `Napi::ThreadSafeFunction` object.
558c339a94Sopenharmony_ci- `callback`: The `Function` to call from another thread.
568c339a94Sopenharmony_ci- `[optional] resource`: An object associated with the async work that will be
578c339a94Sopenharmony_ci  passed to possible async_hooks init hooks.
588c339a94Sopenharmony_ci- `resourceName`: A JavaScript string to provide an identifier for the kind of
598c339a94Sopenharmony_ci  resource that is being provided for diagnostic information exposed by the
608c339a94Sopenharmony_ci  async_hooks API.
618c339a94Sopenharmony_ci- `maxQueueSize`: Maximum size of the queue. `0` for no limit.
628c339a94Sopenharmony_ci- `initialThreadCount`: The initial number of threads, including the main
638c339a94Sopenharmony_ci  thread, which will be making use of this function.
648c339a94Sopenharmony_ci- `[optional] context`: Data to attach to the resulting `ThreadSafeFunction`. It
658c339a94Sopenharmony_ci  can be retreived by calling `GetContext()`.
668c339a94Sopenharmony_ci- `[optional] finalizeCallback`: Function to call when the `ThreadSafeFunction`
678c339a94Sopenharmony_ci  is being destroyed.  This callback will be invoked on the main thread when the
688c339a94Sopenharmony_ci  thread-safe function is about to be destroyed. It receives the context and the
698c339a94Sopenharmony_ci  finalize data given during construction (if given), and provides an
708c339a94Sopenharmony_ci  opportunity for cleaning up after the threads e.g. by calling
718c339a94Sopenharmony_ci  `uv_thread_join()`. It is important that, aside from the main loop thread,
728c339a94Sopenharmony_ci  there be no threads left using the thread-safe function after the finalize
738c339a94Sopenharmony_ci  callback completes. Must implement `void operator()(Env env, DataType* data,
748c339a94Sopenharmony_ci  ContextType* hint)`, skipping `data` or `hint` if they are not provided. Can
758c339a94Sopenharmony_ci  be retrieved via `GetContext()`.
768c339a94Sopenharmony_ci- `[optional] data`: Data to be passed to `finalizeCallback`.
778c339a94Sopenharmony_ci
788c339a94Sopenharmony_ciReturns a non-empty `Napi::ThreadSafeFunction` instance.
798c339a94Sopenharmony_ci
808c339a94Sopenharmony_ci### Acquire
818c339a94Sopenharmony_ci
828c339a94Sopenharmony_ciAdd a thread to this thread-safe function object, indicating that a new thread
838c339a94Sopenharmony_ciwill start making use of the thread-safe function.
848c339a94Sopenharmony_ci
858c339a94Sopenharmony_ci```cpp
868c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::Acquire() const
878c339a94Sopenharmony_ci```
888c339a94Sopenharmony_ci
898c339a94Sopenharmony_ciReturns one of:
908c339a94Sopenharmony_ci- `napi_ok`: The thread has successfully acquired the thread-safe function
918c339a94Sopenharmony_cifor its use.
928c339a94Sopenharmony_ci- `napi_closing`: The thread-safe function has been marked as closing via a
938c339a94Sopenharmony_ciprevious call to `Abort()`.
948c339a94Sopenharmony_ci
958c339a94Sopenharmony_ci### Release
968c339a94Sopenharmony_ci
978c339a94Sopenharmony_ciIndicate that an existing thread will stop making use of the thread-safe
988c339a94Sopenharmony_cifunction. A thread should call this API when it stops making use of this
998c339a94Sopenharmony_cithread-safe function. Using any thread-safe APIs after having called this API
1008c339a94Sopenharmony_cihas undefined results in the current thread, as it may have been destroyed.
1018c339a94Sopenharmony_ci
1028c339a94Sopenharmony_ci```cpp
1038c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::Release() const
1048c339a94Sopenharmony_ci```
1058c339a94Sopenharmony_ci
1068c339a94Sopenharmony_ciReturns one of:
1078c339a94Sopenharmony_ci- `napi_ok`: The thread-safe function has been successfully released.
1088c339a94Sopenharmony_ci- `napi_invalid_arg`: The thread-safe function's thread-count is zero.
1098c339a94Sopenharmony_ci- `napi_generic_failure`: A generic error occurred when attempting to release
1108c339a94Sopenharmony_cithe thread-safe function.
1118c339a94Sopenharmony_ci
1128c339a94Sopenharmony_ci### Abort
1138c339a94Sopenharmony_ci
1148c339a94Sopenharmony_ci"Abort" the thread-safe function. This will cause all subsequent APIs associated
1158c339a94Sopenharmony_ciwith the thread-safe function except `Release()` to return `napi_closing` even
1168c339a94Sopenharmony_cibefore its reference count reaches zero. In particular, `BlockingCall` and
1178c339a94Sopenharmony_ci`NonBlockingCall()` will return `napi_closing`, thus informing the threads that
1188c339a94Sopenharmony_ciit is no longer possible to make asynchronous calls to the thread-safe function.
1198c339a94Sopenharmony_ciThis can be used as a criterion for terminating the thread. Upon receiving a
1208c339a94Sopenharmony_cireturn value of `napi_closing` from a thread-safe function call a thread must
1218c339a94Sopenharmony_cimake no further use of the thread-safe function because it is no longer
1228c339a94Sopenharmony_ciguaranteed to be allocated.
1238c339a94Sopenharmony_ci
1248c339a94Sopenharmony_ci```cpp
1258c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::Abort() const
1268c339a94Sopenharmony_ci```
1278c339a94Sopenharmony_ci
1288c339a94Sopenharmony_ciReturns one of:
1298c339a94Sopenharmony_ci- `napi_ok`: The thread-safe function has been successfully aborted.
1308c339a94Sopenharmony_ci- `napi_invalid_arg`: The thread-safe function's thread-count is zero.
1318c339a94Sopenharmony_ci- `napi_generic_failure`: A generic error occurred when attempting to abort
1328c339a94Sopenharmony_cithe thread-safe function.
1338c339a94Sopenharmony_ci
1348c339a94Sopenharmony_ci### BlockingCall / NonBlockingCall
1358c339a94Sopenharmony_ci
1368c339a94Sopenharmony_ciCalls the Javascript function in either a blocking or non-blocking fashion.
1378c339a94Sopenharmony_ci- `BlockingCall()`: the API blocks until space becomes available in the queue.
1388c339a94Sopenharmony_ci  Will never block if the thread-safe function was created with a maximum queue
1398c339a94Sopenharmony_ci  size of `0`.
1408c339a94Sopenharmony_ci- `NonBlockingCall()`: will return `napi_queue_full` if the queue was full,
1418c339a94Sopenharmony_ci  preventing data from being successfully added to the queue.
1428c339a94Sopenharmony_ci
1438c339a94Sopenharmony_ciThere are several overloaded implementations of `BlockingCall()` and
1448c339a94Sopenharmony_ci`NonBlockingCall()` for use with optional parameters: skip the optional
1458c339a94Sopenharmony_ciparameter for that specific overload.
1468c339a94Sopenharmony_ci
1478c339a94Sopenharmony_ci**These specific function overloads should only be used on a `ThreadSafeFunction`
1488c339a94Sopenharmony_cicreated via `ThreadSafeFunction::New`.**
1498c339a94Sopenharmony_ci
1508c339a94Sopenharmony_ci```cpp
1518c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::BlockingCall(DataType* data, Callback callback) const
1528c339a94Sopenharmony_ci
1538c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::NonBlockingCall(DataType* data, Callback callback) const
1548c339a94Sopenharmony_ci```
1558c339a94Sopenharmony_ci
1568c339a94Sopenharmony_ci- `[optional] data`: Data to pass to `callback`.
1578c339a94Sopenharmony_ci- `[optional] callback`: C++ function that is invoked on the main thread. The
1588c339a94Sopenharmony_ci  callback receives the `ThreadSafeFunction`'s JavaScript callback function to
1598c339a94Sopenharmony_ci  call as an `Napi::Function` in its parameters and the `DataType*` data pointer
1608c339a94Sopenharmony_ci  (if provided). Must implement `void operator()(Napi::Env env, Function
1618c339a94Sopenharmony_ci  jsCallback, DataType* data)`, skipping `data` if not provided. It is not
1628c339a94Sopenharmony_ci  necessary to call into JavaScript via `MakeCallback()` because Node-API runs
1638c339a94Sopenharmony_ci  `callback` in a context appropriate for callbacks.
1648c339a94Sopenharmony_ci
1658c339a94Sopenharmony_ci**These specific function overloads should only be used on a `ThreadSafeFunction`
1668c339a94Sopenharmony_cicreated via `ThreadSafeFunction(napi_threadsafe_function)`.**
1678c339a94Sopenharmony_ci
1688c339a94Sopenharmony_ci```cpp
1698c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::BlockingCall(void* data) const
1708c339a94Sopenharmony_ci
1718c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::NonBlockingCall(void* data) const
1728c339a94Sopenharmony_ci```
1738c339a94Sopenharmony_ci- `data`: Data to pass to `call_js_cb` specified when creating the thread-safe
1748c339a94Sopenharmony_ci  function via `napi_create_threadsafe_function`.
1758c339a94Sopenharmony_ci
1768c339a94Sopenharmony_ciReturns one of:
1778c339a94Sopenharmony_ci- `napi_ok`: The call was successfully added to the queue.
1788c339a94Sopenharmony_ci- `napi_queue_full`: The queue was full when trying to call in a non-blocking
1798c339a94Sopenharmony_ci  method.
1808c339a94Sopenharmony_ci- `napi_closing`: The thread-safe function is aborted and cannot accept more
1818c339a94Sopenharmony_ci  calls.
1828c339a94Sopenharmony_ci- `napi_invalid_arg`: The thread-safe function is closed.
1838c339a94Sopenharmony_ci- `napi_generic_failure`: A generic error occurred when attempting to add to the
1848c339a94Sopenharmony_ci  queue.
1858c339a94Sopenharmony_ci
1868c339a94Sopenharmony_ci## Example
1878c339a94Sopenharmony_ci
1888c339a94Sopenharmony_ci```cpp
1898c339a94Sopenharmony_ci#include <chrono>
1908c339a94Sopenharmony_ci#include <thread>
1918c339a94Sopenharmony_ci#include <napi.h>
1928c339a94Sopenharmony_ci
1938c339a94Sopenharmony_ciusing namespace Napi;
1948c339a94Sopenharmony_ci
1958c339a94Sopenharmony_cistd::thread nativeThread;
1968c339a94Sopenharmony_ciThreadSafeFunction tsfn;
1978c339a94Sopenharmony_ci
1988c339a94Sopenharmony_ciValue Start( const CallbackInfo& info )
1998c339a94Sopenharmony_ci{
2008c339a94Sopenharmony_ci  Napi::Env env = info.Env();
2018c339a94Sopenharmony_ci
2028c339a94Sopenharmony_ci  if ( info.Length() < 2 )
2038c339a94Sopenharmony_ci  {
2048c339a94Sopenharmony_ci    throw TypeError::New( env, "Expected two arguments" );
2058c339a94Sopenharmony_ci  }
2068c339a94Sopenharmony_ci  else if ( !info[0].IsFunction() )
2078c339a94Sopenharmony_ci  {
2088c339a94Sopenharmony_ci    throw TypeError::New( env, "Expected first arg to be function" );
2098c339a94Sopenharmony_ci  }
2108c339a94Sopenharmony_ci  else if ( !info[1].IsNumber() )
2118c339a94Sopenharmony_ci  {
2128c339a94Sopenharmony_ci    throw TypeError::New( env, "Expected second arg to be number" );
2138c339a94Sopenharmony_ci  }
2148c339a94Sopenharmony_ci
2158c339a94Sopenharmony_ci  int count = info[1].As<Number>().Int32Value();
2168c339a94Sopenharmony_ci
2178c339a94Sopenharmony_ci  // Create a ThreadSafeFunction
2188c339a94Sopenharmony_ci  tsfn = ThreadSafeFunction::New(
2198c339a94Sopenharmony_ci      env,
2208c339a94Sopenharmony_ci      info[0].As<Function>(),  // JavaScript function called asynchronously
2218c339a94Sopenharmony_ci      "Resource Name",         // Name
2228c339a94Sopenharmony_ci      0,                       // Unlimited queue
2238c339a94Sopenharmony_ci      1,                       // Only one thread will use this initially
2248c339a94Sopenharmony_ci      []( Napi::Env ) {        // Finalizer used to clean threads up
2258c339a94Sopenharmony_ci        nativeThread.join();
2268c339a94Sopenharmony_ci      } );
2278c339a94Sopenharmony_ci
2288c339a94Sopenharmony_ci  // Create a native thread
2298c339a94Sopenharmony_ci  nativeThread = std::thread( [count] {
2308c339a94Sopenharmony_ci    auto callback = []( Napi::Env env, Function jsCallback, int* value ) {
2318c339a94Sopenharmony_ci      // Transform native data into JS data, passing it to the provided
2328c339a94Sopenharmony_ci      // `jsCallback` -- the TSFN's JavaScript function.
2338c339a94Sopenharmony_ci      jsCallback.Call( {Number::New( env, *value )} );
2348c339a94Sopenharmony_ci
2358c339a94Sopenharmony_ci      // We're finished with the data.
2368c339a94Sopenharmony_ci      delete value;
2378c339a94Sopenharmony_ci    };
2388c339a94Sopenharmony_ci
2398c339a94Sopenharmony_ci    for ( int i = 0; i < count; i++ )
2408c339a94Sopenharmony_ci    {
2418c339a94Sopenharmony_ci      // Create new data
2428c339a94Sopenharmony_ci      int* value = new int( clock() );
2438c339a94Sopenharmony_ci
2448c339a94Sopenharmony_ci      // Perform a blocking call
2458c339a94Sopenharmony_ci      napi_status status = tsfn.BlockingCall( value, callback );
2468c339a94Sopenharmony_ci      if ( status != napi_ok )
2478c339a94Sopenharmony_ci      {
2488c339a94Sopenharmony_ci        // Handle error
2498c339a94Sopenharmony_ci        break;
2508c339a94Sopenharmony_ci      }
2518c339a94Sopenharmony_ci
2528c339a94Sopenharmony_ci      std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
2538c339a94Sopenharmony_ci    }
2548c339a94Sopenharmony_ci
2558c339a94Sopenharmony_ci    // Release the thread-safe function
2568c339a94Sopenharmony_ci    tsfn.Release();
2578c339a94Sopenharmony_ci  } );
2588c339a94Sopenharmony_ci
2598c339a94Sopenharmony_ci  return Boolean::New(env, true);
2608c339a94Sopenharmony_ci}
2618c339a94Sopenharmony_ci
2628c339a94Sopenharmony_ciNapi::Object Init( Napi::Env env, Object exports )
2638c339a94Sopenharmony_ci{
2648c339a94Sopenharmony_ci  exports.Set( "start", Function::New( env, Start ) );
2658c339a94Sopenharmony_ci  return exports;
2668c339a94Sopenharmony_ci}
2678c339a94Sopenharmony_ci
2688c339a94Sopenharmony_ciNODE_API_MODULE( clock, Init )
2698c339a94Sopenharmony_ci```
2708c339a94Sopenharmony_ci
2718c339a94Sopenharmony_ciThe above code can be used from JavaScript as follows:
2728c339a94Sopenharmony_ci
2738c339a94Sopenharmony_ci```js
2748c339a94Sopenharmony_ciconst { start } = require('bindings')('clock');
2758c339a94Sopenharmony_ci
2768c339a94Sopenharmony_cistart(function () {
2778c339a94Sopenharmony_ci    console.log("JavaScript callback called with arguments", Array.from(arguments));
2788c339a94Sopenharmony_ci}, 5);
2798c339a94Sopenharmony_ci```
2808c339a94Sopenharmony_ci
2818c339a94Sopenharmony_ciWhen executed, the output will show the value of `clock()` five times at one
2828c339a94Sopenharmony_cisecond intervals:
2838c339a94Sopenharmony_ci
2848c339a94Sopenharmony_ci```
2858c339a94Sopenharmony_ciJavaScript callback called with arguments [ 84745 ]
2868c339a94Sopenharmony_ciJavaScript callback called with arguments [ 103211 ]
2878c339a94Sopenharmony_ciJavaScript callback called with arguments [ 104516 ]
2888c339a94Sopenharmony_ciJavaScript callback called with arguments [ 105104 ]
2898c339a94Sopenharmony_ciJavaScript callback called with arguments [ 105691 ]
2908c339a94Sopenharmony_ci```
291