mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
c1922783f8
Fix Frame Advance and FifoPlayer pause/unpause/stop. CPU::EnableStepping is not atomic but is called from multiple threads which races and leaves the system in a random state; also instruction stepping was unstable, m_StepEvent had an almost random value because of the dual purpose it served which could cause races where CPU::Run would SingleStep when it was supposed to be sleeping. FifoPlayer never FinishStateMove()d which was causing it to deadlock. Rather than partially reimplementing CPU::Run, just use CPUCoreBase and then call CPU::Run(). More DRY and less likely to have weird bugs specific to the player (i.e the previous freezing on pause/stop). Refactor PowerPC::state into CPU since it manages the state of the CPU Thread which is controlled by CPU, not PowerPC. This simplifies the architecture somewhat and eliminates races that can be caused by calling PowerPC state functions directly instead of using CPU's (because they bypassed the EnableStepping lock).
76 lines
1.6 KiB
C++
76 lines
1.6 KiB
C++
// Copyright 2014 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
// Multithreaded event class. This allows waiting in a thread for an event to
|
|
// be triggered in another thread. While waiting, the CPU will be available for
|
|
// other tasks.
|
|
// * Set(): triggers the event and wakes up the waiting thread.
|
|
// * Wait(): waits for the event to be triggered.
|
|
// * Reset(): tries to reset the event before the waiting thread sees it was
|
|
// triggered. Usually a bad idea.
|
|
|
|
#pragma once
|
|
|
|
#ifdef _WIN32
|
|
#include <concrt.h>
|
|
#endif
|
|
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <mutex>
|
|
|
|
#include "Common/Flag.h"
|
|
|
|
namespace Common {
|
|
|
|
class Event final
|
|
{
|
|
public:
|
|
void Set()
|
|
{
|
|
if (m_flag.TestAndSet())
|
|
{
|
|
std::lock_guard<std::mutex> lk(m_mutex);
|
|
m_condvar.notify_one();
|
|
}
|
|
}
|
|
|
|
void Wait()
|
|
{
|
|
if (m_flag.TestAndClear())
|
|
return;
|
|
|
|
std::unique_lock<std::mutex> lk(m_mutex);
|
|
m_condvar.wait(lk, [&]{ return m_flag.TestAndClear(); });
|
|
}
|
|
|
|
template<class Rep, class Period>
|
|
bool WaitFor(const std::chrono::duration<Rep, Period>& rel_time)
|
|
{
|
|
if (m_flag.TestAndClear())
|
|
return true;
|
|
|
|
std::unique_lock<std::mutex> lk(m_mutex);
|
|
bool signaled = m_condvar.wait_for(lk, rel_time,
|
|
[&]{ return m_flag.TestAndClear(); });
|
|
|
|
return signaled;
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
// no other action required, since wait loops on
|
|
// the predicate and any lingering signal will get
|
|
// cleared on the first iteration
|
|
m_flag.Clear();
|
|
}
|
|
|
|
private:
|
|
Flag m_flag;
|
|
std::condition_variable m_condvar;
|
|
std::mutex m_mutex;
|
|
};
|
|
|
|
} // namespace Common
|