From 3cb8ae9a9c162bbd45b071bd406ff39d88e3e111 Mon Sep 17 00:00:00 2001 From: Stefanos Kornilios Misis Poiitidis Date: Sat, 30 Apr 2022 16:00:00 +0300 Subject: [PATCH] ScopedSignalMask: Add shared mutex support, move constructors --- .../FEXHeaderUtils/ScopedSignalMask.h | 129 ++++++++++++++++-- 1 file changed, 121 insertions(+), 8 deletions(-) diff --git a/FEXHeaderUtils/FEXHeaderUtils/ScopedSignalMask.h b/FEXHeaderUtils/FEXHeaderUtils/ScopedSignalMask.h index 071ef010d..b44cc427b 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/ScopedSignalMask.h +++ b/FEXHeaderUtils/FEXHeaderUtils/ScopedSignalMask.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -20,27 +21,139 @@ namespace FHU { * Destructor Order: * 1) Unlock Mutex * 2) Unmask signals + * + * Masking signals around mutex locks is needed for signal-reentrant safety */ class ScopedSignalMaskWithMutex final { public: + ScopedSignalMaskWithMutex(std::mutex &_Mutex, uint64_t Mask = ~0ULL) - : Mutex {_Mutex} { + : Mutex {&_Mutex} { // Mask all signals, storing the original incoming mask ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &OriginalMask, sizeof(OriginalMask)); // Lock the mutex - Mutex.lock(); + Mutex->lock(); + } + + // No copy or assignment possible + ScopedSignalMaskWithMutex(const ScopedSignalMaskWithMutex&) = delete; + ScopedSignalMaskWithMutex& operator=(ScopedSignalMaskWithMutex&) = delete; + + // Only move + ScopedSignalMaskWithMutex(ScopedSignalMaskWithMutex &&rhs) + : OriginalMask {rhs.OriginalMask}, Mutex {rhs.Mutex} { + rhs.Mutex = nullptr; } ~ScopedSignalMaskWithMutex() { - // Unlock the mutex - Mutex.unlock(); + if (Mutex != nullptr) { + // Unlock the mutex + Mutex->unlock(); - // Unmask back to the original signal mask - ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(OriginalMask)); + // Unmask back to the original signal mask + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(OriginalMask)); + } } private: uint64_t OriginalMask{}; - std::mutex &Mutex; + std::mutex *Mutex; }; -} + + /** + * @brief A class that masks signals and shared locks a shared mutex until it goes out of scope + * + * Constructor order: + * 1) Mask signals + * 2) Lock Mutex + * + * Destructor Order: + * 1) Unlock Mutex + * 2) Unmask signals + * + * Masking signals around mutex locks is needed for signal-rentrant safety + */ + class ScopedSignalMaskWithSharedLock final { + public: + ScopedSignalMaskWithSharedLock(std::shared_mutex &_Mutex, uint64_t Mask = ~0ULL) + : Mutex {&_Mutex} { + // Mask all signals, storing the original incoming mask + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &OriginalMask, sizeof(OriginalMask)); + + // Lock the mutex + Mutex->lock_shared(); + } + + // No copy or assignment possible + ScopedSignalMaskWithSharedLock(const ScopedSignalMaskWithSharedLock&) = delete; + ScopedSignalMaskWithSharedLock& operator=(ScopedSignalMaskWithSharedLock&) = delete; + + // Only move + ScopedSignalMaskWithSharedLock(ScopedSignalMaskWithSharedLock &&rhs) + : OriginalMask {rhs.OriginalMask}, Mutex {rhs.Mutex} { + rhs.Mutex = nullptr; + } + + ~ScopedSignalMaskWithSharedLock() { + if (Mutex) { + // Unlock the mutex + Mutex->unlock_shared(); + + // Unmask back to the original signal mask + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(OriginalMask)); + } + } + private: + uint64_t OriginalMask{}; + std::shared_mutex *Mutex; + }; + + + /** + * @brief A class that masks signals and unique locks a shared mutex until it goes out of scope + * + * Constructor order: + * 1) Mask signals + * 2) Lock Mutex + * + * Destructor Order: + * 1) Unlock Mutex + * 2) Unmask signals + * + * Masking signals around mutex locks is needed for signal-rentrant safety + */ + class ScopedSignalMaskWithUniqueLock final { + public: + ScopedSignalMaskWithUniqueLock(std::shared_mutex &_Mutex, uint64_t Mask = ~0ULL) + : Mutex {&_Mutex} { + // Mask all signals, storing the original incoming mask + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &OriginalMask, sizeof(OriginalMask)); + + // Lock the mutex + Mutex->lock(); + } + + // No copy or assignment possible + ScopedSignalMaskWithUniqueLock(const ScopedSignalMaskWithSharedLock&) = delete; + ScopedSignalMaskWithUniqueLock& operator=(ScopedSignalMaskWithSharedLock&) = delete; + + ScopedSignalMaskWithUniqueLock(ScopedSignalMaskWithUniqueLock &&rhs) + : OriginalMask {rhs.OriginalMask}, Mutex {rhs.Mutex} { + rhs.Mutex = nullptr; + } + + ~ScopedSignalMaskWithUniqueLock() { + if (Mutex != nullptr) + { + // Unlock the mutex + Mutex->unlock(); + + // Unmask back to the original signal mask + ::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &OriginalMask, nullptr, sizeof(OriginalMask)); + } + } + private: + uint64_t OriginalMask{}; + std::shared_mutex *Mutex; + }; +} \ No newline at end of file