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:
parent
20160749e7
commit
5da268077c
|
@ -8,6 +8,20 @@
|
||||||
|
|
||||||
namespace waybar::util {
|
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 {
|
class SleeperThread {
|
||||||
public:
|
public:
|
||||||
SleeperThread() = default;
|
SleeperThread() = default;
|
||||||
|
@ -34,6 +48,7 @@ class SleeperThread {
|
||||||
|
|
||||||
auto sleep_for(std::chrono::system_clock::duration dur) {
|
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_; });
|
return condvar_.wait_for(lk, dur, [this] { return signal_ || !do_run_; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +56,7 @@ class SleeperThread {
|
||||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::system_clock::duration>
|
std::chrono::time_point<std::chrono::system_clock, std::chrono::system_clock::duration>
|
||||||
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_; });
|
return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue