diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index aa968854e3..b9286f2bd5 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1307,6 +1307,7 @@ void thread_t::start(std::function name, std::function fu } //ctrl->set_current(false); + vm::reservation_free(); g_thread_count--; diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index e757ff0301..507f9b57c6 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -81,7 +81,7 @@ void armv7_free_tls(u32 thread) } ARMv7Thread::ARMv7Thread(const std::string& name) - : CPUThread(CPU_THREAD_ARMv7, name, [this]{ return fmt::format("%s[0x%x] Thread (%s)[0x%08x]", GetTypeString(), GetId(), GetName(), PC); }) + : CPUThread(CPU_THREAD_ARMv7, name, WRAP_EXPR(fmt::format("ARMv7[0x%x] Thread (%s)[0x%08x]", GetId(), GetName(), PC))) , ARMv7Context({}) { } diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index f923d316f5..2b0da2d45d 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -16,7 +16,7 @@ CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function< , m_type(type) , m_name(name) { - start(thread_name, [this] + start(std::move(thread_name), [this] { SendDbgCommand(DID_CREATE_THREAD, this); diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index e48a78ee7d..1ef6cc3682 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -78,7 +78,7 @@ std::shared_ptr CPUThreadManager::NewRawSPUThread() { if (m_raw_spu[i].expired()) { - m_raw_spu[i] = result = Emu.GetIdManager().make_ptr("RawSPU " + std::to_string(i), i); + m_raw_spu[i] = result = Emu.GetIdManager().make_ptr(std::to_string(i), i); break; } } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 83b829fb9a..616b39de5e 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -491,7 +491,7 @@ void fill_ppu_exec_map(u32 addr, u32 size) } PPUThread::PPUThread(const std::string& name) - : CPUThread(CPU_THREAD_PPU, name, [this]{ return fmt::format("%s[0x%x] Thread (%s)[0x%08x]", GetTypeString(), GetId(), GetName(), PC); }) + : CPUThread(CPU_THREAD_PPU, name, WRAP_EXPR(fmt::format("PPU[0x%x] Thread (%s)[0x%08x]", GetId(), GetName(), PC))) { InitRotateMask(); } diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 4f484a243e..c5c7ded764 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -9,7 +9,7 @@ thread_local spu_mfc_arg_t raw_spu_mfc[8] = {}; RawSPUThread::RawSPUThread(const std::string& name, u32 index) - : SPUThread(CPU_THREAD_RAW_SPU, name, index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) + : SPUThread(CPU_THREAD_RAW_SPU, name, WRAP_EXPR(fmt::format("RawSPU[0x%x] Thread (%s)[0x%08x]", GetId(), GetName(), PC)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) { Memory.Map(offset, 0x40000); } @@ -23,18 +23,16 @@ RawSPUThread::~RawSPUThread() void RawSPUThread::start() { - bool do_start; - - status.atomic_op([&do_start](u32& status) + const bool do_start = status.atomic_op([](u32& status) -> bool { if (status & SPU_STATUS_RUNNING) { - do_start = false; + return false; } else { status = SPU_STATUS_RUNNING; - do_start = true; + return true; } }); @@ -166,6 +164,7 @@ bool RawSPUThread::WriteReg(const u32 addr, const u32 value) case SPU_In_MBox_offs: { ch_in_mbox.push_uncond(value); + cv.notify_one(); return true; } diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 846aac7b0b..c7e7c4bdc2 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -57,15 +57,15 @@ public: } g_spu_inter_func_list; -SPUThread::SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset) - : CPUThread(type, name, [this]{ return fmt::format("%s[0x%x] Thread (%s)[0x%08x]", GetTypeString(), GetId(), GetName(), PC); }) +SPUThread::SPUThread(CPUThreadType type, const std::string& name, std::function thread_name, u32 index, u32 offset) + : CPUThread(type, name, std::move(thread_name)) , index(index) , offset(offset) { } SPUThread::SPUThread(const std::string& name, u32 index) - : CPUThread(CPU_THREAD_SPU, name, [this]{ return fmt::format("%s[0x%x] Thread (%s)[0x%08x]", GetTypeString(), GetId(), GetName(), PC); }) + : CPUThread(CPU_THREAD_SPU, name, WRAP_EXPR(fmt::format("SPU[0x%x] Thread (%s)[0x%08x]", GetId(), GetName(), PC))) , index(index) , offset(Memory.MainMem.AllocAlign(0x40000)) { diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 46b9e80aee..106d09d36b 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -571,6 +571,8 @@ public: ch_snr2.push_uncond(value); } } + + cv.notify_one(); } void do_dma_transfer(u32 cmd, spu_mfc_arg_t args); @@ -630,7 +632,7 @@ public: std::function m_custom_task; protected: - SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset); + SPUThread(CPUThreadType type, const std::string& name, std::function thread_name, u32 index, u32 offset); public: SPUThread(const std::string& name, u32 index); diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 3783f2f513..fba1d03252 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -22,11 +22,13 @@ public: const std::shared_ptr data; const std::type_info& info; const u32 type; + const u32 id; - template force_inline ID_data_t(std::shared_ptr data, u32 type) + template force_inline ID_data_t(std::shared_ptr data, u32 type, u32 id) : data(std::move(data)) , info(typeid(T)) , type(type) + , id(id) { } @@ -34,6 +36,7 @@ public: : data(right.data) , info(right.info) , type(right.type) + , id(right.id) { } @@ -43,6 +46,7 @@ public: : data(std::move(const_cast&>(right.data))) , info(right.info) , type(right.type) + , id(right.id) { } @@ -101,9 +105,9 @@ public: auto ptr = std::make_shared(std::forward(args)...); - m_id_map.emplace(m_cur_id++, ID_data_t(ptr, type)); + m_id_map.emplace(m_cur_id, ID_data_t(ptr, type, m_cur_id)); - return std::move(ptr); + return m_cur_id++, std::move(ptr); } // add new ID of specified type with specified constructor arguments (returns id) @@ -113,7 +117,7 @@ public: const u32 type = ID_type::type; - m_id_map.emplace(m_cur_id, ID_data_t(std::make_shared(std::forward(args)...), type)); + m_id_map.emplace(m_cur_id, ID_data_t(std::make_shared(std::forward(args)...), type, m_cur_id)); return m_cur_id++; } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index c3e8e422d8..101bc2ef01 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -82,7 +82,7 @@ namespace vm { atomic m_owner{}; std::condition_variable m_cv; - std::mutex m_cv_mutex; + std::mutex m_mutex; public: reservation_mutex_t() @@ -95,18 +95,18 @@ namespace vm { auto owner = get_current_thread_ctrl(); + std::unique_lock lock(m_mutex, std::defer_lock); + while (auto old = m_owner.compare_and_swap(nullptr, owner)) { - std::unique_lock cv_lock(m_cv_mutex); - - m_cv.wait_for(cv_lock, std::chrono::milliseconds(1)); - if (old == owner) { throw EXCEPTION("Deadlock"); } - old = nullptr; + if (!lock) lock.lock(); + + m_cv.wait_for(lock, std::chrono::milliseconds(1)); } do_notify = true; @@ -195,7 +195,7 @@ namespace vm return _reservation_break(addr); } - bool reservation_acquire(void* data, u32 addr, u32 size, const std::function& callback) + bool reservation_acquire(void* data, u32 addr, u32 size, std::function callback) { //const auto stamp0 = get_time(); @@ -232,7 +232,7 @@ namespace vm g_reservation_addr = addr; g_reservation_size = size; g_reservation_owner = get_current_thread_ctrl(); - g_reservation_cb = callback; + g_reservation_cb = std::move(callback); // copy data memcpy(data, vm::get_ptr(addr), size); @@ -243,7 +243,7 @@ namespace vm bool reservation_acquire_no_cb(void* data, u32 addr, u32 size) { - return reservation_acquire(data, addr, size); + return reservation_acquire(data, addr, size, nullptr); } bool reservation_update(u32 addr, const void* data, u32 size) @@ -303,10 +303,10 @@ namespace vm void reservation_free() { - std::lock_guard lock(g_reservation_mutex); - if (g_reservation_owner == get_current_thread_ctrl()) { + std::lock_guard lock(g_reservation_mutex); + _reservation_break(g_reservation_addr); } } diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 5348ffe083..f9d8b2b2ad 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -35,7 +35,7 @@ namespace vm // break the reservation, return true if it was successfully broken bool reservation_break(u32 addr); // read memory and reserve it for further atomic update, return true if the previous reservation was broken - bool reservation_acquire(void* data, u32 addr, u32 size, const std::function& callback = nullptr); + bool reservation_acquire(void* data, u32 addr, u32 size, std::function callback = nullptr); // same as reservation_acquire but does not have the callback argument // used by the PPU LLVM JIT since creating a std::function object in LLVM IR is too complicated bool reservation_acquire_no_cb(void* data, u32 addr, u32 size); diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index abb218cd1f..ccb887bc76 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -9,44 +9,36 @@ #include "Emu/CPU/CPUThreadManager.h" #include "Callback.h" -void CallbackManager::Register(std::function func) +void CallbackManager::Register(check_cb_t 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)); - }); + m_check_cb.emplace(std::move(func)); } -void CallbackManager::Async(std::function func) +void CallbackManager::Async(async_cb_t func) { std::lock_guard lock(m_mutex); - m_async_list.push_back([=](CPUThread& CPU) - { - func(CPU); - }); + m_async_cb.emplace(std::move(func)); m_cv.notify_one(); } -bool CallbackManager::Check(CPUThread& CPU, s32& result) +CallbackManager::check_cb_t CallbackManager::Check() { - std::function func; + std::lock_guard lock(m_mutex); + if (m_check_cb.size()) { - std::lock_guard lock(m_mutex); + check_cb_t func = std::move(m_check_cb.front()); - if (m_cb_list.size()) - { - func = std::move(m_cb_list.front()); - m_cb_list.erase(m_cb_list.begin()); - } + m_check_cb.pop(); + + return func; } - - return func ? result = func(CPU), true : false; + + return nullptr; } void CallbackManager::Init() @@ -57,26 +49,25 @@ void CallbackManager::Init() { std::unique_lock lock(m_mutex); - while (!CPU.CheckStatus()) + while (true) { - 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; - } + CHECK_EMU_STATUS; if (!lock) lock.lock(); + if (m_async_cb.size()) + { + async_cb_t func = std::move(m_async_cb.front()); + + m_async_cb.pop(); + + if (lock) lock.unlock(); + + func(CPU); + + continue; + } + m_cv.wait_for(lock, std::chrono::milliseconds(1)); } }; @@ -109,46 +100,9 @@ void CallbackManager::Clear() { std::lock_guard lock(m_mutex); - m_cb_list.clear(); - m_async_list.clear(); - m_pause_cb_list.clear(); + m_check_cb = {}; + m_async_cb = {}; 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); - } - } -} diff --git a/rpcs3/Emu/SysCalls/Callback.h b/rpcs3/Emu/SysCalls/Callback.h index 3135abd640..1bcf3c5aea 100644 --- a/rpcs3/Emu/SysCalls/Callback.h +++ b/rpcs3/Emu/SysCalls/Callback.h @@ -1,66 +1,31 @@ #pragma once class CPUThread; -class PPUThread; - -typedef void(PauseResumeCB)(bool is_paused); class CallbackManager { + using check_cb_t = std::function; + using async_cb_t = std::function; + std::mutex m_mutex; std::condition_variable m_cv; - std::vector> m_cb_list; - std::vector> m_async_list; + std::queue m_check_cb; + std::queue m_async_cb; + std::shared_ptr m_cb_thread; - struct PauseResumeCBS - { - std::function cb; - u64 tag; - }; - - u64 next_tag; // not initialized, only increased - std::vector m_pause_cb_list; - public: - void Register(std::function func); // register callback (called in Check() method) + // register checked callback (accepts CPUThread&, returns s32) + void Register(check_cb_t func); - void Async(std::function func); // register callback for callback thread (called immediately) + // register async callback, called in callback thread (accepts CPUThread&) + void Async(async_cb_t func); - bool Check(CPUThread& CPU, s32& result); // call one callback registered by Register() method + // get one registered callback + check_cb_t Check(); void Init(); void Clear(); - - u64 AddPauseCallback(std::function func); // register callback for pausing/resuming emulation events - void RemovePauseCallback(const u64 tag); // unregister callback (uses the result of AddPauseCallback() function) - void RunPauseCallbacks(const bool is_paused); -}; - -class PauseCallbackRegisterer -{ - CallbackManager& cb_manager; - u64 cb_tag; - -private: - PauseCallbackRegisterer() = delete; - PauseCallbackRegisterer(const PauseCallbackRegisterer& right) = delete; - PauseCallbackRegisterer(PauseCallbackRegisterer&& right) = delete; - - PauseCallbackRegisterer& operator =(const PauseCallbackRegisterer& right) = delete; - PauseCallbackRegisterer& operator =(PauseCallbackRegisterer&& right) = delete; - -public: - PauseCallbackRegisterer(CallbackManager& cb_manager, const std::function& func) - : cb_manager(cb_manager) - , cb_tag(cb_manager.AddPauseCallback(func)) - { - } - - ~PauseCallbackRegisterer() - { - cb_manager.RemovePauseCallback(cb_tag); - } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 7329b6413a..c464ad8be0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -35,7 +35,6 @@ s32 cellAudioInit() } // reset variables - g_audio.start_time = 0; g_audio.counter = 0; g_audio.keys.clear(); g_audio.start_time = get_system_time(); @@ -137,22 +136,6 @@ s32 cellAudioInit() Emu.GetAudioManager().GetAudioOut().Quit(); }); - u64 last_pause_time; - std::atomic added_time(0); - - PauseCallbackRegisterer pcb(Emu.GetCallbackManager(), [&last_pause_time, &added_time](bool is_paused) - { - if (is_paused) - { - last_pause_time = get_system_time(); - } - else - { - added_time += get_system_time() - last_pause_time; - g_audio.thread.cv.notify_one(); - } - }); - while (g_audio.state.load() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) { if (Emu.IsPaused()) @@ -161,40 +144,32 @@ s32 cellAudioInit() continue; } - if (added_time) - { - g_audio.start_time += added_time.exchange(0); - } - const u64 stamp0 = get_system_time(); + const u64 time_pos = stamp0 - g_audio.start_time - Emu.GetPauseTime(); + // TODO: send beforemix event (in ~2,6 ms before mixing) // precise time of sleeping: 5,(3) ms (or 256/48000 sec) const u64 expected_time = g_audio.counter * AUDIO_SAMPLES * MHZ / 48000; - if (expected_time >= stamp0 - g_audio.start_time) + if (expected_time >= time_pos) { g_audio.thread.cv.wait_for(lock, std::chrono::milliseconds(1)); continue; } - // crutch to hide giant lags caused by debugger - const u64 missed_time = stamp0 - g_audio.start_time - expected_time; - if (missed_time > AUDIO_SAMPLES * MHZ / 48000) - { - cellAudio.Notice("%f ms adjusted", (float)missed_time / 1000); - g_audio.start_time += missed_time; - } + //// crutch to hide giant lags caused by debugger + //const u64 missed_time = time_pos - expected_time; + //if (missed_time > AUDIO_SAMPLES * MHZ / 48000) + //{ + // cellAudio.Notice("%f ms adjusted", (float)missed_time / 1000); + // g_audio.start_time += missed_time; + //} g_audio.counter++; const u32 out_pos = g_audio.counter % BUFFER_NUM; - //if (Emu.IsPaused()) - //{ - // continue; - //} - bool first_mix = true; // mixing: @@ -427,7 +402,7 @@ s32 cellAudioInit() } //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", - //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); + //time_pos, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); } }); @@ -679,7 +654,7 @@ s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) std::lock_guard lock(g_audio.thread.mutex); - *stamp = g_audio.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; + *stamp = g_audio.start_time + Emu.GetPauseTime() + (port.counter + (tag - port.tag)) * 256000000 / 48000; return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp index c16e77d5f5..0916628721 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp @@ -146,9 +146,9 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptrstatus; - Emu.GetCallbackManager().Register([=](PPUThread& PPU) -> s32 + Emu.GetCallbackManager().Register([=](CPUThread& CPU) -> s32 { - callback(PPU, status, userData); + callback(static_cast(CPU), status, userData); return CELL_OK; }); } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp index 19681303cf..419822b202 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp @@ -302,8 +302,8 @@ struct sys_callback { vm::ptr func; vm::ptr arg; - -} g_sys_callback[4]; +} +g_sys_callback[4]; void sysutilSendSystemCommand(u64 status, u64 param) { @@ -312,9 +312,9 @@ void sysutilSendSystemCommand(u64 status, u64 param) { if (cb.func) { - Emu.GetCallbackManager().Register([=](PPUThread& PPU) -> s32 + Emu.GetCallbackManager().Register([=](CPUThread& CPU) -> s32 { - cb.func(PPU, status, param, cb.arg); + cb.func(static_cast(CPU), status, param, cb.arg); return CELL_OK; }); } @@ -325,26 +325,16 @@ s32 cellSysutilCheckCallback(PPUThread& CPU) { cellSysutil.Log("cellSysutilCheckCallback()"); - s32 res; - u32 count = 0; - - while (Emu.GetCallbackManager().Check(CPU, res)) + while (auto func = Emu.GetCallbackManager().Check()) { CHECK_EMU_STATUS; - count++; - - if (res) + if (s32 res = func(CPU)) { return res; } } - if (!count && !g_sys_callback[0].func && !g_sys_callback[1].func && !g_sys_callback[2].func && !g_sys_callback[3].func) - { - LOG_WARNING(TTY, "System warning: no callback registered\n"); - } - return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index 0ae310953a..53d9c11da5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -694,6 +694,7 @@ s32 sys_spu_thread_write_spu_mb(u32 id, u32 value) } thread->ch_in_mbox.push_uncond(value); + thread->cv.notify_one(); return CELL_OK; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 914c57b280..2f88493c9f 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -37,8 +37,8 @@ static const std::string& BreakPointsDBName = "BreakPoints.dat"; static const u16 bpdb_version = 0x1000; extern std::atomic g_thread_count; +extern u64 get_system_time(); extern void finalize_ppu_exec_map(); - extern void finalize_psv_modules(); extern void clear_all_psv_objects(); @@ -64,17 +64,6 @@ Emulator::Emulator() Emulator::~Emulator() { - delete m_thread_manager; - delete m_pad_manager; - delete m_keyboard_manager; - delete m_mouse_manager; - delete m_id_manager; - delete m_gs_manager; - delete m_audio_manager; - delete m_callback_manager; - delete m_event_manager; - delete m_module_manager; - delete m_vfs; } void Emulator::Init() @@ -144,7 +133,11 @@ void Emulator::Load() GetModuleManager().Init(); - if (!fs::is_file(m_path)) return; + if (!fs::is_file(m_path)) + { + m_status = Stopped; + return; + } const std::string elf_dir = m_path.substr(0, m_path.find_last_of("/\\", std::string::npos, 2) + 1); @@ -177,6 +170,7 @@ void Emulator::Load() if (!DecryptSelf(m_path, elf_dir + full_name)) { + m_status = Stopped; return; } } @@ -238,12 +232,14 @@ void Emulator::Load() if (!f.IsOpened()) { LOG_ERROR(LOADER, "Opening '%s' failed", m_path.c_str()); + m_status = Stopped; return; } if (!m_loader.load(f)) { LOG_ERROR(LOADER, "Loading '%s' failed", m_path.c_str()); + m_status = Stopped; vm::close(); return; } @@ -276,6 +272,8 @@ void Emulator::Run() SendDbgCommand(DID_START_EMU); + m_pause_start_time = 0; + m_pause_amend_time = 0; m_status = Running; GetCPU().Exec(); @@ -284,28 +282,48 @@ void Emulator::Run() void Emulator::Pause() { - if (!IsRunning()) return; + const u64 start = get_system_time(); + + // try to set Paused status + if (!sync_bool_compare_and_swap(&m_status, Running, Paused)) + { + return; + } + + // update pause start time + if (m_pause_start_time.exchange(start)) + { + LOG_ERROR(GENERAL, "Pause(): Concurrent access"); + } + SendDbgCommand(DID_PAUSE_EMU); - if (sync_bool_compare_and_swap(&m_status, Running, Paused)) + for (auto& t : GetCPU().GetAllThreads()) { - for (auto& t : GetCPU().GetAllThreads()) - { - t->Sleep(); // trigger status check - } - - SendDbgCommand(DID_PAUSED_EMU); - - GetCallbackManager().RunPauseCallbacks(true); + t->Sleep(); // trigger status check } + + SendDbgCommand(DID_PAUSED_EMU); } void Emulator::Resume() { - if (!IsPaused()) return; - SendDbgCommand(DID_RESUME_EMU); + // try to resume + if (!sync_bool_compare_and_swap(&m_status, Paused, Running)) + { + return; + } - m_status = Running; + if (const u64 time = m_pause_start_time.exchange(0)) + { + m_pause_amend_time += get_system_time() - time; + } + else + { + LOG_ERROR(GENERAL, "Resume(): Concurrent access"); + } + + SendDbgCommand(DID_RESUME_EMU); for (auto& t : GetCPU().GetAllThreads()) { @@ -313,15 +331,16 @@ void Emulator::Resume() } SendDbgCommand(DID_RESUMED_EMU); - - GetCallbackManager().RunPauseCallbacks(false); } extern std::map g_armv7_dump; void Emulator::Stop() { - if(IsStopped()) return; + if (sync_lock_test_and_set(&m_status, Stopped) == Stopped) + { + return; + } SendDbgCommand(DID_STOP_EMU); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 73819719af..308790b69d 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -54,6 +54,9 @@ class Emulator volatile u32 m_status; uint m_mode; + std::atomic m_pause_start_time; // set when paused + std::atomic m_pause_amend_time; // increased when resumed + u32 m_rsx_callback; u32 m_cpu_thr_stop; @@ -62,17 +65,17 @@ class Emulator std::mutex m_core_mutex; - CPUThreadManager* m_thread_manager; - PadManager* m_pad_manager; - KeyboardManager* m_keyboard_manager; - MouseManager* m_mouse_manager; - ID_manager* m_id_manager; - GSManager* m_gs_manager; - AudioManager* m_audio_manager; - CallbackManager* m_callback_manager; - EventManager* m_event_manager; - ModuleManager* m_module_manager; - VFS* m_vfs; + std::unique_ptr m_thread_manager; + std::unique_ptr m_pad_manager; + std::unique_ptr m_keyboard_manager; + std::unique_ptr m_mouse_manager; + std::unique_ptr m_id_manager; + std::unique_ptr m_gs_manager; + std::unique_ptr m_audio_manager; + std::unique_ptr m_callback_manager; + std::unique_ptr m_event_manager; + std::unique_ptr m_module_manager; + std::unique_ptr m_vfs; EmuInfo m_info; loader::loader m_loader; @@ -117,8 +120,12 @@ public: m_emu_path = path; } - std::mutex& GetCoreMutex() { return m_core_mutex; } + u64 GetPauseTime() + { + return m_pause_amend_time; + } + std::mutex& GetCoreMutex() { return m_core_mutex; } CPUThreadManager& GetCPU() { return *m_thread_manager; } PadManager& GetPadManager() { return *m_pad_manager; } KeyboardManager& GetKeyboardManager() { return *m_keyboard_manager; }