Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schulhof <gabriel.schulhof@intel.com>2020-04-06 20:16:15 +0300
committerGabriel Schulhof <gabriel.schulhof@intel.com>2020-04-19 20:07:00 +0300
commitd26ca06c16f497ffa5ac4845a27922d5058a9318 (patch)
tree1ebcc99e42c0cb6f3d98fc52d801f6abc81ed0d6 /src/node_api.cc
parent250060a0509204031ae068a5aa90e3481c1a78ae (diff)
n-api: detect deadlocks in thread-safe function
We introduce status `napi_would_deadlock` to be used as a return status by `napi_call_threadsafe_function` if the call is made with `napi_tsfn_blocking` on the main thread and the queue is full. Fixes: https://github.com/nodejs/node/issues/32615 Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com> PR-URL: https://github.com/nodejs/node/pull/32860 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Zeyu Yang <himself65@outlook.com>
Diffstat (limited to 'src/node_api.cc')
-rw-r--r--src/node_api.cc23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/node_api.cc b/src/node_api.cc
index fad9cf72a97..cb8bd4b4823 100644
--- a/src/node_api.cc
+++ b/src/node_api.cc
@@ -155,6 +155,29 @@ class ThreadSafeFunction : public node::AsyncResource {
if (mode == napi_tsfn_nonblocking) {
return napi_queue_full;
}
+
+ // Here we check if there is a Node.js event loop running on this thread.
+ // If there is, and our queue is full, we return `napi_would_deadlock`. We
+ // do this for two reasons:
+ //
+ // 1. If this is the thread on which our own event loop runs then we
+ // cannot wait here because that will prevent our event loop from
+ // running and emptying the very queue on which we are waiting.
+ //
+ // 2. If this is not the thread on which our own event loop runs then we
+ // still cannot wait here because that allows the following sequence of
+ // events:
+ //
+ // 1. JSThread1 calls JSThread2 and blocks while its queue is full and
+ // because JSThread2's queue is also full.
+ //
+ // 2. JSThread2 calls JSThread1 before it's had a chance to remove an
+ // item from its own queue and blocks because JSThread1's queue is
+ // also full.
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ if (isolate != nullptr && node::GetCurrentEventLoop(isolate) != nullptr)
+ return napi_would_deadlock;
+
cond->Wait(lock);
}