diff --git a/include/util/sleeper_thread.hpp b/include/util/sleeper_thread.hpp index 9adbe8f7..d1c6ba0d 100644 --- a/include/util/sleeper_thread.hpp +++ b/include/util/sleeper_thread.hpp @@ -8,6 +8,20 @@ namespace waybar::util { +/** + * Defer pthread_cancel until the end of a current scope. + * + * Required to protect a scope where it's unsafe to raise `__forced_unwind` exception. + * An example of these is a call of a method marked as `noexcept`; an attempt to cancel within such + * a method may result in a `std::terminate` call. + */ +class CancellationGuard { + int oldstate; +public: + CancellationGuard() { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); } + ~CancellationGuard() { pthread_setcancelstate(oldstate, &oldstate); } +}; + class SleeperThread { public: SleeperThread() = default; @@ -33,14 +47,16 @@ class SleeperThread { bool isRunning() const { return do_run_; } auto sleep_for(std::chrono::system_clock::duration dur) { - std::unique_lock lk(mutex_); + std::unique_lock lk(mutex_); + CancellationGuard cancel_lock; return condvar_.wait_for(lk, dur, [this] { return signal_ || !do_run_; }); } auto sleep_until( std::chrono::time_point time_point) { - std::unique_lock lk(mutex_); + std::unique_lock lk(mutex_); + CancellationGuard cancel_lock; return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; }); }