Skip to content

Commit

Permalink
[sshfs] Use Timer and wrap posix signals
Browse files Browse the repository at this point in the history
  • Loading branch information
Sploder12 committed Dec 17, 2024
1 parent 17c2580 commit 3d5bfc1
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 26 deletions.
21 changes: 17 additions & 4 deletions include/multipass/platform_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,25 @@

#include <signal.h>

namespace multipass
#include "singleton.h"

#define MP_POSIX_SIGNAL multipass::platform::SignalWrapper::instance()

namespace multipass::platform
{
namespace platform

class SignalWrapper : public Singleton<SignalWrapper>
{
public:
SignalWrapper(const PrivatePass&) noexcept;

virtual int mask_signals(int how, const sigset_t* sigset, sigset_t* old_set = nullptr) const;
virtual int send(pthread_t target, int signal) const;
virtual int wait(const sigset_t& sigset, int& got) const;
};

sigset_t make_sigset(const std::vector<int>& sigs);
sigset_t make_and_block_signals(const std::vector<int>& sigs);
} // namespace platform
}

} // namespace multipass::platform
#endif // MULTIPASS_PLATFORM_UNIX_H
54 changes: 32 additions & 22 deletions src/platform/platform_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <unistd.h>

#include <libssh/sftp.h>
#include <multipass/auto_join_thread.h>
#include <multipass/timer.h>

namespace mp = multipass;

Expand Down Expand Up @@ -158,6 +158,25 @@ int mp::platform::symlink_attr_from(const char* path, sftp_attributes_struct* at
return 0;
}

mp::platform::SignalWrapper::SignalWrapper(const PrivatePass& pass) noexcept
: Singleton(pass){}


int mp::platform::SignalWrapper::mask_signals(int how, const sigset_t* sigset, sigset_t* old_set) const
{
return pthread_sigmask(how, sigset, old_set);
}

int mp::platform::SignalWrapper::send(pthread_t target, int signal) const
{
return pthread_kill(target, signal);
}

int mp::platform::SignalWrapper::wait(const sigset_t& sigset, int& got) const
{
return sigwait(std::addressof(sigset), std::addressof(got));
}

sigset_t mp::platform::make_sigset(const std::vector<int>& sigs)
{
sigset_t sigset;
Expand All @@ -172,7 +191,7 @@ sigset_t mp::platform::make_sigset(const std::vector<int>& sigs)
sigset_t mp::platform::make_and_block_signals(const std::vector<int>& sigs)
{
auto sigset{make_sigset(sigs)};
pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
MP_POSIX_SIGNAL.mask_signals(SIG_BLOCK, &sigset, nullptr);
return sigset;
}

Expand All @@ -188,34 +207,25 @@ std::function<std::optional<int>(const std::function<bool()>&)> mp::platform::ma
{
return [sigset = make_and_block_signals({SIGQUIT, SIGTERM, SIGHUP, SIGUSR2}),
period](const std::function<bool()>& condition) -> std::optional<int> {
std::mutex sig_mtx;
std::condition_variable sig_cv;
int sig = SIGUSR2;

// A signal generator that triggers after `timeout`
AutoJoinThread signaler([&sig_mtx, &sig_cv, &sig, &period, signalee = pthread_self()] {
std::unique_lock lock(sig_mtx);
while (!sig_cv.wait_for(lock, period, [&sig] { return sig != SIGUSR2; }))
{
pthread_kill(signalee, SIGUSR2);
}
});

// create a timer to periodically send SIGUSR2
utils::Timer signal_generator{period, [signalee = pthread_self()] {
MP_POSIX_SIGNAL.send(signalee, SIGUSR2);
}};

// wait on signals and condition
int latest_signal = SIGUSR2;
while (latest_signal == SIGUSR2 && condition())
{
signal_generator.start();

// can't use sigtimedwait since macOS doesn't support it
sigwait(&sigset, &latest_signal);
MP_POSIX_SIGNAL.wait(sigset, latest_signal);
}

{ // set `sig` to something other than SIGUSR2 so `signaler` knows to exit
std::lock_guard lock(sig_mtx);
sig = latest_signal == SIGUSR2 ? 0 : latest_signal;
}
sig_cv.notify_all();
signal_generator.stop();

// if `sig` is 0 then we know we're exiting because condition() was false
return sig ? std::make_optional(sig) : std::nullopt;
// if `latest_signal` is SIGUSR2 then we know `condition()` is false
return latest_signal == SIGUSR2 ? std::nullopt : std::make_optional(latest_signal);
};
}

0 comments on commit 3d5bfc1

Please sign in to comment.