#pragma once #include #include #include #include #include namespace waybar::util { class SleeperThread { public: SleeperThread() = default; SleeperThread(std::function func) : thread_{[this, func] { while (do_run_) { signal_ = false; func(); } }} {} SleeperThread& operator=(std::function func) { thread_ = std::thread([this, func] { while (do_run_) { signal_ = false; func(); } }); return *this; } bool isRunning() const { return do_run_; } auto sleep_for(std::chrono::system_clock::duration dur) { std::unique_lock lk(mutex_); 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_); return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; }); } auto wake_up() { { std::lock_guard lck(mutex_); signal_ = true; } condvar_.notify_all(); } auto stop() { { std::lock_guard lck(mutex_); signal_ = true; do_run_ = false; } condvar_.notify_all(); auto handle = thread_.native_handle(); if (handle != 0) { // TODO: find a proper way to terminate thread... pthread_cancel(handle); } } ~SleeperThread() { stop(); if (thread_.joinable()) { thread_.join(); } } private: std::thread thread_; std::condition_variable condvar_; std::mutex mutex_; bool do_run_ = true; bool signal_ = false; }; } // namespace waybar::util