Skip to content

Deadlock when using FindComponent(s) with WaitForX #577

@rmihael

Description

@rmihael

Today we started to see random hang-ups while running bUnit tests. After some debugging, it boiled down to these two threads mutually locking each other:

Worker thread @33878491
	Monitor.Enter() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/3da0403ae6e540a7a79283e509f3945b8d7e00/18E/Monitor.cs:line 48
	TestRenderer.FindComponents<SolidCube.Components.Shared.TreeItem>() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/8adb50b4d399477b881862854de9b0cb13c00/26/TestRenderer.cs:line 251
	TestRenderer.FindComponents<SolidCube.Components.Shared.TreeItem>() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/8adb50b4d399477b881862854de9b0cb13c00/26/TestRenderer.cs:line 111
	RenderedFragmentExtensions.FindComponents<SolidCube.Components.Shared.TreeItem>() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/b1aaada6d19e4b1a9a6620aa89b26c4b2aa00/27/RenderedFragmentExtensions.cs:line 83
	RenderedComponentExtensions.<>c__DisplayClass1_0<TreeItem>.<WaitForComponents>b__0()
	WaitForAssertionHelper.<>c__DisplayClass6_0.<.ctor>b__0()
	WaitForHelper<object>.OnAfterRender() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/8adb50b4d399477b881862854de9b0cb13c00/14/WaitForHelper.cs:line 106
	new WaitForHelper<object>() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/8adb50b4d399477b881862854de9b0cb13c00/14/WaitForHelper.cs:line 73
	new WaitForAssertionHelper()
	RenderedFragmentWaitForHelperExtensions.WaitForAssertion()
	RenderedComponentExtensions.WaitForComponents<SolidCube.Components.Shared.TreeItem>()
Worker thread @33878451
	Monitor.Enter() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/3da0403ae6e540a7a79283e509f3945b8d7e00/18E/Monitor.cs:line 48
	WaitForHelper<object>.OnAfterRender() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/8adb50b4d399477b881862854de9b0cb13c00/14/WaitForHelper.cs:line 97
	RenderedFragment.Bunit.IRenderedFragmentBase.OnRender() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/b1aaada6d19e4b1a9a6620aa89b26c4b2aa00/4A/RenderedFragment.cs:line 158
	TestRenderer.UpdateDisplayAsync()
	Renderer.ProcessRenderQueue()
	Renderer.ProcessPendingRender() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/28489e7a98534715a55deed8cf7572df6b200/3E/Renderer.cs:line 438
	TestRenderer.ProcessPendingRender() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/8adb50b4d399477b881862854de9b0cb13c00/26/TestRenderer.cs:line 125
	Renderer.DispatchEventAsync() at /Users/rmihael/Library/Application Support/JetBrains/Rider2021.2/resharper-host/SourcesCache/28489e7a98534715a55deed8cf7572df6b200/3E/Renderer.cs:line 285
	TestRenderer.<>n__0()
	TestRenderer.<>c__DisplayClass15_0.<DispatchEventAsync>b__0()
	RendererSynchronizationContext.<>c.<<InvokeAsync>b__9_0>d.MoveNext()
	AsyncMethodBuilderCore.Start<Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c.<<InvokeAsync>b__9_0>d>()
	AsyncVoidMethodBuilder.Start<Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c.<<InvokeAsync>b__9_0>d>()
	RendererSynchronizationContext.<>c.<InvokeAsync>b__9_0()
	RendererSynchronizationContext.ExecuteSynchronously()
	RendererSynchronizationContext.<>c.<.cctor>b__23_0()
	ExecutionContext.RunInternal()
	ExecutionContext.Run()
	RendererSynchronizationContext.ExecuteBackground()
	RendererSynchronizationContext.<>c.<.cctor>b__23_1()
	ContinuationTaskFromTask.InnerInvoke()
	Task.<>c.<.cctor>b__277_0()
	ExecutionContext.RunFromThreadPoolDispatchLoop()
	Task.ExecuteWithThreadLocal()
	Task.ExecuteEntryUnsafe()
	Task.ExecuteFromThreadPool()
	ThreadPoolWorkQueue.Dispatch()
	_ThreadPoolWaitCallback.PerformWaitCallback()
	[Native to Managed Transition]

It seems that Renderer.DispatchEventAsync calls TestRenderer.ProcessPendingRender which locks TestRenderer.renderTreeAccessLock and then proceed to WaitForHelper.OnAfterRender where it waits on WaitForHelder.lockObject. On the other thread WaitForHelper.OnAfterRender locks WaitForHelper.lockObject and then proceeds to TestRenderer.FindComponents where it waits for TestRenderer.renderTreeAccessLock.

Version info:

  • bUnit version: 1.3.42
  • .NET Runtime and Blazor version: .NET 5.0.402, AspNetCore 5.0.8
  • OS type and version: MacOS 11.5.2

Additional context:

We saw hang-ups sporadically before, but now they are very consistent. It happened after we replaced Blazor.EventsAggregator dependency with native C# events. Many methods that were async before now sync, possibly resulting in a more deterministic flow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions