Skip to content

[dylink] Fix deadlock in _emscripten_dlsync_threads()#27000

Open
kleisauke wants to merge 3 commits into
emscripten-core:mainfrom
kleisauke:issue-26913-fix
Open

[dylink] Fix deadlock in _emscripten_dlsync_threads()#27000
kleisauke wants to merge 3 commits into
emscripten-core:mainfrom
kleisauke:issue-26913-fix

Conversation

@kleisauke
Copy link
Copy Markdown
Collaborator

@kleisauke kleisauke commented May 23, 2026

This extends commit 662cb06 by ensuring _emscripten_thread_notify()
is also called for the synchronous _emscripten_dlsync_threads()
path. This ensures that threads process the dlopen catch-up queue
promptly, even when blocked in emscripten_futex_wait().

To implement this cleanly, dlopen_proxying_queue is moved from a
dynamic pointer in dynlink.c to a statically initialized queue in
proxying.c.

Fixes: #26913.

Comment thread system/lib/pthread/proxying.c Outdated
DBG("waking main runtime thread using _emscripten_thread_notify");
if (ret) {
// Wake up the target thread in case it is blocked in
// `emscripten_futex_wait`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is little confusing (and maybe wasteful) though since normal pthread do not run their proxy queue in emscripten_yield, and therefore wakeing them them up should not be needed.

pthreads do however call _emscripten_process_dlopen_queue from emscripten_yield .. so it should only be necessary to wake them up if/when need need to call _emscripten_process_dlopen_queue, and not whereever work gets proxied to them.

Copy link
Copy Markdown
Collaborator Author

@kleisauke kleisauke May 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if _emscripten_thread_notify() is actually that expensive, since it already returns early when the thread isn't waiting.

I tried limiting this notify to the dlopen() proxying queue with commit 72cb72a, but reintroducing && pthread_equal(target_thread, emscripten_main_runtime_thread_id()) regressed this again.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pthreads do however call _emscripten_process_dlopen_queue from emscripten_yield [...]

I think that's probably why reintroducing && pthread_equal(target_thread, emscripten_main_runtime_thread_id()) caused this regression again, as the queue is processed from pthreads rather than from the main runtime thread.

sbc100 pushed a commit that referenced this pull request May 23, 2026
kleisauke added 3 commits May 23, 2026 22:39
This extends commit 662cb06 by ensuring `_emscripten_thread_notify()`
is also called for the synchronous `_emscripten_dlsync_threads()`
path. This ensures that threads process the dlopen catch-up queue
promptly, even when blocked in `emscripten_futex_wait()`.

To implement this cleanly, `dlopen_proxying_queue` is moved from a
dynamic pointer in `dynlink.c` to a statically initialized queue in
`proxying.c`.

Fixes: emscripten-core#26913.
This is an automatic change generated by tools/maint/rebaseline_tests.py.

The following (2) test expectation files were updated by
running the tests with `--rebaseline`:

```
codesize/test_codesize_minimal_pthreads.json: 26180 => 26179 [-1 bytes / -0.00%]
codesize/test_codesize_minimal_pthreads_memgrowth.json: 26589 => 26588 [-1 bytes / -0.00%]

Average change: -0.00% (-0.00% - -0.00%)
```
@kleisauke kleisauke changed the title [dylink] Fix deadlock in synchronous _emscripten_dlsync_threads() path [dylink] Fix deadlock in _emscripten_dlsync_threads() May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Possible deadlock in _emscripten_dlsync_threads() since #26659

2 participants