Open MackinnonBuck opened 3 weeks ago
Tagging subscribers to 'arch-wasm': @lewing See info in area-owners.md if you want to be subscribed.
Most probably connected with https://github.com/dotnet/runtime/issues/104772. I am gonna check if the fix is backporting https://github.com/dotnet/runtime/pull/105464
@ilonatommy, I realized my original comment mentioned ".NET 8 Preview 7", but I actually meant ".NET 9 Preview 7". Sorry if that created any confusion!
I just tried the repro again from the latest main
installer in this table, which should contain the fix from #105464, and the problem still reproduces for me.
@pavelsavara, the problem is real and can be reproduced by using the threading sample on main.
The minimal requirement is async JsImport
(triggering threads without interop does not deadlock, e.g. exchanging
await JS.GetEmptyPromiseAsync();
for
await Task.Run(async ()=>{ JS.Log($"ID: {Environment.CurrentManagedThreadId}"); });
works fine),
and reloading the page. Calling async JsImport
function without re-initializing the threads (no page reload) does not deadlock either.
this one is updated version of the truncated one, I caught the same place again.
my theory: all 3 screenshots are showing
memory.growth()
to UI thread from inside locked allocator@kg
It could be also problem in emscripten code.
Allocation happens with inside do_proxy() -> get_or_add_tasks_for_thread()
inside of pthread_mutex_lock(&q->mutex);
But it seems to me that in our case, the target queue is queue of IO thread, not the UI thread.
More stacks (same stack result was produced in several different runs, the only difference - non-truncated last thread dump. I stop collecting): main [0]
deputy [1]
IO [2]
norm [3]
pool [4] won't break
gate [5]
emscripten pool [6] won't break, the only one that is not running (last log of thread dump when the app was running)
After the app froze, dump of threads:
Description
When
<WasmEnableThreads>
is set totrue
, awaiting aTask
returned by a[JSImport]
method may cause a deadlock, even if the associated JSPromise
is just aPromise.resolve()
.This is likely the cause of the following test failures we've been seeing in dotnet/aspnetcore:
When I repro'd the failures locally, the test app was deadlocking in an interop call made by the framework here.
However, a much simpler scenario can reproduce the same issue. Here's some of the code from my minimal repro project:
This repeatedly reloads the page until the deadlock occurs. On my machine, the deadlock happens within ~10 refreshes.
Reproduction Steps
dotnet workload install wasm-tools --include-previews
dotnet workload install wasm-experimental --include-previews
dotnet tool install dotnet-serve
dotnet publish
wwwroot
folder in the published output, run:dotnet serve -h "Cross-Origin-Embedder-Policy:require-corp" -h "Cross-Origin-Opener-Policy:same-origin"
Expected behavior
A deadlock does not happen, and the webpage continues to refresh indefinitely.
Actual behavior
The page freezes within ~10 page reloads.
Regression?
Unsure - I unfortunately wasn't able to get the repro to run on a .NET 8 TFM and SDK.
Known Workarounds
No response
Configuration
.NET SDK:
OS
Windows 11 Enterprise 23H2
Architecture
x64
Do you know whether it is specific to that configuration?
No
Which web browser(s) do you see this issue in?
I was able to repro this in:
Other information
No response