diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 55e179a..0e70d71 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: build-binary: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout Code uses: actions/checkout@v4 diff --git a/include/core.hpp b/include/core.hpp index 4d85ec6..24827a6 100644 --- a/include/core.hpp +++ b/include/core.hpp @@ -35,6 +35,7 @@ namespace core { namespace background { void run(); + void run_once(); void stop(); } // namespace background diff --git a/source/cfg.cpp b/source/cfg.cpp index d3215a4..5f765ae 100644 --- a/source/cfg.cpp +++ b/source/cfg.cpp @@ -205,8 +205,10 @@ namespace cfg { void menu_close() { - if (cfg::sync_on_changes && important_vars_changed()) + if (cfg::sync_on_changes && important_vars_changed()) { + core::background::stop(); core::background::run(); + } cfg::save(); diff --git a/source/core.cpp b/source/core.cpp index 7aac978..6bca845 100644 --- a/source/core.cpp +++ b/source/core.cpp @@ -110,6 +110,19 @@ namespace core { } + void + sleep_for(std::chrono::milliseconds t, + std::stop_token token) + { + using clock = std::chrono::steady_clock; + const auto deadline = clock::now() + t; + while (clock::now() < deadline) { + check_stop(token); + std::this_thread::sleep_for(100ms); + } + } + + // Note: hardcoded for IPv4, the Wii U doesn't have IPv6. std::pair ntp_query(std::stop_token token, @@ -438,28 +451,39 @@ namespace core { namespace background { std::stop_source stopper{std::nostopstate}; - std::atomic_bool running; + + enum class state_t : unsigned { + none, + started, + finished, + canceled, + }; + std::atomic state{state_t::none}; + void run() { - if (running) - return; - - running = true; + state = state_t::started; std::jthread t{ [](std::stop_token token) { - wups::logger::guard lguard{PLUGIN_NAME}; - notify::guard nguard; + wups::logger::guard logger_guard{PLUGIN_NAME}; + notify::guard notify_guard; try { + // Note: we wait 5 seconds, to minimize spurious network errors. + sleep_for(5s, token); core::run(token, false); + state = state_t::finished; + } + catch (canceled_error& e) { + state = state_t::canceled; } catch (std::exception& e) { notify::error(notify::level::normal, e.what()); + state = state_t::finished; } - running = false; } }; @@ -469,26 +493,33 @@ namespace core { } + void + run_once() + { + if (state != state_t::finished) + run(); + } + + void stop() { - if (running) { + if (state == state_t::started) { stopper.request_stop(); // Wait up to ~10 seconds for the thread to flag it stopped running. unsigned max_tries = 100; do { std::this_thread::sleep_for(100ms); - } while (running && --max_tries); + } while ((state == state_t::started) && --max_tries); - if (max_tries == 0) + if (state == state_t::started) logger::printf("WARNING: Background thread did not stop!\n"); stopper = std::stop_source{std::nostopstate}; } } - } // namespace background } // namespace core diff --git a/source/main.cpp b/source/main.cpp index 3a4ea39..8483c91 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -32,13 +32,23 @@ INITIALIZE_PLUGIN() wups::logger::guard guard{PLUGIN_NAME}; cfg::init(); +} + + +DEINITIALIZE_PLUGIN() +{ + core::background::stop(); +} + +ON_APPLICATION_START() +{ if (cfg::sync_on_boot) - core::background::run(); + core::background::run_once(); } -DEINITIALIZE_PLUGIN() +ON_APPLICATION_REQUESTS_EXIT() { core::background::stop(); } diff --git a/source/synchronize_item.cpp b/source/synchronize_item.cpp index fffa8a6..02d907a 100644 --- a/source/synchronize_item.cpp +++ b/source/synchronize_item.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include