fix(tray): use the blocking event loop to avoid wasting power (#4457)

This commit is contained in:
Cameron Gutman
2025-11-29 12:39:45 -06:00
committed by GitHub
parent 62d58ed6e0
commit f1f9e755a9
4 changed files with 20 additions and 106 deletions

View File

@@ -99,32 +99,20 @@ void mainThreadLoop(const std::shared_ptr<safe::event_t<bool>> &shutdown_event)
// Conditions that would require the main thread event loop // Conditions that would require the main thread event loop
#ifndef _WIN32 #ifndef _WIN32
run_loop = tray_is_enabled; // On Windows, tray runs in separate thread, so no main loop needed for tray run_loop = tray_is_enabled && config::sunshine.system_tray; // On Windows, tray runs in separate thread, so no main loop needed for tray
#endif #endif
if (!run_loop) { if (!run_loop) {
BOOST_LOG(info) << "No main thread features enabled, skipping event loop"sv; BOOST_LOG(info) << "No main thread features enabled, skipping event loop"sv;
// Wait for shutdown
shutdown_event->view();
return; return;
} }
// Main thread event loop // Main thread event loop
BOOST_LOG(info) << "Starting main loop"sv; BOOST_LOG(info) << "Starting main loop"sv;
while (true) { while (system_tray::process_tray_events() == 0);
if (shutdown_event->peek()) { BOOST_LOG(info) << "Main loop has exited"sv;
BOOST_LOG(info) << "Shutdown event detected, breaking main loop"sv;
if (tray_is_enabled && config::sunshine.system_tray) {
system_tray::end_tray();
}
break;
}
if (tray_is_enabled) {
system_tray::process_tray_events();
}
// Sleep to avoid busy waiting
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@@ -297,7 +285,10 @@ int main(int argc, char *argv[]) {
}; };
force_shutdown = task_pool.pushDelayed(task, 10s).task_id; force_shutdown = task_pool.pushDelayed(task, 10s).task_id;
// Break out of the main loop
shutdown_event->raise(true); shutdown_event->raise(true);
system_tray::end_tray();
display_device_deinit_guard = nullptr; display_device_deinit_guard = nullptr;
}); });
@@ -311,7 +302,10 @@ int main(int argc, char *argv[]) {
}; };
force_shutdown = task_pool.pushDelayed(task, 10s).task_id; force_shutdown = task_pool.pushDelayed(task, 10s).task_id;
// Break out of the main loop
shutdown_event->raise(true); shutdown_event->raise(true);
system_tray::end_tray();
display_device_deinit_guard = nullptr; display_device_deinit_guard = nullptr;
}); });
@@ -400,9 +394,6 @@ int main(int argc, char *argv[]) {
mainThreadLoop(shutdown_event); mainThreadLoop(shutdown_event);
// Wait for shutdown, this is not necessary when we're using the main event loop
shutdown_event->view();
httpThread.join(); httpThread.join();
configThread.join(); configThread.join();
rtspThread.join(); rtspThread.join();
@@ -416,11 +407,6 @@ int main(int argc, char *argv[]) {
nvprefs_instance.restore_global_profile(); nvprefs_instance.restore_global_profile();
nvprefs_instance.unload(); nvprefs_instance.unload();
} }
// Stop the threaded tray if it was started
if (tray_is_enabled && config::sunshine.system_tray) {
system_tray::end_tray_threaded();
}
#endif #endif
return lifetime::desired_exit_code; return lifetime::desired_exit_code;

View File

@@ -53,11 +53,6 @@ using namespace std::literals;
namespace system_tray { namespace system_tray {
static std::atomic tray_initialized = false; static std::atomic tray_initialized = false;
// Threading variables for all platforms
static std::thread tray_thread;
static std::atomic tray_thread_running = false;
static std::atomic tray_thread_should_exit = false;
void tray_open_ui_cb([[maybe_unused]] struct tray_menu *item) { void tray_open_ui_cb([[maybe_unused]] struct tray_menu *item) {
BOOST_LOG(info) << "Opening UI from system tray"sv; BOOST_LOG(info) << "Opening UI from system tray"sv;
launch_ui(); launch_ui();
@@ -207,16 +202,12 @@ namespace system_tray {
int process_tray_events() { int process_tray_events() {
if (!tray_initialized) { if (!tray_initialized) {
BOOST_LOG(error) << "System tray is not initialized"sv;
return 1; return 1;
} }
// Process one iteration of the tray loop with non-blocking mode (0) // Block until an event is processed or tray_quit() is called
if (const int result = tray_loop(0); result != 0) { return tray_loop(1);
BOOST_LOG(warning) << "System tray loop failed"sv;
return result;
}
return 0;
} }
int end_tray() { int end_tray() {
@@ -319,63 +310,22 @@ namespace system_tray {
// Initialize the tray in this thread // Initialize the tray in this thread
if (init_tray() != 0) { if (init_tray() != 0) {
BOOST_LOG(error) << "Failed to initialize tray in thread"sv; BOOST_LOG(error) << "Failed to initialize tray in thread"sv;
tray_thread_running = false;
return; return;
} }
tray_thread_running = true;
// Main tray event loop // Main tray event loop
while (!tray_thread_should_exit) { while (process_tray_events() == 0);
if (process_tray_events() != 0) {
BOOST_LOG(warning) << "Tray event processing failed in thread"sv;
break;
}
// Sleep to avoid busy waiting
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
// Clean up the tray
end_tray();
tray_thread_running = false;
BOOST_LOG(info) << "System tray thread ended"sv; BOOST_LOG(info) << "System tray thread ended"sv;
} }
int init_tray_threaded() { int init_tray_threaded() {
if (tray_thread_running) {
BOOST_LOG(warning) << "Tray thread is already running"sv;
return 1;
}
tray_thread_should_exit = false;
try { try {
tray_thread = std::thread(tray_thread_worker); auto tray_thread = std::thread(tray_thread_worker);
// Wait for the thread to start and initialize // The tray thread doesn't require strong lifetime management.
const auto start_time = std::chrono::steady_clock::now(); // It will exit asynchronously when tray_exit() is called.
while (!tray_thread_running && !tray_thread_should_exit) { tray_thread.detach();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// Timeout after 10 seconds
if (std::chrono::steady_clock::now() - start_time > std::chrono::seconds(10)) {
BOOST_LOG(error) << "Tray thread initialization timeout"sv;
tray_thread_should_exit = true;
if (tray_thread.joinable()) {
tray_thread.join();
}
return 1;
}
}
if (!tray_thread_running) {
BOOST_LOG(error) << "Tray thread failed to start"sv;
if (tray_thread.joinable()) {
tray_thread.join();
}
return 1;
}
BOOST_LOG(info) << "System tray thread initialized successfully"sv; BOOST_LOG(info) << "System tray thread initialized successfully"sv;
return 0; return 0;
@@ -385,21 +335,5 @@ namespace system_tray {
} }
} }
int end_tray_threaded() {
if (!tray_thread_running) {
return 0;
}
BOOST_LOG(info) << "Stopping system tray thread"sv;
tray_thread_should_exit = true;
if (tray_thread.joinable()) {
tray_thread.join();
}
BOOST_LOG(info) << "System tray thread stopped"sv;
return 0;
}
} // namespace system_tray } // namespace system_tray
#endif #endif

View File

@@ -96,10 +96,4 @@ namespace system_tray {
* @return 0 if initialization was successful, non-zero otherwise. * @return 0 if initialization was successful, non-zero otherwise.
*/ */
int init_tray_threaded(); int init_tray_threaded();
/**
* @brief Stops the threaded system tray and waits for the thread to finish.
* @return 0 after stopping the threaded tray.
*/
int end_tray_threaded();
} // namespace system_tray } // namespace system_tray