// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include #include #include namespace Common { class Event { public: void Set() { std::lock_guard lk{mutex}; if (!is_set) { is_set = true; condvar.notify_one(); } } void Wait() { std::unique_lock lk{mutex}; condvar.wait(lk, [&] { return is_set.load(); }); is_set = false; } template bool WaitFor(const std::chrono::duration& time) { std::unique_lock lk{mutex}; if (!condvar.wait_for(lk, time, [this] { return is_set.load(); })) return false; is_set = false; return true; } template bool WaitUntil(const std::chrono::time_point& time) { std::unique_lock lk{mutex}; if (!condvar.wait_until(lk, time, [this] { return is_set.load(); })) return false; is_set = false; return true; } void Reset() { std::unique_lock lk{mutex}; // no other action required, since wait loops on the predicate and any lingering signal will // get cleared on the first iteration is_set = false; } private: std::condition_variable condvar; std::mutex mutex; std::atomic_bool is_set{false}; }; class Barrier { public: explicit Barrier(std::size_t count_) : count(count_) {} /// Blocks until all "count" threads have called Sync() void Sync() { std::unique_lock lk{mutex}; const std::size_t current_generation = generation; if (++waiting == count) { generation++; waiting = 0; condvar.notify_all(); } else { condvar.wait(lk, [this, current_generation] { return current_generation != generation; }); } } std::size_t Generation() const { std::unique_lock lk(mutex); return generation; } private: std::condition_variable condvar; mutable std::mutex mutex; std::size_t count; std::size_t waiting = 0; std::size_t generation = 0; // Incremented once each time the barrier is used }; void SetCurrentThreadName(const char* name); } // namespace Common