Skip to content

Commit 53b498d

Browse files
committed
chore: improved comments + cleanup
1 parent 2879b75 commit 53b498d

File tree

2 files changed

+19
-26
lines changed

2 files changed

+19
-26
lines changed

packages/host/cpp/ThreadsafeFunction.cpp

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,14 @@
22
#include <unordered_map>
33
#include "Logger.hpp"
44

5-
// This file provides a React Native-friendly implementation of Node-API's
6-
// thread-safe function primitive. In RN we don't own/libuv, so we:
7-
// - Use CallInvoker to hop onto the JS thread instead of uv_async.
8-
// - Track a registry mapping unique IDs to shared_ptrs for lookup/lifetime.
9-
// - Emulate ref/unref semantics without affecting any event loop.
10-
5+
// Global registry to map unique IDs to ThreadSafeFunction instances.
6+
// We use IDs instead of raw pointers to avoid any use-after-free issues.
117
static std::unordered_map<std::uintptr_t,
128
std::shared_ptr<callstack::nodeapihost::ThreadSafeFunction>>
139
registry;
1410
static std::mutex registryMutex;
1511
static std::atomic<std::uintptr_t> nextId{1};
1612

17-
// Constants for better readability
1813
static constexpr size_t INITIAL_REF_COUNT = 1;
1914

2015
namespace callstack::nodeapihost {
@@ -44,13 +39,10 @@ ThreadSafeFunction::ThreadSafeFunction(
4439
context_{context},
4540
callJsCb_{callJsCb} {
4641
if (jsFunc) {
47-
// Keep JS function alive across async hops; fatal here mirrors Node-API's
48-
// behavior when environment is irrecoverable.
42+
// Keep JS function alive across async hops
4943
const auto status =
5044
napi_create_reference(env, jsFunc, INITIAL_REF_COUNT, &jsFuncRef_);
5145
if (status != napi_ok) {
52-
// Consider throwing an exception instead of fatal error in future
53-
// versions
5446
napi_fatal_error(nullptr,
5547
0,
5648
"Failed to create JS function reference",
@@ -101,6 +93,7 @@ std::shared_ptr<ThreadSafeFunction> ThreadSafeFunction::create(
10193
std::shared_ptr<ThreadSafeFunction> ThreadSafeFunction::get(
10294
napi_threadsafe_function func) {
10395
std::lock_guard lock{registryMutex};
96+
// Cast the handle back to ID for registry lookup
10497
const auto id = reinterpret_cast<std::uintptr_t>(func);
10598
const auto it = registry.find(id);
10699
return it != registry.end() ? it->second : nullptr;
@@ -120,7 +113,7 @@ napi_status ThreadSafeFunction::getContext(void** result) noexcept {
120113
}
121114

122115
napi_status ThreadSafeFunction::call(
123-
void* data, napi_threadsafe_function_call_mode isBlocking) {
116+
void* data, napi_threadsafe_function_call_mode isBlocking) noexcept {
124117
if (isClosingOrAborted()) {
125118
return napi_closing;
126119
}
@@ -152,7 +145,7 @@ napi_status ThreadSafeFunction::call(
152145
return napi_ok;
153146
}
154147

155-
napi_status ThreadSafeFunction::acquire() {
148+
napi_status ThreadSafeFunction::acquire() noexcept {
156149
if (closing_.load(std::memory_order_acquire)) {
157150
return napi_closing;
158151
}
@@ -161,7 +154,7 @@ napi_status ThreadSafeFunction::acquire() {
161154
}
162155

163156
napi_status ThreadSafeFunction::release(
164-
napi_threadsafe_function_release_mode mode) {
157+
napi_threadsafe_function_release_mode mode) noexcept {
165158
// Node-API semantics: abort prevents further JS calls and wakes any waiters.
166159
if (mode == napi_tsfn_abort) {
167160
aborted_.store(true, std::memory_order_relaxed);
@@ -185,8 +178,8 @@ napi_status ThreadSafeFunction::release(
185178
}
186179

187180
napi_status ThreadSafeFunction::ref() noexcept {
188-
// In libuv, this would keep the loop alive. In RN we don't own or expose a
189-
// libuv loop. We just track the state for API parity.
181+
// In libuv, this allows the loop to exit if nothing else is keeping it
182+
// alive. In RN this is a no-op beyond state tracking.
190183
referenced_.store(true, std::memory_order_relaxed);
191184
return napi_ok;
192185
}
@@ -199,6 +192,7 @@ napi_status ThreadSafeFunction::unref() noexcept {
199192
}
200193

201194
void ThreadSafeFunction::finalize() {
195+
// Ensure finalization happens exactly once
202196
bool expected = false;
203197
if (!finalizeScheduled_.compare_exchange_strong(
204198
expected, true, std::memory_order_acq_rel)) {
@@ -208,7 +202,6 @@ void ThreadSafeFunction::finalize() {
208202
closing_.store(true, std::memory_order_release);
209203

210204
const auto onFinalize = [self = shared_from_this()] {
211-
// Invoke user finalizer and unregister the handle from the global map.
212205
if (self->threadFinalizeCb_) {
213206
self->threadFinalizeCb_(
214207
self->env_, self->threadFinalizeData_, self->context_);
@@ -249,12 +242,14 @@ void ThreadSafeFunction::processQueue() {
249242
// Execute JS callback if we have data and aren't aborted
250243
if (queuedData && !aborted_.load(std::memory_order_relaxed)) {
251244
if (callJsCb_) {
245+
// Prefer the user-provided callJsCb_ (Node-API compatible)
252246
napi_value fn{nullptr};
253247
if (jsFuncRef_) {
254248
napi_get_reference_value(env_, jsFuncRef_, &fn);
255249
}
256250
callJsCb_(env_, fn, context_, queuedData);
257251
} else if (jsFuncRef_) {
252+
// Fallback: call JS function directly with no args
258253
napi_value fn{nullptr};
259254
if (napi_get_reference_value(env_, jsFuncRef_, &fn) == napi_ok) {
260255
napi_value recv{nullptr};
@@ -271,14 +266,13 @@ void ThreadSafeFunction::processQueue() {
271266
}
272267
}
273268

274-
[[nodiscard]] bool ThreadSafeFunction::isClosingOrAborted() const noexcept {
269+
bool ThreadSafeFunction::isClosingOrAborted() const noexcept {
275270
return aborted_.load(std::memory_order_relaxed) ||
276271
closing_.load(std::memory_order_relaxed);
277272
}
278273

279-
[[nodiscard]] bool ThreadSafeFunction::shouldFinalize() const noexcept {
274+
bool ThreadSafeFunction::shouldFinalize() const noexcept {
280275
return threadCount_.load(std::memory_order_acquire) == 0 &&
281276
!closing_.load(std::memory_order_acquire);
282277
}
283-
284-
} // namespace callstack::nodeapihost
278+
} // namespace callstack::nodeapihost

packages/host/cpp/ThreadsafeFunction.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,10 @@ class ThreadSafeFunction
4343
[[nodiscard]] napi_threadsafe_function getHandle() const noexcept;
4444
[[nodiscard]] napi_status getContext(void** result) noexcept;
4545
[[nodiscard]] napi_status call(
46-
void* data, napi_threadsafe_function_call_mode isBlocking);
47-
[[nodiscard]] napi_status acquire();
48-
[[nodiscard]] napi_status release(napi_threadsafe_function_release_mode mode);
49-
// Node-API compatibility: These do not affect RN's lifecycle. We only track
50-
// the state for diagnostics and API parity with libuv's ref/unref.
46+
void* data, napi_threadsafe_function_call_mode isBlocking) noexcept;
47+
[[nodiscard]] napi_status acquire() noexcept;
48+
[[nodiscard]] napi_status release(
49+
napi_threadsafe_function_release_mode mode) noexcept;
5150
[[nodiscard]] napi_status ref() noexcept;
5251
[[nodiscard]] napi_status unref() noexcept;
5352

0 commit comments

Comments
 (0)