diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 067ba55a9b..7678041cd8 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -11,6 +11,18 @@ #include #endif +template <> +void fmt_class_string>::format(std::string& out, u64 arg) +{ + // Dynamic format arg + const auto& pair = get_object(arg); + + if (pair.first) + { + pair.first->fmt_string(out, pair.second); + } +} + void fmt_class_string::format(std::string& out, u64 arg) { if (arg) diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp index 84386662b5..4eed846947 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -8,241 +8,277 @@ #include "sys_mutex.h" #include "sys_cond.h" -#include - namespace vm { using namespace ps3; } logs::channel sys_cond("sys_cond", logs::level::notice); extern u64 get_system_time(); -void lv2_cond::notify(lv2_lock_t, cpu_thread* thread) -{ - if (mutex->owner) - { - // add thread to the mutex sleep queue if cannot lock immediately - mutex->sq.emplace_back(thread); - } - else - { - mutex->owner = idm::get(thread->id); - thread->set_signal(); - } -} - -s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr attr) +error_code sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr attr) { sys_cond.warning("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr); - LV2_LOCK; - - const auto mutex = idm::get(mutex_id); - - if (!mutex) - { - return CELL_ESRCH; - } - if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags) { sys_cond.error("sys_cond_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags); return CELL_EINVAL; } - if (!++mutex->cond_count) + auto mutex = idm::get(mutex_id); + + if (!mutex) { - fmt::throw_exception("Unexpected cond_count" HERE); + return CELL_ESRCH; } - *cond_id = idm::make(mutex, attr->name_u64); + if (const u32 id = idm::make(attr->name_u64, std::move(mutex))) + { + *cond_id = id; + return CELL_OK; + } - return CELL_OK; + return CELL_EAGAIN; } -s32 sys_cond_destroy(u32 cond_id) +error_code sys_cond_destroy(u32 cond_id) { sys_cond.warning("sys_cond_destroy(cond_id=0x%x)", cond_id); - LV2_LOCK; + const auto cond = idm::withdraw(cond_id, [&](lv2_cond& cond) -> CellError + { + if (cond.waiters) + { + return CELL_EBUSY; + } - const auto cond = idm::get(cond_id); + cond.mutex->cond_count--; + return {}; + }); if (!cond) { return CELL_ESRCH; } - if (!cond->sq.empty()) + if (cond.ret) { - return CELL_EBUSY; + return cond.ret; } - if (!cond->mutex->cond_count--) - { - fmt::throw_exception("Unexpected cond_count" HERE); - } - - idm::remove(cond_id); - return CELL_OK; } -s32 sys_cond_signal(u32 cond_id) +error_code sys_cond_signal(u32 cond_id) { sys_cond.trace("sys_cond_signal(cond_id=0x%x)", cond_id); - LV2_LOCK; + const auto cond = idm::check(cond_id, [](lv2_cond& cond) -> cpu_thread* + { + if (cond.waiters) + { + semaphore_lock lock(cond.mutex->mutex); - const auto cond = idm::get(cond_id); + if (const auto cpu = cond.schedule(cond.sq, cond.mutex->protocol)) + { + cond.waiters--; + + if (cond.mutex->try_own(*cpu, cpu->id)) + { + return cpu; + } + } + } + + return nullptr; + }); if (!cond) { return CELL_ESRCH; } - // signal one waiting thread; protocol is ignored in current implementation - if (!cond->sq.empty()) + if (cond.ret) { - cond->notify(lv2_lock, cond->sq.front()); - cond->sq.pop_front(); + cond.ret->set_signal(); } return CELL_OK; } -s32 sys_cond_signal_all(u32 cond_id) +error_code sys_cond_signal_all(u32 cond_id) { sys_cond.trace("sys_cond_signal_all(cond_id=0x%x)", cond_id); - LV2_LOCK; + const auto cond = idm::check(cond_id, [](lv2_cond& cond) + { + cpu_thread* result = nullptr; - const auto cond = idm::get(cond_id); + if (cond.waiters) + { + semaphore_lock lock(cond.mutex->mutex); + + while (const auto cpu = cond.schedule(cond.sq, cond.mutex->protocol)) + { + cond.waiters--; + + if (cond.mutex->try_own(*cpu, cpu->id)) + { + result = cpu; + } + } + } + + return result; + }); if (!cond) { return CELL_ESRCH; } - // signal all waiting threads; protocol is ignored in current implementation - for (auto& thread : cond->sq) + if (cond.ret) { - cond->notify(lv2_lock, thread); + cond.ret->set_signal(); } - cond->sq.clear(); - return CELL_OK; } -s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) +error_code sys_cond_signal_to(u32 cond_id, u32 thread_id) { sys_cond.trace("sys_cond_signal_to(cond_id=0x%x, thread_id=0x%x)", cond_id, thread_id); - LV2_LOCK; + const auto cond = idm::check(cond_id, [&](lv2_cond& cond) -> cpu_thread* + { + if (cond.waiters) + { + semaphore_lock lock(cond.mutex->mutex); - const auto cond = idm::get(cond_id); + for (auto cpu : cond.sq) + { + if (cpu->id == thread_id) + { + verify(HERE), cond.unqueue(cond.sq, cpu), cond.waiters--; + + if (cond.mutex->try_own(*cpu, cpu->id)) + { + return cpu; + } + + return (cpu_thread*)(1); + } + } + } + + return nullptr; + }); if (!cond) { return CELL_ESRCH; } - const auto found = std::find_if(cond->sq.begin(), cond->sq.end(), [=](cpu_thread* thread) + if (cond.ret && cond.ret != (cpu_thread*)(1)) { - return thread->id == thread_id; - }); - - // TODO: check if CELL_ESRCH is returned if thread_id is invalid - if (found == cond->sq.end()) - { - return CELL_EPERM; + cond.ret->set_signal(); + } + else if (!cond.ret) + { + return not_an_error(CELL_EPERM); } - - // signal specified thread - cond->notify(lv2_lock, *found); - cond->sq.erase(found); return CELL_OK; } -s32 sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout) +error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout) { sys_cond.trace("sys_cond_wait(cond_id=0x%x, timeout=%lld)", cond_id, timeout); const u64 start_time = get_system_time(); - LV2_LOCK; + const auto cond = idm::get(cond_id, [&](lv2_cond& cond) + { + // Add a "promise" to add a waiter + cond.waiters++; - const auto cond = idm::get(cond_id); + // Save the recursive value + return cond.mutex->lock_count.load(); + }); if (!cond) { return CELL_ESRCH; } - // check current ownership - if (cond->mutex->owner.get() != &ppu) + // Verify ownership + if (cond->mutex->owner >> 1 != ppu.id) { + // Awww + cond->waiters--; return CELL_EPERM; } + else + { + semaphore_lock lock(cond->mutex->mutex); - // save the recursive value - const u32 recursive_value = cond->mutex->recursive_count.exchange(0); + // Register waiter + cond->sq.emplace_back(&ppu); - // unlock the mutex - cond->mutex->unlock(lv2_lock); + // Unlock the mutex + cond->mutex->lock_count = 0; + cond->mutex->reown(); - // add waiter; protocol is ignored in current implementation - sleep_entry waiter(cond->sq, ppu); + // Further function result + ppu.gpr[3] = CELL_OK; + } - // potential mutex waiter (not added immediately) - sleep_entry mutex_waiter(cond->mutex->sq, ppu, defer_sleep); + // SLEEP while (!ppu.state.test_and_reset(cpu_flag::signal)) { - CHECK_EMU_STATUS; - - // timeout is ignored if waiting on the cond var is already dropped - if (timeout && waiter) + if (timeout) { const u64 passed = get_system_time() - start_time; if (passed >= timeout) { - // try to reown mutex and exit if timed out - if (!cond->mutex->owner) + semaphore_lock lock(cond->mutex->mutex); + + // Try to cancel the waiting + if (cond->unqueue(cond->sq, &ppu)) { - cond->mutex->owner = idm::get(ppu.id); - break; + cond->waiters--; + + ppu.gpr[3] = CELL_ETIMEDOUT; + + // Own or requeue + if (cond->mutex->try_own(ppu, ppu.id)) + { + break; + } } - // drop condition variable and start waiting on the mutex queue - mutex_waiter.enter(); - waiter.leave(); + timeout = 0; continue; } - LV2_UNLOCK, thread_ctrl::wait_for(timeout - passed); + thread_ctrl::wait_for(timeout - passed); } else { - LV2_UNLOCK, thread_ctrl::wait(); + thread_ctrl::wait(); } } - // mutex owner is restored after notification or unlocking - if (cond->mutex->owner.get() != &ppu) - { - fmt::throw_exception("Unexpected mutex owner" HERE); - } + // Verify ownership + verify(HERE), cond->mutex->owner >> 1 == ppu.id; - // restore the recursive value - cond->mutex->recursive_count = recursive_value; + // Restore the recursive value + cond->mutex->lock_count = cond.ret; - // check timeout (unclear) - if (timeout && get_system_time() - start_time > timeout) + if (ppu.gpr[3] == CELL_ETIMEDOUT) { - return CELL_ETIMEDOUT; + return not_an_error(CELL_ETIMEDOUT); } return CELL_OK; diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.h b/rpcs3/Emu/Cell/lv2/sys_cond.h index 11143292d9..4e5ed94b54 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.h +++ b/rpcs3/Emu/Cell/lv2/sys_cond.h @@ -21,26 +21,33 @@ struct lv2_cond final : lv2_obj { static const u32 id_base = 0x86000000; + const u32 shared; + const s32 flags; + const u64 key; const u64 name; - const std::shared_ptr mutex; // associated mutex - sleep_queue sq; + std::shared_ptr mutex; // Associated Mutex + atomic_t waiters{0}; + std::deque sq; - lv2_cond(const std::shared_ptr& mutex, u64 name) - : mutex(mutex) + lv2_cond(u64 name, std::shared_ptr mutex) + : shared(0) + , key(0) + , flags(0) , name(name) + , mutex(std::move(mutex)) { + this->mutex->cond_count++; } - - void notify(lv2_lock_t, cpu_thread* thread); }; class ppu_thread; -// SysCalls -s32 sys_cond_create(vm::ps3::ptr cond_id, u32 mutex_id, vm::ps3::ptr attr); -s32 sys_cond_destroy(u32 cond_id); -s32 sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout); -s32 sys_cond_signal(u32 cond_id); -s32 sys_cond_signal_all(u32 cond_id); -s32 sys_cond_signal_to(u32 cond_id, u32 thread_id); +// Syscalls + +error_code sys_cond_create(vm::ps3::ptr cond_id, u32 mutex_id, vm::ps3::ptr attr); +error_code sys_cond_destroy(u32 cond_id); +error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout); +error_code sys_cond_signal(u32 cond_id); +error_code sys_cond_signal_all(u32 cond_id); +error_code sys_cond_signal_to(u32 cond_id, u32 thread_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index b87e2a6818..aa71fc8445 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -13,19 +13,7 @@ logs::channel sys_mutex("sys_mutex", logs::level::notice); extern u64 get_system_time(); -void lv2_mutex::unlock(lv2_lock_t) -{ - owner.reset(); - - if (sq.size()) - { - // pick new owner; protocol is ignored in current implementation - owner = idm::get(sq.front()->id); - owner->set_signal(); - } -} - -s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) +error_code sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) { sys_mutex.warning("sys_mutex_create(mutex_id=*0x%x, attr=*0x%x)", mutex_id, attr); @@ -49,195 +37,176 @@ s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) } } - const bool recursive = attr->recursive == SYS_SYNC_RECURSIVE; + const u32 recursive = attr->recursive; - if ((!recursive && attr->recursive != SYS_SYNC_NOT_RECURSIVE) || attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->adaptive != SYS_SYNC_NOT_ADAPTIVE || attr->ipc_key || attr->flags) + switch (recursive) { - sys_mutex.error("sys_mutex_create(): unknown attributes (recursive=0x%x, pshared=0x%x, adaptive=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->recursive, attr->pshared, attr->adaptive, attr->ipc_key, attr->flags); + case SYS_SYNC_RECURSIVE: break; + case SYS_SYNC_NOT_RECURSIVE: break; + default: + { + sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", recursive); + return CELL_EINVAL; + } + } + if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->adaptive != SYS_SYNC_NOT_ADAPTIVE || attr->ipc_key || attr->flags) + { + sys_mutex.error("sys_mutex_create(): unknown attributes (pshared=0x%x, adaptive=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->adaptive, attr->ipc_key, attr->flags); return CELL_EINVAL; } - *mutex_id = idm::make(recursive, protocol, attr->name_u64); + if (const u32 id = idm::make(protocol, recursive, attr->name_u64)) + { + *mutex_id = id; + return CELL_OK; + } - return CELL_OK; + return CELL_EAGAIN; } -s32 sys_mutex_destroy(u32 mutex_id) +error_code sys_mutex_destroy(u32 mutex_id) { sys_mutex.warning("sys_mutex_destroy(mutex_id=0x%x)", mutex_id); - LV2_LOCK; + const auto mutex = idm::withdraw(mutex_id, [](lv2_mutex& mutex) -> CellError + { + if (mutex.owner || mutex.lock_count) + { + return CELL_EBUSY; + } - const auto mutex = idm::get(mutex_id); + if (mutex.cond_count) + { + return CELL_EPERM; + } + + return {}; + }); if (!mutex) { return CELL_ESRCH; } - if (mutex->owner || mutex->sq.size()) + if (mutex.ret) { - return CELL_EBUSY; + return mutex.ret; } - if (mutex->cond_count) - { - return CELL_EPERM; - } - - idm::remove(mutex_id); - return CELL_OK; } -s32 sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout) +error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout) { sys_mutex.trace("sys_mutex_lock(mutex_id=0x%x, timeout=0x%llx)", mutex_id, timeout); const u64 start_time = get_system_time(); - LV2_LOCK; - - const auto mutex = idm::get(mutex_id); + const auto mutex = idm::get(mutex_id, [&](lv2_mutex& mutex) + { + return mutex.lock(ppu, ppu.id); + }); if (!mutex) { return CELL_ESRCH; } - // check current ownership - if (mutex->owner.get() == &ppu) + if (mutex.ret) { - if (mutex->recursive) + if (mutex.ret != CELL_EBUSY) { - if (mutex->recursive_count == 0xffffffffu) - { - return CELL_EKRESOURCE; - } - - mutex->recursive_count++; - - return CELL_OK; + return mutex.ret; } - - return CELL_EDEADLK; } - - // lock immediately if not locked - if (!mutex->owner) + else { - mutex->owner = idm::get(ppu.id); - return CELL_OK; } - // add waiter; protocol is ignored in current implementation - sleep_entry waiter(mutex->sq, ppu); + // SLEEP while (!ppu.state.test_and_reset(cpu_flag::signal)) { - CHECK_EMU_STATUS; - if (timeout) { const u64 passed = get_system_time() - start_time; if (passed >= timeout) { - return CELL_ETIMEDOUT; + semaphore_lock lock(mutex->mutex); + + if (!mutex->unqueue(mutex->sq, &ppu)) + { + timeout = 0; + continue; + } + + return not_an_error(CELL_ETIMEDOUT); } - LV2_UNLOCK, thread_ctrl::wait_for(timeout - passed); + thread_ctrl::wait_for(timeout - passed); } else { - LV2_UNLOCK, thread_ctrl::wait(); + thread_ctrl::wait(); } } - // new owner must be set when unlocked - if (mutex->owner.get() != &ppu) - { - fmt::throw_exception("Unexpected mutex owner" HERE); - } - return CELL_OK; } -s32 sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id) +error_code sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id) { sys_mutex.trace("sys_mutex_trylock(mutex_id=0x%x)", mutex_id); - LV2_LOCK; - - const auto mutex = idm::get(mutex_id); + const auto mutex = idm::check(mutex_id, [&](lv2_mutex& mutex) + { + return mutex.try_lock(ppu.id); + }); if (!mutex) { return CELL_ESRCH; } - // check current ownership - if (mutex->owner.get() == &ppu) + if (mutex.ret) { - if (mutex->recursive) + if (mutex.ret == CELL_EBUSY) { - if (mutex->recursive_count == 0xffffffffu) - { - return CELL_EKRESOURCE; - } - - mutex->recursive_count++; - - return CELL_OK; + return not_an_error(CELL_EBUSY); } - return CELL_EDEADLK; + return mutex.ret; } - if (mutex->owner) - { - return CELL_EBUSY; - } - - // own the mutex if free - mutex->owner = idm::get(ppu.id); - return CELL_OK; } -s32 sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id) +error_code sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id) { sys_mutex.trace("sys_mutex_unlock(mutex_id=0x%x)", mutex_id); - LV2_LOCK; - - const auto mutex = idm::get(mutex_id); + const auto mutex = idm::check(mutex_id, [&](lv2_mutex& mutex) + { + return mutex.try_unlock(ppu.id); + }); if (!mutex) { return CELL_ESRCH; } - // check current ownership - if (mutex->owner.get() != &ppu) + if (mutex.ret == CELL_EBUSY) { - return CELL_EPERM; - } + semaphore_lock lock(mutex->mutex); - if (mutex->recursive_count) - { - if (!mutex->recursive) - { - fmt::throw_exception("Unexpected recursive_count" HERE); - } - - mutex->recursive_count--; + mutex->reown(); } - else + else if (mutex.ret) { - mutex->unlock(lv2_lock); + return mutex.ret; } return CELL_OK; diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.h b/rpcs3/Emu/Cell/lv2/sys_mutex.h index fa837ff624..90cc6c35c6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.h @@ -23,31 +23,149 @@ struct lv2_mutex final : lv2_obj { static const u32 id_base = 0x85000000; - const bool recursive; const u32 protocol; + const u32 recursive; + const u32 shared; + const u32 adaptive; + const u64 key; const u64 name; + const s32 flags; - atomic_t cond_count{ 0 }; // count of condition variables associated - atomic_t recursive_count{ 0 }; // count of recursive locks - std::shared_ptr owner; // current mutex owner + semaphore<> mutex; + atomic_t owner{0}; // Owner Thread ID + atomic_t lock_count{0}; // Recursive Locks + atomic_t cond_count{0}; // Condition Variables + std::deque sq; - sleep_queue sq; - - lv2_mutex(bool recursive, u32 protocol, u64 name) - : recursive(recursive) - , protocol(protocol) + lv2_mutex(u32 protocol, u32 recursive, u64 name) + : protocol(protocol) + , recursive(recursive) + , shared(0) + , adaptive(0) + , key(0) + , flags(0) , name(name) { } - void unlock(lv2_lock_t); + CellError try_lock(u32 id) + { + const u32 value = owner; + + if (value >> 1 == id) + { + // Recursive locking + if (recursive == SYS_SYNC_RECURSIVE) + { + if (lock_count == 0xffffffffu) + { + return CELL_EKRESOURCE; + } + + lock_count++; + return {}; + } + + return CELL_EDEADLK; + } + + if (value == 0) + { + if (owner.compare_and_swap_test(0, id << 1)) + { + return {}; + } + } + + return CELL_EBUSY; + } + + bool try_own(cpu_thread& cpu, u32 id) + { + if (owner.fetch_op([&](u32& val) + { + if (val == 0) + { + val = id << 1; + } + else + { + val |= 1; + } + })) + { + sq.emplace_back(&cpu); + return false; + } + + return true; + } + + CellError lock(cpu_thread& cpu, u32 id) + { + CellError result = try_lock(id); + + if (result == CELL_EBUSY) + { + semaphore_lock lock(mutex); + + if (try_own(cpu, id)) + { + return {}; + } + } + + return result; + } + + CellError try_unlock(u32 id) + { + const u32 value = owner; + + if (value >> 1 != id) + { + return CELL_EPERM; + } + + if (lock_count) + { + lock_count--; + return {}; + } + + if (value == id << 1) + { + if (owner.compare_and_swap_test(value, 0)) + { + return {}; + } + } + + return CELL_EBUSY; + } + + template + void reown() + { + if (auto cpu = schedule(sq, protocol)) + { + owner = cpu->id << 1 | !sq.empty(); + + cpu->set_signal(); + } + else + { + owner = 0; + } + } }; class ppu_thread; -// SysCalls -s32 sys_mutex_create(vm::ps3::ptr mutex_id, vm::ps3::ptr attr); -s32 sys_mutex_destroy(u32 mutex_id); -s32 sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout); -s32 sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id); -s32 sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id); +// Syscalls + +error_code sys_mutex_create(vm::ps3::ptr mutex_id, vm::ps3::ptr attr); +error_code sys_mutex_destroy(u32 mutex_id); +error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout); +error_code sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id); +error_code sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 8f4aefa432..0dd720fb3a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -6,6 +6,8 @@ #include "Utilities/sema.h" #include "Utilities/cond.h" +#include "Emu/Cell/ErrorCodes.h" + // attr_protocol (waiting scheduling policy) enum { diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index b9d0f25f03..c956ddcd35 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -498,47 +498,46 @@ void Emulator::Stop() s32 error_code::error_report(const fmt_type_info* sup, u64 arg) { - std::string out; + logs::channel* channel = &logs::GENERAL; + logs::level level = logs::level::error; + const char* func = "Unknown function"; if (auto thread = get_current_cpu_thread()) { if (g_system == system_type::ps3 && thread->id_type() == 1) { - if (auto func = static_cast(thread)->last_function) + auto& ppu = static_cast(*thread); + + // Filter some annoying reports + switch (arg) { - out += "'"; - out += func; - out += "'"; + case CELL_EDEADLK: + { + if (ppu.m_name == "_cellsurMixerMain" && std::memcmp(ppu.last_function, "sys_mutex_lock", 15) == 0) + { + level = logs::level::trace; + } + + break; + } + } + + if (ppu.last_function) + { + func = ppu.last_function; } } if (g_system == system_type::psv) { - if (auto func = static_cast(thread)->last_function) + if (auto _func = static_cast(thread)->last_function) { - out += "'"; - out += func; - out += "'"; + func = _func; } } } - if (out.empty()) - { - fmt::append(out, "Unknown function failed with 0x%08x", arg); - } - else - { - fmt::append(out, " failed with 0x%08x", arg); - } - - if (sup) - { - fmt::raw_append(out, " : %s", sup, fmt_args_t{arg}); - } - - LOG_ERROR(GENERAL, "%s", out); - + channel->format(level, "'%s' failed with 0x%08x%s%s", func, arg, sup ? " : " : "", std::make_pair(sup, arg)); return static_cast(arg); } diff --git a/rpcs3/Gui/KernelExplorer.cpp b/rpcs3/Gui/KernelExplorer.cpp index 2e2654a35e..7d76cd02f9 100644 --- a/rpcs3/Gui/KernelExplorer.cpp +++ b/rpcs3/Gui/KernelExplorer.cpp @@ -137,13 +137,14 @@ void KernelExplorer::Update() case SYS_MUTEX_OBJECT: { auto& mutex = static_cast(obj); - m_tree->AppendItem(node, fmt::format("Mutex: ID = 0x%08x \"%s\"", id, +name64(mutex.name))); + m_tree->AppendItem(node, fmt::format("Mutex: ID = 0x%08x \"%s\",%s Owner = 0x%x, Locks = %u, Conds = %u, Wq = %zu", id, +name64(mutex.name), + mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", mutex.owner >> 1, +mutex.lock_count, +mutex.cond_count, mutex.sq.size())); break; } case SYS_COND_OBJECT: { auto& cond = static_cast(obj); - m_tree->AppendItem(node, fmt::format("Cond: ID = 0x%08x \"%s\"", id, +name64(cond.name))); + m_tree->AppendItem(node, fmt::format("Cond: ID = 0x%08x \"%s\", Waiters = %u", id, +name64(cond.name), +cond.waiters)); break; } case SYS_RWLOCK_OBJECT: