#include "stdafx.h" #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" #include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/CPU/CPUThreadManager.h" #include "Callback.h" void CallbackManager::Register(std::function func) { std::lock_guard lock(m_mutex); m_cb_list.push_back([=](CPUThread& CPU) -> s32 { if (CPU.GetType() != CPU_THREAD_PPU) throw EXCEPTION("PPU thread expected"); return func(static_cast(CPU)); }); } void CallbackManager::Async(std::function func) { std::lock_guard lock(m_mutex); m_async_list.push_back([=](CPUThread& CPU) { func(CPU); }); m_cv.notify_one(); } bool CallbackManager::Check(CPUThread& CPU, s32& result) { std::function func; { std::lock_guard lock(m_mutex); if (m_cb_list.size()) { func = std::move(m_cb_list.front()); m_cb_list.erase(m_cb_list.begin()); } } return func ? result = func(CPU), true : false; } void CallbackManager::Init() { std::lock_guard lock(m_mutex); auto task = [this](CPUThread& CPU) { std::unique_lock lock(m_mutex); while (!CPU.CheckStatus()) { std::function func; if (m_async_list.size()) { func = std::move(m_async_list.front()); m_async_list.erase(m_async_list.begin()); } if (func) { if (lock) lock.unlock(); func(*m_cb_thread); continue; } if (!lock) lock.lock(); m_cv.wait_for(lock, std::chrono::milliseconds(1)); } }; if (Memory.PSV.RAM.GetStartAddr()) { auto thread = Emu.GetIdManager().make_ptr("Callback Thread"); thread->prio = 1001; thread->stack_size = 0x10000; thread->custom_task = task; thread->Run(); m_cb_thread = thread; } else { auto thread = Emu.GetIdManager().make_ptr("Callback Thread"); thread->prio = 1001; thread->stack_size = 0x10000; thread->custom_task = task; thread->Run(); m_cb_thread = thread; } } void CallbackManager::Clear() { std::lock_guard lock(m_mutex); m_cb_list.clear(); m_async_list.clear(); m_pause_cb_list.clear(); m_cb_thread.reset(); } u64 CallbackManager::AddPauseCallback(std::function func) { std::lock_guard lock(m_mutex); m_pause_cb_list.push_back({ func, next_tag }); return next_tag++; } void CallbackManager::RemovePauseCallback(const u64 tag) { std::lock_guard lock(m_mutex); for (auto& data : m_pause_cb_list) { if (data.tag == tag) { m_pause_cb_list.erase(m_pause_cb_list.begin() + (&data - m_pause_cb_list.data())); return; } } assert(!"CallbackManager()::RemovePauseCallback(): tag not found"); } void CallbackManager::RunPauseCallbacks(const bool is_paused) { std::lock_guard lock(m_mutex); for (auto& data : m_pause_cb_list) { if (data.cb) { data.cb(is_paused); } } }