Skip to content

Commit 87a78f2

Browse files
committed
fix: add deadlock prevention mechanism
1 parent 9de74e6 commit 87a78f2

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

packages/host/cpp/ThreadsafeFunction.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,33 @@ napi_status ThreadSafeFunction::call(
127127
if (isBlocking == napi_tsfn_nonblocking) {
128128
return napi_queue_full;
129129
}
130-
queueCv_.wait(lock, [&] {
131-
return queue_.size() < maxQueueSize_ || isClosingOrAborted();
132-
});
133-
if (isClosingOrAborted()) return napi_closing;
130+
131+
// In blocking mode with full queue: process queue immediately to avoid
132+
// deadlock when called from JS thread. Release lock during processing.
133+
lock.unlock();
134+
const auto invoker = callInvoker_.lock();
135+
if (invoker) {
136+
invoker->invokeSync(
137+
[self = shared_from_this()] { self->processQueue(); });
138+
}
139+
lock.lock();
140+
141+
// After processing, wait if queue is still full
142+
if (maxQueueSize_ && queue_.size() >= maxQueueSize_) {
143+
queueCv_.wait(lock, [&] {
144+
return queue_.size() < maxQueueSize_ || isClosingOrAborted();
145+
});
146+
// Re-check conditions after waiting
147+
if (isClosingOrAborted()) return napi_closing;
148+
// Double-check queue size in case of spurious wakeup or race condition
149+
if (maxQueueSize_ && queue_.size() >= maxQueueSize_) {
150+
return napi_queue_full;
151+
}
152+
}
153+
}
154+
// Final check before pushing - ensure we're not closing and have space
155+
if (isClosingOrAborted()) {
156+
return napi_closing;
134157
}
135158
queue_.push(data);
136159
}

0 commit comments

Comments
 (0)