From 979ee07c675dad56446ac1f36f9d43a35fe90949 Mon Sep 17 00:00:00 2001 From: Trevor Shoe Date: Fri, 6 Dec 2024 12:19:22 -0500 Subject: [PATCH] [sshfs] Use seperate signaling thread --- src/platform/platform_unix.cpp | 48 +++++++++++++++++++------------- src/sshfs_mount/sshfs_server.cpp | 2 +- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/platform/platform_unix.cpp b/src/platform/platform_unix.cpp index 895e0d4cf1..59708b6de6 100644 --- a/src/platform/platform_unix.cpp +++ b/src/platform/platform_unix.cpp @@ -26,6 +26,7 @@ #include #include +#include namespace mp = multipass; @@ -183,37 +184,46 @@ timespec make_timespec(std::chrono::duration duration) return timespec{seconds.count(), std::chrono::duration_cast(duration - seconds).count()}; } +#include + std::function(const std::function&)> mp::platform::make_quit_watchdog( const std::chrono::milliseconds& timeout) { return [sigset = make_and_block_signals({SIGQUIT, SIGTERM, SIGHUP, SIGUSR2}), - time = make_timespec(timeout)](const std::function& condition) -> std::optional { - // create a timer to send SIGUSR2 which unblocks this thread - sigevent sevp{}; - sevp.sigev_notify = SIGEV_SIGNAL; - sevp.sigev_signo = SIGUSR2; - - timer_t timer{}; - if (timer_create(CLOCK_MONOTONIC, &sevp, &timer) == -1) - throw std::runtime_error(fmt::format("Could not create timer: {}", strerror(errno))); + timeout](const std::function& condition) -> std::optional { + std::mutex sig_mtx; + std::condition_variable sig_cv; + int sig = SIGUSR2; - // scope guard to make sure the timer is deleted once it's no longer needed - const auto timer_guard = sg::make_scope_guard([timer]() noexcept { timer_delete(timer); }); + // A signal generator that triggers after `timeout` + AutoJoinThread signaler([&sig_mtx, &sig_cv, &sig, &timeout, signalee = pthread_self()] { + std::unique_lock lock(sig_mtx); + while (sig == SIGUSR2) + { + auto status = sig_cv.wait_for(lock, timeout); - // set timer interval and initial time to provided timeout - const itimerspec timer_interval{time, time}; - if (timer_settime(timer, 0, &timer_interval, nullptr) == -1) - throw std::runtime_error(fmt::format("Could not set timer: {}", strerror(errno))); + if (sig == SIGUSR2 && status == std::cv_status::timeout) + { + pthread_kill(signalee, SIGUSR2); + } + } + }); // wait on signals and condition - int sig = SIGUSR2; - while (sig == SIGUSR2 && condition()) + int ret = SIGUSR2; + while (ret == SIGUSR2 && condition()) { // can't use sigtimedwait since macOS doesn't support it - sigwait(&sigset, &sig); + sigwait(&sigset, &ret); + } + + { + std::unique_lock lock(sig_mtx); + sig = ret == SIGUSR2 ? 0 : ret; } + sig_cv.notify_all(); // if sig is SIGUSR2 then we know we're exiting because condition() was false - return sig == SIGUSR2 ? std::nullopt : std::make_optional(sig); + return ret == SIGUSR2 ? std::nullopt : std::make_optional(sig); }; } diff --git a/src/sshfs_mount/sshfs_server.cpp b/src/sshfs_mount/sshfs_server.cpp index eb519a7895..ee49d7a3e5 100644 --- a/src/sshfs_mount/sshfs_server.cpp +++ b/src/sshfs_mount/sshfs_server.cpp @@ -117,7 +117,7 @@ int main(int argc, char* argv[]) if (sig.has_value()) cout << "Received signal " << *sig << ". Stopping" << endl; else - cout << "SFTP server thread stopped unexpectedly." << endl; + cerr << "SFTP server thread stopped unexpectedly." << endl; sshfs_mount.stop(); exit(sig.has_value() ? EXIT_SUCCESS : EXIT_FAILURE);