summaryrefslogtreecommitdiff
path: root/src/utils/cpp/atomic.hpp
diff options
context:
space:
mode:
authorKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
committerKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
commit619def44c1cca9f3cdf63544d5f24f2c7a7d9b77 (patch)
tree01868de723cb82c86842f33743fa7b14e24c1fa3 /src/utils/cpp/atomic.hpp
downloadjustbuild-619def44c1cca9f3cdf63544d5f24f2c7a7d9b77.tar.gz
Initial self-hosting commit
This is the initial version of our tool that is able to build itself. In can be bootstrapped by ./bin/bootstrap.py Co-authored-by: Oliver Reiche <oliver.reiche@huawei.com> Co-authored-by: Victor Moreno <victor.moreno1@huawei.com>
Diffstat (limited to 'src/utils/cpp/atomic.hpp')
-rw-r--r--src/utils/cpp/atomic.hpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/utils/cpp/atomic.hpp b/src/utils/cpp/atomic.hpp
new file mode 100644
index 00000000..7f7631d0
--- /dev/null
+++ b/src/utils/cpp/atomic.hpp
@@ -0,0 +1,119 @@
+#ifndef INCLUDED_SRC_UTILS_CPP_ATOMIC_HPP
+#define INCLUDED_SRC_UTILS_CPP_ATOMIC_HPP
+
+#include <atomic>
+#include <condition_variable>
+#include <shared_mutex>
+
+// Atomic wrapper with notify/wait capabilities.
+// TODO(modernize): Replace any use this class by C++20's std::atomic<T>, once
+// libcxx adds support for notify_*() and wait().
+// [https://libcxx.llvm.org/docs/Cxx2aStatus.html]
+template <class T>
+class atomic {
+ public:
+ atomic() = default;
+ explicit atomic(T value) : value_{std::move(value)} {}
+ atomic(atomic const& other) = delete;
+ atomic(atomic&& other) = delete;
+ ~atomic() = default;
+
+ auto operator=(atomic const& other) -> atomic& = delete;
+ auto operator=(atomic&& other) -> atomic& = delete;
+ auto operator=(T desired) -> T { // NOLINT
+ std::shared_lock lock(mutex_);
+ value_ = desired;
+ return desired;
+ }
+ operator T() const { return static_cast<T>(value_); } // NOLINT
+
+ void store(T desired, std::memory_order order = std::memory_order_seq_cst) {
+ std::shared_lock lock(mutex_);
+ value_.store(std::move(desired), order);
+ }
+ [[nodiscard]] auto load(
+ std::memory_order order = std::memory_order_seq_cst) const -> T {
+ return value_.load(order);
+ }
+
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ auto operator++() -> T {
+ std::shared_lock lock(mutex_);
+ return ++value_;
+ }
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ [[nodiscard]] auto operator++(int) -> T {
+ std::shared_lock lock(mutex_);
+ return value_++;
+ }
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ auto operator--() -> T {
+ std::shared_lock lock(mutex_);
+ return --value_;
+ }
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ [[nodiscard]] auto operator--(int) -> T {
+ std::shared_lock lock(mutex_);
+ return value_--;
+ }
+
+ void notify_one() { cv_.notify_one(); }
+ void notify_all() { cv_.notify_all(); }
+ void wait(T old,
+ std::memory_order order = std::memory_order::seq_cst) const {
+ std::unique_lock lock(mutex_);
+ cv_.wait(lock,
+ [this, &old, order]() { return value_.load(order) != old; });
+ }
+
+ private:
+ std::atomic<T> value_{};
+ mutable std::shared_mutex mutex_{};
+ mutable std::condition_variable_any cv_{};
+};
+
+// Atomic shared_pointer with notify/wait capabilities.
+// TODO(modernize): Replace any use this class by C++20's
+// std::atomic<std::shared_ptr<T>>, once libcxx adds support for it.
+// [https://libcxx.llvm.org/docs/Cxx2aStatus.html]
+template <class T>
+class atomic_shared_ptr {
+ using ptr_t = std::shared_ptr<T>;
+
+ public:
+ atomic_shared_ptr() = default;
+ explicit atomic_shared_ptr(ptr_t value) : value_{std::move(value)} {}
+ atomic_shared_ptr(atomic_shared_ptr const& other) = delete;
+ atomic_shared_ptr(atomic_shared_ptr&& other) = delete;
+ ~atomic_shared_ptr() = default;
+
+ auto operator=(atomic_shared_ptr const& other)
+ -> atomic_shared_ptr& = delete;
+ auto operator=(atomic_shared_ptr&& other) -> atomic_shared_ptr& = delete;
+ auto operator=(ptr_t desired) -> ptr_t { // NOLINT
+ std::shared_lock lock(mutex_);
+ value_ = desired;
+ return desired;
+ }
+ operator ptr_t() const { value_; } // NOLINT
+
+ void store(ptr_t desired) {
+ std::shared_lock lock(mutex_);
+ value_ = std::move(desired);
+ }
+ [[nodiscard]] auto load() const -> ptr_t { return value_; }
+
+ void notify_one() { cv_.notify_one(); }
+ void notify_all() { cv_.notify_all(); }
+ void wait(ptr_t old) const {
+ std::unique_lock lock(mutex_);
+ cv_.wait(lock, [this, &old]() { return value_ != old; });
+ }
+
+ private:
+ ptr_t value_{};
+ mutable std::shared_mutex mutex_{};
+ mutable std::condition_variable_any cv_{};
+};
+
+#endif // INCLUDED_SRC_UTILS_CPP_ATOMIC_HPP