mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-05 20:53:52 +00:00
fix: watchdog thread called SDL video functions from non-main thread
SDL2 requires video/window functions to be called from the main thread (the one that called SDL_Init). The watchdog thread was calling SDL_SetRelativeMouseMode, SDL_ShowCursor, and SDL_SetWindowGrab directly on stall detection — undefined behavior on macOS (Cocoa requires main- thread UI calls) and unsafe on other platforms. Now the watchdog sets an atomic flag, and the main loop checks it at the top of each iteration, executing the SDL calls on the correct thread.
This commit is contained in:
parent
5583573beb
commit
74cc048767
1 changed files with 23 additions and 13 deletions
|
|
@ -679,8 +679,13 @@ void Application::run() {
|
|||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count()
|
||||
};
|
||||
std::thread watchdogThread([this, &watchdogRunning, &watchdogHeartbeatMs]() {
|
||||
bool releasedForCurrentStall = false;
|
||||
// Signal flag: watchdog sets this when a stall is detected, main loop
|
||||
// handles the actual SDL calls. SDL2 video functions must only be called
|
||||
// from the main thread (the one that called SDL_Init); calling them from
|
||||
// a background thread is UB on macOS (Cocoa) and unsafe on other platforms.
|
||||
std::atomic<bool> watchdogRequestRelease{false};
|
||||
std::thread watchdogThread([&watchdogRunning, &watchdogHeartbeatMs, &watchdogRequestRelease]() {
|
||||
bool signalledForCurrentStall = false;
|
||||
while (watchdogRunning.load(std::memory_order_acquire)) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
const int64_t nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
|
|
@ -688,21 +693,15 @@ void Application::run() {
|
|||
const int64_t lastBeatMs = watchdogHeartbeatMs.load(std::memory_order_acquire);
|
||||
const int64_t stallMs = nowMs - lastBeatMs;
|
||||
|
||||
// Failsafe: if the main loop stalls while relative mouse mode is active,
|
||||
// forcibly release grab so the user can move the cursor and close the app.
|
||||
if (stallMs > 1500) {
|
||||
if (!releasedForCurrentStall) {
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
if (window && window->getSDLWindow()) {
|
||||
SDL_SetWindowGrab(window->getSDLWindow(), SDL_FALSE);
|
||||
}
|
||||
if (!signalledForCurrentStall) {
|
||||
watchdogRequestRelease.store(true, std::memory_order_release);
|
||||
LOG_WARNING("Main-loop stall detected (", stallMs,
|
||||
"ms) — force-released mouse capture failsafe");
|
||||
releasedForCurrentStall = true;
|
||||
"ms) — requesting mouse capture release");
|
||||
signalledForCurrentStall = true;
|
||||
}
|
||||
} else {
|
||||
releasedForCurrentStall = false;
|
||||
signalledForCurrentStall = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -714,6 +713,17 @@ void Application::run() {
|
|||
std::chrono::steady_clock::now().time_since_epoch()).count(),
|
||||
std::memory_order_release);
|
||||
|
||||
// Handle watchdog mouse-release request on the main thread where
|
||||
// SDL video calls are safe (required by SDL2 threading model).
|
||||
if (watchdogRequestRelease.exchange(false, std::memory_order_acq_rel)) {
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
if (window && window->getSDLWindow()) {
|
||||
SDL_SetWindowGrab(window->getSDLWindow(), SDL_FALSE);
|
||||
}
|
||||
LOG_WARNING("Watchdog: force-released mouse capture on main thread");
|
||||
}
|
||||
|
||||
// Calculate delta time
|
||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<float> deltaTimeDuration = currentTime - lastTime;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue