diff --git a/src/swrenderer/drawers/r_thread.cpp b/src/swrenderer/drawers/r_thread.cpp index f6dae7d90..57d86ab9b 100644 --- a/src/swrenderer/drawers/r_thread.cpp +++ b/src/swrenderer/drawers/r_thread.cpp @@ -33,6 +33,11 @@ #include "r_thread.h" #include "swrenderer/r_memory.h" #include "swrenderer/r_renderthread.h" +#include + +#ifdef WIN32 +void PeekThreadedErrorPane(); +#endif CVAR(Bool, r_multithreaded, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); @@ -73,10 +78,20 @@ void DrawerThreads::Execute(DrawerCommandQueuePtr commands) void DrawerThreads::WaitForWorkers() { + using namespace std::chrono_literals; + // Wait for workers to finish auto queue = Instance(); std::unique_lock end_lock(queue->end_mutex); - queue->end_condition.wait(end_lock, [&]() { return queue->tasks_left == 0; }); + if (!queue->end_condition.wait_for(end_lock, 5s, [&]() { return queue->tasks_left == 0; })) + { +#ifdef WIN32 + PeekThreadedErrorPane(); +#endif + // Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing + int *threadCrashed = nullptr; + *threadCrashed = 0xdeadbeef; + } end_lock.unlock(); // Clean up diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 5109cb82c..5948a5c4a 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -57,6 +57,11 @@ #include "swrenderer/r_memory.h" #include "swrenderer/r_renderthread.h" #include "swrenderer/things/r_playersprite.h" +#include + +#ifdef WIN32 +void PeekThreadedErrorPane(); +#endif EXTERN_CVAR(Bool, r_shadercolormaps) EXTERN_CVAR(Int, r_clearbuffer) @@ -217,9 +222,18 @@ namespace swrenderer // Wait for everyone to finish: if (Threads.size() > 1) { + using namespace std::chrono_literals; std::unique_lock end_lock(end_mutex); finished_threads++; - end_condition.wait(end_lock, [&]() { return finished_threads == Threads.size(); }); + if (!end_condition.wait_for(end_lock, 5s, [&]() { return finished_threads == Threads.size(); })) + { +#ifdef WIN32 + PeekThreadedErrorPane(); +#endif + // Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing + int *threadCrashed = nullptr; + *threadCrashed = 0xdeadbeef; + } finished_threads = 0; } diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 4ae1595ef..d6d246185 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -821,6 +821,13 @@ void ShowErrorPane(const char *text) } } +void PeekThreadedErrorPane() +{ + // Allow SendMessage from another thread to call its message handler so that it can display the crash dialog + MSG msg; + PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); +} + //========================================================================== // // DoMain