mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-30 22:58:46 +00:00
14d2a6d8ff
Let's hope this doesn't causes build failures for e.g. musl: I just know it's good on macOS and our Linux CI. It's been a long time. One fix this brings, is I discovered we #include assert.h or cassert in a lot of places. If those ever happen to be in a file that doesn't include common.h, or we are before common.h gets included, we're unawaringly working with the system 'assert' macro again, which may get disabled for debug builds or at least has different behavior on crash. We undef 'assert' and redefine it in common.h. Those were all eliminated, except in one catch-22 spot for maybe.h: it can't include common.h. A fix might be to make a fish_assert.h that *usually* common.h exports.
66 lines
2 KiB
C++
66 lines
2 KiB
C++
// Support for enforcing correct access to globals.
|
|
#ifndef FISH_GLOBAL_SAFETY_H
|
|
#define FISH_GLOBAL_SAFETY_H
|
|
|
|
#include "config.h" // IWYU pragma: keep
|
|
|
|
#include <atomic>
|
|
|
|
#include "common.h"
|
|
|
|
/// A latch variable may only be set once.
|
|
/// The value is immortal.
|
|
template <typename T>
|
|
class latch_t : noncopyable_t, nonmovable_t {
|
|
T *value_{};
|
|
|
|
public:
|
|
operator T *() { return value_; }
|
|
operator const T *() const { return value_; }
|
|
|
|
T *operator->() { return value_; }
|
|
const T *operator->() const { return value_; }
|
|
|
|
bool is_set() const { return value_ != nullptr; }
|
|
|
|
void operator=(std::unique_ptr<T> value) {
|
|
assert(value_ == nullptr && "Latch variable initialized multiple times");
|
|
assert(value != nullptr && "Latch variable initialized with null");
|
|
// Note: deliberate leak.
|
|
value_ = value.release();
|
|
}
|
|
|
|
void operator=(T &&value) { *this = make_unique<T>(std::move(value)); }
|
|
};
|
|
|
|
/// An atomic type that always use relaxed reads.
|
|
template <typename T>
|
|
class relaxed_atomic_t {
|
|
std::atomic<T> value_{};
|
|
|
|
public:
|
|
relaxed_atomic_t() = default;
|
|
relaxed_atomic_t(T value) : value_(value) {}
|
|
|
|
operator T() const volatile { return value_.load(std::memory_order_relaxed); }
|
|
|
|
void operator=(T v) { return value_.store(v, std::memory_order_relaxed); }
|
|
void operator=(T v) volatile { return value_.store(v, std::memory_order_relaxed); }
|
|
|
|
// Perform a CAS operation, returning whether it succeeded.
|
|
bool compare_exchange(T expected, T desired) {
|
|
return value_.compare_exchange_strong(expected, desired, std::memory_order_relaxed);
|
|
}
|
|
|
|
// postincrement
|
|
T operator++(int) { return value_.fetch_add(1, std::memory_order_relaxed); }
|
|
T operator--(int) { return value_.fetch_sub(1, std::memory_order_relaxed); }
|
|
|
|
// preincrement
|
|
T operator++() { return value_.fetch_add(1, std::memory_order_relaxed) + 1; }
|
|
T operator--() { return value_.fetch_sub(1, std::memory_order_relaxed) - 1; }
|
|
};
|
|
|
|
using relaxed_atomic_bool_t = relaxed_atomic_t<bool>;
|
|
|
|
#endif
|