Minor cleanup

This commit is contained in:
Nekotekina 2015-07-04 22:23:10 +03:00
parent 3064cf8101
commit 22e1da5e76
19 changed files with 166 additions and 249 deletions

View file

@ -1307,6 +1307,7 @@ void thread_t::start(std::function<std::string()> name, std::function<void()> fu
} }
//ctrl->set_current(false); //ctrl->set_current(false);
vm::reservation_free();
g_thread_count--; g_thread_count--;

View file

@ -81,7 +81,7 @@ void armv7_free_tls(u32 thread)
} }
ARMv7Thread::ARMv7Thread(const std::string& name) 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({}) , ARMv7Context({})
{ {
} }

View file

@ -16,7 +16,7 @@ CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function<
, m_type(type) , m_type(type)
, m_name(name) , m_name(name)
{ {
start(thread_name, [this] start(std::move(thread_name), [this]
{ {
SendDbgCommand(DID_CREATE_THREAD, this); SendDbgCommand(DID_CREATE_THREAD, this);

View file

@ -78,7 +78,7 @@ std::shared_ptr<RawSPUThread> CPUThreadManager::NewRawSPUThread()
{ {
if (m_raw_spu[i].expired()) if (m_raw_spu[i].expired())
{ {
m_raw_spu[i] = result = Emu.GetIdManager().make_ptr<RawSPUThread>("RawSPU " + std::to_string(i), i); m_raw_spu[i] = result = Emu.GetIdManager().make_ptr<RawSPUThread>(std::to_string(i), i);
break; break;
} }
} }

View file

@ -491,7 +491,7 @@ void fill_ppu_exec_map(u32 addr, u32 size)
} }
PPUThread::PPUThread(const std::string& name) 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(); InitRotateMask();
} }

View file

@ -9,7 +9,7 @@
thread_local spu_mfc_arg_t raw_spu_mfc[8] = {}; thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
RawSPUThread::RawSPUThread(const std::string& name, u32 index) 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); Memory.Map(offset, 0x40000);
} }
@ -23,18 +23,16 @@ RawSPUThread::~RawSPUThread()
void RawSPUThread::start() void RawSPUThread::start()
{ {
bool do_start; const bool do_start = status.atomic_op([](u32& status) -> bool
status.atomic_op([&do_start](u32& status)
{ {
if (status & SPU_STATUS_RUNNING) if (status & SPU_STATUS_RUNNING)
{ {
do_start = false; return false;
} }
else else
{ {
status = SPU_STATUS_RUNNING; 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: case SPU_In_MBox_offs:
{ {
ch_in_mbox.push_uncond(value); ch_in_mbox.push_uncond(value);
cv.notify_one();
return true; return true;
} }

View file

@ -57,15 +57,15 @@ public:
} }
g_spu_inter_func_list; g_spu_inter_func_list;
SPUThread::SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset) SPUThread::SPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name, u32 index, u32 offset)
: CPUThread(type, name, [this]{ return fmt::format("%s[0x%x] Thread (%s)[0x%08x]", GetTypeString(), GetId(), GetName(), PC); }) : CPUThread(type, name, std::move(thread_name))
, index(index) , index(index)
, offset(offset) , offset(offset)
{ {
} }
SPUThread::SPUThread(const std::string& name, u32 index) 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) , index(index)
, offset(Memory.MainMem.AllocAlign(0x40000)) , offset(Memory.MainMem.AllocAlign(0x40000))
{ {

View file

@ -571,6 +571,8 @@ public:
ch_snr2.push_uncond(value); ch_snr2.push_uncond(value);
} }
} }
cv.notify_one();
} }
void do_dma_transfer(u32 cmd, spu_mfc_arg_t args); void do_dma_transfer(u32 cmd, spu_mfc_arg_t args);
@ -630,7 +632,7 @@ public:
std::function<void(SPUThread& SPU)> m_custom_task; std::function<void(SPUThread& SPU)> m_custom_task;
protected: protected:
SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset); SPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name, u32 index, u32 offset);
public: public:
SPUThread(const std::string& name, u32 index); SPUThread(const std::string& name, u32 index);

View file

@ -22,11 +22,13 @@ public:
const std::shared_ptr<void> data; const std::shared_ptr<void> data;
const std::type_info& info; const std::type_info& info;
const u32 type; const u32 type;
const u32 id;
template<typename T> force_inline ID_data_t(std::shared_ptr<T> data, u32 type) template<typename T> force_inline ID_data_t(std::shared_ptr<T> data, u32 type, u32 id)
: data(std::move(data)) : data(std::move(data))
, info(typeid(T)) , info(typeid(T))
, type(type) , type(type)
, id(id)
{ {
} }
@ -34,6 +36,7 @@ public:
: data(right.data) : data(right.data)
, info(right.info) , info(right.info)
, type(right.type) , type(right.type)
, id(right.id)
{ {
} }
@ -43,6 +46,7 @@ public:
: data(std::move(const_cast<std::shared_ptr<void>&>(right.data))) : data(std::move(const_cast<std::shared_ptr<void>&>(right.data)))
, info(right.info) , info(right.info)
, type(right.type) , type(right.type)
, id(right.id)
{ {
} }
@ -101,9 +105,9 @@ public:
auto ptr = std::make_shared<T>(std::forward<Args>(args)...); auto ptr = std::make_shared<T>(std::forward<Args>(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) // add new ID of specified type with specified constructor arguments (returns id)
@ -113,7 +117,7 @@ public:
const u32 type = ID_type<T>::type; const u32 type = ID_type<T>::type;
m_id_map.emplace(m_cur_id, ID_data_t(std::make_shared<T>(std::forward<Args>(args)...), type)); m_id_map.emplace(m_cur_id, ID_data_t(std::make_shared<T>(std::forward<Args>(args)...), type, m_cur_id));
return m_cur_id++; return m_cur_id++;
} }

View file

@ -82,7 +82,7 @@ namespace vm
{ {
atomic<const thread_ctrl_t*> m_owner{}; atomic<const thread_ctrl_t*> m_owner{};
std::condition_variable m_cv; std::condition_variable m_cv;
std::mutex m_cv_mutex; std::mutex m_mutex;
public: public:
reservation_mutex_t() reservation_mutex_t()
@ -95,18 +95,18 @@ namespace vm
{ {
auto owner = get_current_thread_ctrl(); auto owner = get_current_thread_ctrl();
std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
while (auto old = m_owner.compare_and_swap(nullptr, owner)) while (auto old = m_owner.compare_and_swap(nullptr, owner))
{ {
std::unique_lock<std::mutex> cv_lock(m_cv_mutex);
m_cv.wait_for(cv_lock, std::chrono::milliseconds(1));
if (old == owner) if (old == owner)
{ {
throw EXCEPTION("Deadlock"); throw EXCEPTION("Deadlock");
} }
old = nullptr; if (!lock) lock.lock();
m_cv.wait_for(lock, std::chrono::milliseconds(1));
} }
do_notify = true; do_notify = true;
@ -195,7 +195,7 @@ namespace vm
return _reservation_break(addr); return _reservation_break(addr);
} }
bool reservation_acquire(void* data, u32 addr, u32 size, const std::function<void()>& callback) bool reservation_acquire(void* data, u32 addr, u32 size, std::function<void()> callback)
{ {
//const auto stamp0 = get_time(); //const auto stamp0 = get_time();
@ -232,7 +232,7 @@ namespace vm
g_reservation_addr = addr; g_reservation_addr = addr;
g_reservation_size = size; g_reservation_size = size;
g_reservation_owner = get_current_thread_ctrl(); g_reservation_owner = get_current_thread_ctrl();
g_reservation_cb = callback; g_reservation_cb = std::move(callback);
// copy data // copy data
memcpy(data, vm::get_ptr(addr), size); memcpy(data, vm::get_ptr(addr), size);
@ -243,7 +243,7 @@ namespace vm
bool reservation_acquire_no_cb(void* data, u32 addr, u32 size) 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) bool reservation_update(u32 addr, const void* data, u32 size)
@ -303,10 +303,10 @@ namespace vm
void reservation_free() void reservation_free()
{ {
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
if (g_reservation_owner == get_current_thread_ctrl()) if (g_reservation_owner == get_current_thread_ctrl())
{ {
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
_reservation_break(g_reservation_addr); _reservation_break(g_reservation_addr);
} }
} }

View file

@ -35,7 +35,7 @@ namespace vm
// break the reservation, return true if it was successfully broken // break the reservation, return true if it was successfully broken
bool reservation_break(u32 addr); bool reservation_break(u32 addr);
// read memory and reserve it for further atomic update, return true if the previous reservation was broken // 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<void()>& callback = nullptr); bool reservation_acquire(void* data, u32 addr, u32 size, std::function<void()> callback = nullptr);
// same as reservation_acquire but does not have the callback argument // 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 // 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); bool reservation_acquire_no_cb(void* data, u32 addr, u32 size);

View file

@ -9,44 +9,36 @@
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Callback.h" #include "Callback.h"
void CallbackManager::Register(std::function<s32(PPUThread& PPU)> func) void CallbackManager::Register(check_cb_t func)
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
m_cb_list.push_back([=](CPUThread& CPU) -> s32 m_check_cb.emplace(std::move(func));
{
if (CPU.GetType() != CPU_THREAD_PPU) throw EXCEPTION("PPU thread expected");
return func(static_cast<PPUThread&>(CPU));
});
} }
void CallbackManager::Async(std::function<void(CPUThread& CPU)> func) void CallbackManager::Async(async_cb_t func)
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
m_async_list.push_back([=](CPUThread& CPU) m_async_cb.emplace(std::move(func));
{
func(CPU);
});
m_cv.notify_one(); m_cv.notify_one();
} }
bool CallbackManager::Check(CPUThread& CPU, s32& result) CallbackManager::check_cb_t CallbackManager::Check()
{ {
std::function<s32(CPUThread& CPU)> func;
{
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (m_cb_list.size()) if (m_check_cb.size())
{ {
func = std::move(m_cb_list.front()); check_cb_t func = std::move(m_check_cb.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() void CallbackManager::Init()
@ -57,26 +49,25 @@ void CallbackManager::Init()
{ {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock(m_mutex);
while (!CPU.CheckStatus()) while (true)
{ {
std::function<void(CPUThread& CPU)> func; CHECK_EMU_STATUS;
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(); 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)); m_cv.wait_for(lock, std::chrono::milliseconds(1));
} }
}; };
@ -109,46 +100,9 @@ void CallbackManager::Clear()
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
m_cb_list.clear(); m_check_cb = {};
m_async_list.clear(); m_async_cb = {};
m_pause_cb_list.clear();
m_cb_thread.reset(); m_cb_thread.reset();
} }
u64 CallbackManager::AddPauseCallback(std::function<PauseResumeCB> func)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_pause_cb_list.push_back({ func, next_tag });
return next_tag++;
}
void CallbackManager::RemovePauseCallback(const u64 tag)
{
std::lock_guard<std::mutex> 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<std::mutex> lock(m_mutex);
for (auto& data : m_pause_cb_list)
{
if (data.cb)
{
data.cb(is_paused);
}
}
}

View file

@ -1,66 +1,31 @@
#pragma once #pragma once
class CPUThread; class CPUThread;
class PPUThread;
typedef void(PauseResumeCB)(bool is_paused);
class CallbackManager class CallbackManager
{ {
using check_cb_t = std::function<s32(CPUThread&)>;
using async_cb_t = std::function<void(CPUThread&)>;
std::mutex m_mutex; std::mutex m_mutex;
std::condition_variable m_cv; std::condition_variable m_cv;
std::vector<std::function<s32(CPUThread&)>> m_cb_list; std::queue<check_cb_t> m_check_cb;
std::vector<std::function<void(CPUThread&)>> m_async_list; std::queue<async_cb_t> m_async_cb;
std::shared_ptr<CPUThread> m_cb_thread; std::shared_ptr<CPUThread> m_cb_thread;
struct PauseResumeCBS
{
std::function<PauseResumeCB> cb;
u64 tag;
};
u64 next_tag; // not initialized, only increased
std::vector<PauseResumeCBS> m_pause_cb_list;
public: public:
void Register(std::function<s32(PPUThread& CPU)> func); // register callback (called in Check() method) // register checked callback (accepts CPUThread&, returns s32)
void Register(check_cb_t func);
void Async(std::function<void(CPUThread& CPU)> 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 Init();
void Clear(); void Clear();
u64 AddPauseCallback(std::function<PauseResumeCB> 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<PauseResumeCB>& func)
: cb_manager(cb_manager)
, cb_tag(cb_manager.AddPauseCallback(func))
{
}
~PauseCallbackRegisterer()
{
cb_manager.RemovePauseCallback(cb_tag);
}
}; };

View file

@ -35,7 +35,6 @@ s32 cellAudioInit()
} }
// reset variables // reset variables
g_audio.start_time = 0;
g_audio.counter = 0; g_audio.counter = 0;
g_audio.keys.clear(); g_audio.keys.clear();
g_audio.start_time = get_system_time(); g_audio.start_time = get_system_time();
@ -137,22 +136,6 @@ s32 cellAudioInit()
Emu.GetAudioManager().GetAudioOut().Quit(); Emu.GetAudioManager().GetAudioOut().Quit();
}); });
u64 last_pause_time;
std::atomic<u64> 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()) while (g_audio.state.load() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped())
{ {
if (Emu.IsPaused()) if (Emu.IsPaused())
@ -161,40 +144,32 @@ s32 cellAudioInit()
continue; continue;
} }
if (added_time)
{
g_audio.start_time += added_time.exchange(0);
}
const u64 stamp0 = get_system_time(); 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) // TODO: send beforemix event (in ~2,6 ms before mixing)
// precise time of sleeping: 5,(3) ms (or 256/48000 sec) // precise time of sleeping: 5,(3) ms (or 256/48000 sec)
const u64 expected_time = g_audio.counter * AUDIO_SAMPLES * MHZ / 48000; 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)); g_audio.thread.cv.wait_for(lock, std::chrono::milliseconds(1));
continue; continue;
} }
// crutch to hide giant lags caused by debugger //// crutch to hide giant lags caused by debugger
const u64 missed_time = stamp0 - g_audio.start_time - expected_time; //const u64 missed_time = time_pos - expected_time;
if (missed_time > AUDIO_SAMPLES * MHZ / 48000) //if (missed_time > AUDIO_SAMPLES * MHZ / 48000)
{ //{
cellAudio.Notice("%f ms adjusted", (float)missed_time / 1000); // cellAudio.Notice("%f ms adjusted", (float)missed_time / 1000);
g_audio.start_time += missed_time; // g_audio.start_time += missed_time;
} //}
g_audio.counter++; g_audio.counter++;
const u32 out_pos = g_audio.counter % BUFFER_NUM; const u32 out_pos = g_audio.counter % BUFFER_NUM;
//if (Emu.IsPaused())
//{
// continue;
//}
bool first_mix = true; bool first_mix = true;
// mixing: // mixing:
@ -427,7 +402,7 @@ s32 cellAudioInit()
} }
//LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", //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<u64> stamp)
std::lock_guard<std::mutex> lock(g_audio.thread.mutex); std::lock_guard<std::mutex> 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; return CELL_OK;
} }

View file

@ -146,9 +146,9 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
{ {
const s32 status = g_msg_dialog->status; const s32 status = g_msg_dialog->status;
Emu.GetCallbackManager().Register([=](PPUThread& PPU) -> s32 Emu.GetCallbackManager().Register([=](CPUThread& CPU) -> s32
{ {
callback(PPU, status, userData); callback(static_cast<PPUThread&>(CPU), status, userData);
return CELL_OK; return CELL_OK;
}); });
} }

View file

@ -302,8 +302,8 @@ struct sys_callback
{ {
vm::ptr<CellSysutilCallback> func; vm::ptr<CellSysutilCallback> func;
vm::ptr<void> arg; vm::ptr<void> arg;
}
} g_sys_callback[4]; g_sys_callback[4];
void sysutilSendSystemCommand(u64 status, u64 param) void sysutilSendSystemCommand(u64 status, u64 param)
{ {
@ -312,9 +312,9 @@ void sysutilSendSystemCommand(u64 status, u64 param)
{ {
if (cb.func) 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<PPUThread&>(CPU), status, param, cb.arg);
return CELL_OK; return CELL_OK;
}); });
} }
@ -325,26 +325,16 @@ s32 cellSysutilCheckCallback(PPUThread& CPU)
{ {
cellSysutil.Log("cellSysutilCheckCallback()"); cellSysutil.Log("cellSysutilCheckCallback()");
s32 res; while (auto func = Emu.GetCallbackManager().Check())
u32 count = 0;
while (Emu.GetCallbackManager().Check(CPU, res))
{ {
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
count++; if (s32 res = func(CPU))
if (res)
{ {
return res; 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; return CELL_OK;
} }

View file

@ -694,6 +694,7 @@ s32 sys_spu_thread_write_spu_mb(u32 id, u32 value)
} }
thread->ch_in_mbox.push_uncond(value); thread->ch_in_mbox.push_uncond(value);
thread->cv.notify_one();
return CELL_OK; return CELL_OK;
} }

View file

@ -37,8 +37,8 @@ static const std::string& BreakPointsDBName = "BreakPoints.dat";
static const u16 bpdb_version = 0x1000; static const u16 bpdb_version = 0x1000;
extern std::atomic<u32> g_thread_count; extern std::atomic<u32> g_thread_count;
extern u64 get_system_time();
extern void finalize_ppu_exec_map(); extern void finalize_ppu_exec_map();
extern void finalize_psv_modules(); extern void finalize_psv_modules();
extern void clear_all_psv_objects(); extern void clear_all_psv_objects();
@ -64,17 +64,6 @@ Emulator::Emulator()
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() void Emulator::Init()
@ -144,7 +133,11 @@ void Emulator::Load()
GetModuleManager().Init(); 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); 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)) if (!DecryptSelf(m_path, elf_dir + full_name))
{ {
m_status = Stopped;
return; return;
} }
} }
@ -238,12 +232,14 @@ void Emulator::Load()
if (!f.IsOpened()) if (!f.IsOpened())
{ {
LOG_ERROR(LOADER, "Opening '%s' failed", m_path.c_str()); LOG_ERROR(LOADER, "Opening '%s' failed", m_path.c_str());
m_status = Stopped;
return; return;
} }
if (!m_loader.load(f)) if (!m_loader.load(f))
{ {
LOG_ERROR(LOADER, "Loading '%s' failed", m_path.c_str()); LOG_ERROR(LOADER, "Loading '%s' failed", m_path.c_str());
m_status = Stopped;
vm::close(); vm::close();
return; return;
} }
@ -276,6 +272,8 @@ void Emulator::Run()
SendDbgCommand(DID_START_EMU); SendDbgCommand(DID_START_EMU);
m_pause_start_time = 0;
m_pause_amend_time = 0;
m_status = Running; m_status = Running;
GetCPU().Exec(); GetCPU().Exec();
@ -284,28 +282,48 @@ void Emulator::Run()
void Emulator::Pause() 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); 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 t->Sleep(); // trigger status check
} }
SendDbgCommand(DID_PAUSED_EMU); SendDbgCommand(DID_PAUSED_EMU);
GetCallbackManager().RunPauseCallbacks(true);
}
} }
void Emulator::Resume() void Emulator::Resume()
{ {
if (!IsPaused()) return; // try to resume
SendDbgCommand(DID_RESUME_EMU); 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()) for (auto& t : GetCPU().GetAllThreads())
{ {
@ -313,15 +331,16 @@ void Emulator::Resume()
} }
SendDbgCommand(DID_RESUMED_EMU); SendDbgCommand(DID_RESUMED_EMU);
GetCallbackManager().RunPauseCallbacks(false);
} }
extern std::map<u32, std::string> g_armv7_dump; extern std::map<u32, std::string> g_armv7_dump;
void Emulator::Stop() void Emulator::Stop()
{ {
if(IsStopped()) return; if (sync_lock_test_and_set(&m_status, Stopped) == Stopped)
{
return;
}
SendDbgCommand(DID_STOP_EMU); SendDbgCommand(DID_STOP_EMU);

View file

@ -54,6 +54,9 @@ class Emulator
volatile u32 m_status; volatile u32 m_status;
uint m_mode; uint m_mode;
std::atomic<u64> m_pause_start_time; // set when paused
std::atomic<u64> m_pause_amend_time; // increased when resumed
u32 m_rsx_callback; u32 m_rsx_callback;
u32 m_cpu_thr_stop; u32 m_cpu_thr_stop;
@ -62,17 +65,17 @@ class Emulator
std::mutex m_core_mutex; std::mutex m_core_mutex;
CPUThreadManager* m_thread_manager; std::unique_ptr<CPUThreadManager> m_thread_manager;
PadManager* m_pad_manager; std::unique_ptr<PadManager> m_pad_manager;
KeyboardManager* m_keyboard_manager; std::unique_ptr<KeyboardManager> m_keyboard_manager;
MouseManager* m_mouse_manager; std::unique_ptr<MouseManager> m_mouse_manager;
ID_manager* m_id_manager; std::unique_ptr<ID_manager> m_id_manager;
GSManager* m_gs_manager; std::unique_ptr<GSManager> m_gs_manager;
AudioManager* m_audio_manager; std::unique_ptr<AudioManager> m_audio_manager;
CallbackManager* m_callback_manager; std::unique_ptr<CallbackManager> m_callback_manager;
EventManager* m_event_manager; std::unique_ptr<EventManager> m_event_manager;
ModuleManager* m_module_manager; std::unique_ptr<ModuleManager> m_module_manager;
VFS* m_vfs; std::unique_ptr<VFS> m_vfs;
EmuInfo m_info; EmuInfo m_info;
loader::loader m_loader; loader::loader m_loader;
@ -117,8 +120,12 @@ public:
m_emu_path = path; 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; } CPUThreadManager& GetCPU() { return *m_thread_manager; }
PadManager& GetPadManager() { return *m_pad_manager; } PadManager& GetPadManager() { return *m_pad_manager; }
KeyboardManager& GetKeyboardManager() { return *m_keyboard_manager; } KeyboardManager& GetKeyboardManager() { return *m_keyboard_manager; }