From bd6235efba1189c134fbde26850db291c0b1871d Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 25 Oct 2025 00:18:34 -0500 Subject: [PATCH] Use async logging while streaming only The benefits of reliable output outweigh performance concerns during non-streaming activities. --- app/main.cpp | 27 +++++++++++++++++++++++++-- app/streaming/session.cpp | 6 ++++++ app/streaming/streamutils.cpp | 12 ++++++++++++ app/streaming/streamutils.h | 6 ++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/app/main.cpp b/app/main.cpp index c1ea8e4a..7242ffdd 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -60,9 +60,16 @@ // Log to console for debug Mac builds #endif +// StreamUtils::setAsyncLogging() exposes control of this to the Session +// class to enable async logging once the stream has started. +// +// FIXME: Clean this up +QAtomicInt g_AsyncLoggingEnabled; + static QElapsedTimer s_LoggerTime; static QTextStream s_LoggerStream(stderr); static QThreadPool s_LoggerThread; +static QMutex s_SyncLoggerMutex; static bool s_SuppressVerboseOutput; static QRegularExpression k_RikeyRegex("&rikey=\\w+"); static QRegularExpression k_RikeyIdRegex("&rikeyid=[\\d-]+"); @@ -127,8 +134,16 @@ void logToLoggerStream(QString& message) } #endif - // Queue the log message to be written asynchronously - s_LoggerThread.start(new LoggerTask(message)); + if (g_AsyncLoggingEnabled) { + // Queue the log message to be written asynchronously + s_LoggerThread.start(new LoggerTask(message)); + } + else { + // QTextStream is not thread-safe, so we must lock + QMutexLocker locker(&s_SyncLoggerMutex); + s_LoggerStream << message; + s_LoggerStream.flush(); + } } void sdlLogToDiskHandler(void*, int category, SDL_LogPriority priority, const char* message) @@ -298,6 +313,11 @@ LONG WINAPI UnhandledExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) qCritical() << "Unhandled exception! Failed to open dump file:" << qDmpFileName << "with error" << GetLastError(); } + // Sleep for a moment to allow the logging thread to finish up before crashing + if (g_AsyncLoggingEnabled) { + Sleep(500); + } + // Let the program crash and WER collect a dump return EXCEPTION_CONTINUE_SEARCH; } @@ -826,6 +846,9 @@ int main(int argc, char *argv[]) av_log_set_callback(av_log_default_callback); #endif + // We should not be in async logging mode anymore + Q_ASSERT(g_AsyncLoggingEnabled == 0); + // Wait for pending log messages to be printed s_LoggerThread.waitForDone(); diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 5b335081..ef65cca7 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -2014,6 +2014,9 @@ void Session::execInternal() // Toggle the stats overlay if requested by the user m_OverlayManager.setOverlayState(Overlay::OverlayDebug, m_Preferences->showPerformanceOverlay); + // Switch to async logging mode when we enter the SDL loop + StreamUtils::enterAsyncLoggingMode(); + // Hijack this thread to be the SDL main thread. We have to do this // because we want to suspend all Qt processing until the stream is over. SDL_Event event; @@ -2363,6 +2366,9 @@ void Session::execInternal() } DispatchDeferredCleanup: + // Switch back to synchronous logging mode + StreamUtils::exitAsyncLoggingMode(); + // Uncapture the mouse and hide the window immediately, // so we can return to the Qt GUI ASAP. m_InputHandler->setCaptureActive(false); diff --git a/app/streaming/streamutils.cpp b/app/streaming/streamutils.cpp index 9456756b..a1a5291c 100644 --- a/app/streaming/streamutils.cpp +++ b/app/streaming/streamutils.cpp @@ -417,3 +417,15 @@ int StreamUtils::getDrmFd(bool preferRenderNode) return -1; } + +extern QAtomicInt g_AsyncLoggingEnabled; + +void StreamUtils::enterAsyncLoggingMode() +{ + g_AsyncLoggingEnabled.ref(); +} + +void StreamUtils::exitAsyncLoggingMode() +{ + g_AsyncLoggingEnabled.deref(); +} diff --git a/app/streaming/streamutils.h b/app/streaming/streamutils.h index 671ce24c..63ea7e61 100644 --- a/app/streaming/streamutils.h +++ b/app/streaming/streamutils.h @@ -31,4 +31,10 @@ public: static int getDrmFd(bool preferRenderNode); + + static + void enterAsyncLoggingMode(); + + static + void exitAsyncLoggingMode(); };