thread.h
1 // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <atomic> 8 #include <chrono> 9 #include <condition_variable> 10 #include <cstddef> 11 #include <mutex> 12 #include <thread> 13 #include "common/common_types.h" 14 #include "common/polyfill_thread.h" 15 16 namespace Common { 17 18 class Event { 19 public: 20 void Set() { 21 std::scoped_lock lk{mutex}; 22 if (!is_set) { 23 is_set = true; 24 condvar.notify_one(); 25 } 26 } 27 28 void Wait() { 29 std::unique_lock lk{mutex}; 30 condvar.wait(lk, [&] { return is_set.load(); }); 31 is_set = false; 32 } 33 34 template <class Duration> 35 bool WaitFor(const std::chrono::duration<Duration>& time) { 36 std::unique_lock lk{mutex}; 37 if (!condvar.wait_for(lk, time, [this] { return is_set.load(); })) 38 return false; 39 is_set = false; 40 return true; 41 } 42 43 template <class Clock, class Duration> 44 bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) { 45 std::unique_lock lk{mutex}; 46 if (!condvar.wait_until(lk, time, [this] { return is_set.load(); })) 47 return false; 48 is_set = false; 49 return true; 50 } 51 52 void Reset() { 53 std::unique_lock lk{mutex}; 54 // no other action required, since wait loops on the predicate and any lingering signal will 55 // get cleared on the first iteration 56 is_set = false; 57 } 58 59 [[nodiscard]] bool IsSet() { 60 return is_set; 61 } 62 63 private: 64 std::condition_variable condvar; 65 std::mutex mutex; 66 std::atomic_bool is_set{false}; 67 }; 68 69 class Barrier { 70 public: 71 explicit Barrier(std::size_t count_) : count(count_) {} 72 73 /// Blocks until all "count" threads have called Sync() 74 bool Sync(std::stop_token token = {}) { 75 std::unique_lock lk{mutex}; 76 const std::size_t current_generation = generation; 77 78 if (++waiting == count) { 79 generation++; 80 waiting = 0; 81 condvar.notify_all(); 82 return true; 83 } else { 84 CondvarWait(condvar, lk, token, 85 [this, current_generation] { return current_generation != generation; }); 86 return !token.stop_requested(); 87 } 88 } 89 90 std::size_t Generation() { 91 std::unique_lock lk{mutex}; 92 return generation; 93 } 94 95 private: 96 std::condition_variable_any condvar; 97 std::mutex mutex; 98 std::size_t count; 99 std::size_t waiting = 0; 100 std::size_t generation = 0; // Incremented once each time the barrier is used 101 }; 102 103 enum class ThreadPriority : u32 { 104 Low = 0, 105 Normal = 1, 106 High = 2, 107 VeryHigh = 3, 108 Critical = 4, 109 }; 110 111 void SetCurrentThreadPriority(ThreadPriority new_priority); 112 113 void SetCurrentThreadName(const char* name); 114 115 } // namespace Common