mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-11-04 09:42:42 +01:00 
			
		
		
		
	fix(util): protect std::condition_variable methods from pthread_cancel
The changes in GCC 11.x made `std::condition_variable` implementation internals `noexcept`. `noexcept` is known to interact particularly bad with `pthread_cancel`, i.e. `__cxxabiv1::__force_unwind` passing through the `noexcept` call stack frame causes a `std::terminate` call and immediate termination of the program Digging through the GCC ML archives[1] lead me to the idea of patching this with a few pthread_setcancelstate's. As bad as the solution is, it seems to be the best we can do within C++17 limits and without major rework. [1]: https://gcc.gnu.org/legacy-ml/gcc/2017-08/msg00156.html
This commit is contained in:
		@@ -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<std::chrono::system_clock, std::chrono::system_clock::duration>
 | 
			
		||||
          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_; });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user