cellSysutil: drain callback queue at single step

This way if a new callback is registered in a process,
it will not be executed immediately in the same loop.
Remove mutex, use lock-free queue.
This commit is contained in:
Nekotekina 2018-12-31 22:03:30 +03:00 committed by Ivan
parent 3b83e223d8
commit 7a4282b4c0
1 changed files with 13 additions and 30 deletions

View File

@ -6,43 +6,27 @@
#include "cellSysutil.h" #include "cellSysutil.h"
#include "Utilities/StrUtil.h" #include "Utilities/StrUtil.h"
#include "Utilities/lockless.h"
#include <mutex>
#include <queue>
LOG_CHANNEL(cellSysutil); LOG_CHANNEL(cellSysutil);
struct sysutil_cb_manager struct sysutil_cb_manager
{ {
std::mutex mutex; struct alignas(8) registered_cb
std::array<std::pair<vm::ptr<CellSysutilCallback>, vm::ptr<void>>, 4> callbacks;
std::queue<std::function<s32(ppu_thread&)>> registered;
std::function<s32(ppu_thread&)> get_cb()
{ {
std::lock_guard lock(mutex); vm::ptr<CellSysutilCallback> first;
vm::ptr<void> second;
};
if (registered.empty()) atomic_t<registered_cb> callbacks[4]{};
{
return nullptr;
}
auto func = std::move(registered.front()); lf_queue<std::function<s32(ppu_thread&)>> registered;
registered.pop();
return func;
}
}; };
extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&& cb) extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&& cb)
{ {
const auto cbm = fxm::get_always<sysutil_cb_manager>(); const auto cbm = fxm::get_always<sysutil_cb_manager>();
std::lock_guard lock(cbm->mutex);
cbm->registered.push(std::move(cb)); cbm->registered.push(std::move(cb));
} }
@ -50,12 +34,10 @@ extern void sysutil_send_system_cmd(u64 status, u64 param)
{ {
if (const auto cbm = fxm::get<sysutil_cb_manager>()) if (const auto cbm = fxm::get<sysutil_cb_manager>())
{ {
for (auto& cb : cbm->callbacks) for (sysutil_cb_manager::registered_cb cb : cbm->callbacks)
{ {
if (cb.first) if (cb.first)
{ {
std::lock_guard lock(cbm->mutex);
cbm->registered.push([=](ppu_thread& ppu) -> s32 cbm->registered.push([=](ppu_thread& ppu) -> s32
{ {
// TODO: check it and find the source of the return value (void isn't equal to CELL_OK) // TODO: check it and find the source of the return value (void isn't equal to CELL_OK)
@ -244,10 +226,11 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu)
const auto cbm = fxm::get_always<sysutil_cb_manager>(); const auto cbm = fxm::get_always<sysutil_cb_manager>();
while (auto func = cbm->get_cb()) for (auto list = cbm->registered.pop_all(); list; list = list->pop_all())
{ {
if (s32 res = func(ppu)) if (s32 res = list->get()(ppu))
{ {
// Currently impossible
return not_an_error(res); return not_an_error(res);
} }
@ -271,7 +254,7 @@ s32 cellSysutilRegisterCallback(s32 slot, vm::ptr<CellSysutilCallback> func, vm:
const auto cbm = fxm::get_always<sysutil_cb_manager>(); const auto cbm = fxm::get_always<sysutil_cb_manager>();
cbm->callbacks[slot] = std::make_pair(func, userdata); cbm->callbacks[slot].store({func, userdata});
return CELL_OK; return CELL_OK;
} }
@ -287,7 +270,7 @@ s32 cellSysutilUnregisterCallback(u32 slot)
const auto cbm = fxm::get_always<sysutil_cb_manager>(); const auto cbm = fxm::get_always<sysutil_cb_manager>();
cbm->callbacks[slot] = std::make_pair(vm::null, vm::null); cbm->callbacks[slot].store({});
return CELL_OK; return CELL_OK;
} }