/ src / common / thread.h
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