dotnet / corert

This repo contains CoreRT, an experimental .NET Core runtime optimized for AOT (ahead of time compilation) scenarios, with the accompanying compiler toolchain.
http://dot.net
MIT License
2.91k stars 508 forks source link

Main thread Thread::WaitForGC infinitely #8308

Open ryancheung opened 4 years ago

ryancheung commented 4 years ago

I had a demo MonoGame 3.8 game project and try CoreRT with it.

The game use two thread loops, one is a background thread for sending draw commands to a ConcurrentQueue, another is the game loop in main thread that receive draw commands from ConcurrentQueue and draw the game.

After compiled with CoreRT and run, the window just freezed and nothing was showed. Then I debug it with vscode and it seems the Main thread stuck on Thread::WaitForGC, sometimes stuck on ThreadStore::WaitForSuspendComplete.

I've noticed that the background thread, which is MirGameTemplate.WindowsDX.exe!MirEngine_MirEngine_GameBase__ActiveSceneDrawLoop() in the following stack trace, is not suspended and is running in a intential inifinite loop. If I put a Thread.Sleep(1) in this loop then everything is working.

Here is a stack trace of threads:

Main Thread

ntdll.dll!00007fff7bb6be44() (未知源:0)
KernelBase.dll!00007fff795626ee() (未知源:0)
MirGameTemplate.WindowsDX.exe!Thread::WaitForGC(void * pTransitionFrame) Line 89 (e:\a\_work\103\s\corert_4026918\src\native\runtime\thread.cpp:89)
MirGameTemplate.WindowsDX.exe!RhpWaitForGC2(PInvokeTransitionFrame * pFrame) Line 979 (e:\a\_work\103\s\corert_4026918\src\native\runtime\thread.cpp:979)
MirGameTemplate.WindowsDX.exe!RhpWaitForGCNoAbort() Line 84 (e:\A\_work\103\s\corert_4026918\src\Native\Runtime\amd64\PInvoke.asm:84)
MirGameTemplate.WindowsDX.exe!RhpWaitForGC() Line 114 (e:\A\_work\103\s\corert_4026918\src\Native\Runtime\amd64\PInvoke.asm:114)
MirGameTemplate.WindowsDX.exe!Internal_CompilerGenerated__Module___<Calli>UnmanagedCallingConventionStdCall, Static<Int32__S_P_CoreLib_System_Void<Pointer>__S_P_CoreLib_System_Void<Pointer>__S_P_CoreLib_System_Void<Pointer>__S_P_CoreLib_System_Void<Pointer>>() (未知源:0)
MirGameTemplate.WindowsDX.exe!SharpDX_Direct3D11_SharpDX_Direct3D11_Device__CreateBuffer() (未知源:0)
MirGameTemplate.WindowsDX.exe!SharpDX_Direct3D11_SharpDX_Direct3D11_Buffer___ctor_2() (未知源:0)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Graphics_VertexBuffer__GenerateIfRequired() Line 49 (d:\MonoGame\MonoGame\MonoGame.Framework\Platform\Graphics\Vertices\VertexBuffer.DirectX.cs:49)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Graphics_GraphicsDevice__SetUserVertexBuffer<MonoGame_Framework_Microsoft_Xna_Framework_Graphics_VertexPositionColorTexture>() Line 1385 (d:\MonoGame\MonoGame\MonoGame.Framework\Platform\Graphics\GraphicsDevice.DirectX.cs:1385)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Graphics_GraphicsDevice__PlatformDrawUserIndexedPrimitives<MonoGame_Framework_Microsoft_Xna_Framework_Graphics_VertexPositionColorTexture>() Line 1502 (d:\MonoGame\MonoGame\MonoGame.Framework\Platform\Graphics\GraphicsDevice.DirectX.cs:1502)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Graphics_GraphicsDevice__DrawUserIndexedPrimitives_0<MonoGame_Framework_Microsoft_Xna_Framework_Graphics_VertexPositionColorTexture>() Line 1218 (d:\MonoGame\MonoGame\MonoGame.Framework\Graphics\GraphicsDevice.cs:1218)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Graphics_SpriteBatcher__FlushVertexArray() Line 285 (d:\MonoGame\MonoGame\MonoGame.Framework\Graphics\SpriteBatcher.cs:285)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Graphics_SpriteBatcher__DrawBatch() Line 209 (d:\MonoGame\MonoGame\MonoGame.Framework\Graphics\SpriteBatcher.cs:209)
MirGameTemplate.WindowsDX.exe!MirEngine_MirEngine_Engine__ExecuteCommandBuffer() Line 346 (d:\xxx\xxxEngine\xxxEngine\Engine.cs:346)
MirGameTemplate.WindowsDX.exe!MirEngine_MirEngine_GameBase__EndDraw() Line 290 (d:\xxx\MirEngine\MirEngine\GameBase.cs:290)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Game__Tick() Line 611 (d:\MonoGame\MonoGame\MonoGame.Framework\Game.cs:611)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_MonoGame_Framework_WinFormsGameWindow__TickOnIdle() Line 479 (d:\MonoGame\MonoGame\MonoGame.Framework\Platform\Windows\WinFormsGameWindow.cs:479)
MirGameTemplate.WindowsDX.exe!System_Windows_Forms_System_Windows_Forms_Application_ThreadContext__System_Windows_Forms_UnsafeNativeMethods_IMsoComponent_FDoIdle() (未知源:0)
MirGameTemplate.WindowsDX.exe!System_Windows_Forms_System_Windows_Forms_Application_ComponentManager__System_Windows_Forms_UnsafeNativeMethods_IMsoComponentManager_FPushMessageLoop() (未知源:0)
MirGameTemplate.WindowsDX.exe!System_Windows_Forms_System_Windows_Forms_Application_ThreadContext__RunMessageLoopInner() (未知源:0)
MirGameTemplate.WindowsDX.exe!System_Windows_Forms_System_Windows_Forms_Application_ThreadContext__RunMessageLoop() (未知源:0)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_MonoGame_Framework_WinFormsGameWindow__RunLoop() Line 450 (d:\MonoGame\MonoGame\MonoGame.Framework\Platform\Windows\WinFormsGameWindow.cs:450)
MirGameTemplate.WindowsDX.exe!MonoGame_Framework_Microsoft_Xna_Framework_Game__Run_0() Line 482 (d:\MonoGame\MonoGame\MonoGame.Framework\Game.cs:482)
MirGameTemplate.WindowsDX.exe!MirGameTemplate_WindowsDX_MirGameTemplate_WindowsDX_Program__Main() Line 11 (d:\xxx\MirEngine\MirGameTemplate.WindowsDX\Program.cs:11)
MirGameTemplate.WindowsDX.exe!MirGameTemplate_WindowsDX__Module___StartupCodeMain() (未知源:0)
MirGameTemplate.WindowsDX.exe!wmain(int argc, wchar_t * * argv) Line 440 (e:\a\_work\103\s\corert_4026918\src\native\bootstrap\main.cpp:440)
[Inline Frame] MirGameTemplate.WindowsDX.exe!invoke_main() Line 90 (d:\agent\_work\9\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:90)
MirGameTemplate.WindowsDX.exe!__scrt_common_main_seh() Line 288 (d:\agent\_work\9\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
kernel32.dll!00007fff7ae16fd4() (未知源:0)
ntdll.dll!00007fff7bb1cec1() (未知源:0)

MirGameTemplate.Windows.DX.exe!FinalizerStart

ntdll.dll!00007fff7bb6be44() (未知源:0)
KernelBase.dll!00007fff795626ee() (未知源:0)
[Inline Frame] MirGameTemplate.WindowsDX.exe!PalWaitForSingleObjectEx(void * arg1, unsigned int) (未知源:0)
MirGameTemplate.WindowsDX.exe!RhpWaitForFinalizerRequest() Line 203 (e:\a\_work\103\s\corert_4026918\src\native\runtime\finalizerhelpers.cpp:203)
MirGameTemplate.WindowsDX.exe!ProcessFinalizers() (未知源:0)
MirGameTemplate.WindowsDX.exe!FinalizerStart(void * pContext) Line 72 (e:\a\_work\103\s\corert_4026918\src\native\runtime\finalizerhelpers.cpp:72)
kernel32.dll!00007fff7ae16fd4() (未知源:0)
ntdll.dll!00007fff7bb1cec1() (未知源:0)

MirGameTemplate.WindowsDX.exe!S_P_CoreLib_System_Threading_Thread_ThreadEntryPoint[]()

ntdll.dll!00007fff7bb6be44() (未知源:0)
KernelBase.dll!00007fff795626ee() (未知源:0)
MirGameTemplate.WindowsDX.exe!Thread::WaitForGC(void * pTransitionFrame) Line 89 (e:\a\_work\103\s\corert_4026918\src\native\runtime\thread.cpp:89)
MirGameTemplate.WindowsDX.exe!RhpWaitForGC2(PInvokeTransitionFrame * pFrame) Line 979 (e:\a\_work\103\s\corert_4026918\src\native\runtime\thread.cpp:979)
MirGameTemplate.WindowsDX.exe!RhpWaitForGCNoAbort() Line 84 (e:\A\_work\103\s\corert_4026918\src\Native\Runtime\amd64\PInvoke.asm:84)
MirGameTemplate.WindowsDX.exe!RhpWaitForGC() Line 114 (e:\A\_work\103\s\corert_4026918\src\Native\Runtime\amd64\PInvoke.asm:114)
MirGameTemplate.WindowsDX.exe!Microsoft_Win32_SystemEvents_Interop_User32__MsgWaitForMultipleObjectsEx() (未知源:0)
MirGameTemplate.WindowsDX.exe!Microsoft_Win32_SystemEvents_Microsoft_Win32_SystemEvents__WindowThreadProc() (未知源:0)
MirGameTemplate.WindowsDX.exe!S_P_CoreLib_System_Threading_Thread__StartThread() (未知源:0)
MirGameTemplate.WindowsDX.exe!S_P_CoreLib_System_Threading_Thread__ThreadEntryPoint() (未知源:0)
kernel32.dll!00007fff7ae16fd4() (未知源:0)
ntdll.dll!00007fff7bb1cec1() (未知源:0)

*MirGameTemplate.WindowsDX.exe!unsigned int (void )::**

ntdll.dll!00007fff7bb6f534() (未知源:0)
KernelBase.dll!00007fff795bbe20() (未知源:0)
MirGameTemplate.WindowsDX.exe!PalHijack(void * hThread, unsigned int(*)(void *, PAL_LIMITED_CONTEXT *, void *) callback, void * pCallbackContext) Line 330 (e:\a\_work\103\s\corert_4026918\src\native\runtime\windows\palredhawkminwin.cpp:330)
MirGameTemplate.WindowsDX.exe!Thread::Hijack() Line 648 (e:\a\_work\103\s\corert_4026918\src\native\runtime\thread.cpp:648)
MirGameTemplate.WindowsDX.exe!ThreadStore::SuspendAllThreads(bool waitForGCEvent, bool fireDebugEvent) Line 263 (e:\a\_work\103\s\corert_4026918\src\native\runtime\threadstore.cpp:263)
MirGameTemplate.WindowsDX.exe!GCToEEInterface::SuspendEE(SUSPEND_REASON reason) Line 809 (e:\a\_work\103\s\corert_4026918\src\native\runtime\gcrhenv.cpp:809)
[Inline Frame] MirGameTemplate.WindowsDX.exe!WKS::gc_heap::bgc_suspend_EE() (未知源:0)
MirGameTemplate.WindowsDX.exe!WKS::gc_heap::background_mark_phase() Line 26483 (e:\a\_work\103\s\corert_4026918\src\native\gc\gc.cpp:26483)
MirGameTemplate.WindowsDX.exe!WKS::gc_heap::gc1() Line 16153 (e:\a\_work\103\s\corert_4026918\src\native\gc\gc.cpp:16153)
MirGameTemplate.WindowsDX.exe!WKS::gc_heap::bgc_thread_function() Line 27540 (e:\a\_work\103\s\corert_4026918\src\native\gc\gc.cpp:27540)
MirGameTemplate.WindowsDX.exe!GCToEEInterface::CreateThread::__l2::<lambda>(void * argument) Line 1349 (e:\a\_work\103\s\corert_4026918\src\native\runtime\gcrhenv.cpp:1349)
kernel32.dll!00007fff7ae16fd4() (未知源:0)
ntdll.dll!00007fff7bb1cec1() (未知源:0)

MirGameTemplate.WindowsDX.exe!S_P_CoreLib_System_Threading_Thread_ThreadEntryPoint[]()

MirGameTemplate.WindowsDX.exe!MirEngine_MirEngine_GameBase__ActiveSceneDrawLoop() Line 250 (d:\xxx\MirEngine\MirEngine\GameBase.cs:250)
MirGameTemplate.WindowsDX.exe!RhpGcProbeHijackScalar() Line 152 (e:\A\_work\103\s\corert_4026918\src\Native\Runtime\amd64\GcProbe.asm:152)
ryancheung commented 4 years ago

The long running uninterrupted computation will run into problems though. For example, if the program has infinite loop for(;;) { } on one thread and allocates on a second thread, the GC thread suspension will hang in CoreRT today https://github.com/dotnet/corert/issues/7807#issuecomment-537646340

@jkotas So this GC suspension hanging bug still exists in current CoreRT?

jkotas commented 4 years ago

Yes, this problem still exists in current CoreRT.

ryancheung commented 4 years ago

Got it. Thanks for reply.

ryancheung commented 4 years ago

I managed to make this game demo works in .NET Native in UWP before.

MichalStrehovsky commented 4 years ago

.NET Native has the codegen+runtime feature necessary for the GC to be able to make progress in a case like this. CoreRT has a different codegen so this requires extra work that hasn't happened yet.