Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

napi_call_threadsafe_function should error if called from the main thread #32615

Closed
josephg opened this issue Apr 2, 2020 · 6 comments
Closed
Labels
node-api Issues and PRs related to the Node-API.

Comments

@josephg
Copy link
Contributor

josephg commented Apr 2, 2020

I spent the last few hours tracking down a deadlock one of my users was running into with my library. It was 100% a bug in my code - but I think napi could pretty easily protect module writers against the mistake I was making.

The problem was it turns out that (sometimes) I've been calling napi_call_threadsafe_function(fn, ctx, napi_tsfn_blocking) from nodejs's main thread. The problem is if you call that function with napi_tsfn_blocking when the queue is full, nodejs's main thread will end up deadlocked. (The call to call_threadsafe_function will block until there's room in the queue - but it can't clear room in the queue while its blocking waiting for room.)

Anyway, I think we should add a check in ThreadsafeFunction::Push to return an error if:

  • Its called from nodejs's main thread.
  • Its called with napi_tsfn_blocking, and the queue has limited size

This would have saved me some time; and I suspect I'm not the only one who will accidentally misuse napi_call_threadsafe_function and land in trouble.

The compatibility constraints on this are interesting - its always wrong to call call_threadsafe_function like this, but many programs will run for awhile anyway, timebomb and all.

@legendecas legendecas added the node-api Issues and PRs related to the Node-API. label Apr 2, 2020
@himself65
Copy link
Member

himself65 commented Apr 2, 2020

the reason I think is when ThreadSafeFunction (tsfn) called by the main thread and the queue
also happened full, so deadlock appears.

for short, wait and notify are called by the same thread

cond->Wait(lock);

@josephg
Copy link
Contributor Author

josephg commented Apr 2, 2020

Yes. Another option would be to call the JS function immediately without putting it in the queue. That would stop the deadlock behaviour but it breaks the (implicit?) contract that order is preserved between calls to napi_call_tsfn and JavaScript. (Although if you’re calling napi_call_tsfn from multiple threads you can’t really preserve order anyway, because there’s no guarantee of thread execution order.)

@bnoordhuis
Copy link
Member

cc @gabrielschulhof

@gabrielschulhof
Copy link
Contributor

@nodejs/n-api we should discuss this during our next meeting.

@gabrielschulhof
Copy link
Contributor

@josephg dequeuing one item synchronously to make room for the incoming item might be one solution ...

@josephg
Copy link
Contributor Author

josephg commented Apr 4, 2020

Could be; but that sounds complicated. And the javascript code you call might synchronously queue another item or two in turn.

gabrielschulhof pushed a commit to gabrielschulhof/node that referenced this issue Apr 9, 2020
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.

PR-URL: nodejs#32689
Fixes: nodejs#32615
Signed-off-by: Gabriel Schulhof <[email protected]>
targos pushed a commit that referenced this issue Apr 12, 2020
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.

PR-URL: #32689
Fixes: #32615
Signed-off-by: Gabriel Schulhof <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: David Carlier <[email protected]>
Reviewed-By: Chengzhong Wu <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
BethGriggs pushed a commit that referenced this issue Apr 14, 2020
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.

PR-URL: #32689
Fixes: #32615
Signed-off-by: Gabriel Schulhof <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: David Carlier <[email protected]>
Reviewed-By: Chengzhong Wu <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
gabrielschulhof pushed a commit to gabrielschulhof/node that referenced this issue Apr 16, 2020
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: nodejs#32615
Signed-off-by: Gabriel Schulhof <[email protected]>
gabrielschulhof pushed a commit that referenced this issue Apr 19, 2020
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: #32615
Signed-off-by: Gabriel Schulhof <[email protected]>
PR-URL: #32860
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
Reviewed-By: Zeyu Yang <[email protected]>
gabrielschulhof pushed a commit to gabrielschulhof/node that referenced this issue Apr 20, 2020
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: nodejs#32615
Signed-off-by: Gabriel Schulhof <[email protected]>
PR-URL: nodejs#32860
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
Reviewed-By: Zeyu Yang <[email protected]>
BethGriggs pushed a commit that referenced this issue Apr 27, 2020
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: #32615
Signed-off-by: Gabriel Schulhof <[email protected]>
PR-URL: #32860
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
Reviewed-By: Zeyu Yang <[email protected]>
targos pushed a commit that referenced this issue Apr 28, 2020
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: #32615
Signed-off-by: Gabriel Schulhof <[email protected]>
PR-URL: #32860
Backport-PR-URL: #32948
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
Reviewed-By: Zeyu Yang <[email protected]>
targos pushed a commit that referenced this issue Apr 30, 2020
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: #32615
Signed-off-by: Gabriel Schulhof <[email protected]>
PR-URL: #32860
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
Reviewed-By: Zeyu Yang <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
node-api Issues and PRs related to the Node-API.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants