eden/src/common/thread.h
lizzie 7c32cf03a1
[core/core_timing] better MWAITX and WAITPKG delays (#3984)
This implements MWAITX and WAITPKG extensions (umonitor, mwait) for CPUs that support them.

Reduces wait times and bypasses the timing stuff from the OS that is slow (windows notably). generally it should answer within 0.2 to 0.5 microsecs (since most requests wait for that long).

Also does a general rework of static ctors and stuff

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3984
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-30 21:59:10 +02:00

106 lines
2.7 KiB
C++

// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <mutex>
#include <thread>
#include "common/common_types.h"
#include "common/polyfill_thread.h"
namespace Common {
class Event {
public:
void Set() {
std::scoped_lock 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;
}
bool WaitFor(const std::chrono::nanoseconds time);
template<class Clock, class Duration>
bool WaitUntil(const std::chrono::time_point<Clock, Duration> 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;
}
[[nodiscard]] bool IsSet() const {
return is_set;
}
private:
alignas(64) std::atomic<bool> is_set{false};
std::condition_variable condvar;
std::mutex mutex;
};
class Barrier {
public:
explicit Barrier(std::size_t count_) : count(count_) {}
/// Blocks until all "count" threads have called Sync()
bool Sync(std::stop_token token = {}) {
std::unique_lock lk{mutex};
const std::size_t current_generation = generation;
if (++waiting == count) {
generation++;
waiting = 0;
condvar.notify_all();
return true;
} else {
condvar.wait(lk, token,
[this, current_generation] { return current_generation != generation; });
return !token.stop_requested();
}
}
private:
std::condition_variable_any condvar;
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
};
enum class ThreadPriority : u32 {
Low = 0,
Normal = 1,
High = 2,
VeryHigh = 3,
Critical = 4,
};
void SetCurrentThreadPriority(ThreadPriority new_priority);
void SetCurrentThreadName(const char* name);
void PinCurrentThreadToPerformanceCore(size_t core_id);
} // namespace Common