sys_lwcond/cond/ppu_thread: Respect scheduler in various syscalls

This commit is contained in:
Eladash 2023-05-24 21:19:49 +03:00 committed by Ivan
parent 5d4e87373f
commit d152537e50
3 changed files with 402 additions and 202 deletions

View file

@ -143,12 +143,31 @@ error_code sys_cond_signal(ppu_thread& ppu, u32 cond_id)
sys_cond.trace("sys_cond_signal(cond_id=0x%x)", cond_id); sys_cond.trace("sys_cond_signal(cond_id=0x%x)", cond_id);
while (true)
{
if (ppu.test_stopped())
{
ppu.state += cpu_flag::again;
return {};
}
bool finished = true;
ppu.state += cpu_flag::wait;
const auto cond = idm::check<lv2_obj, lv2_cond>(cond_id, [&, notify = lv2_obj::notify_all_t()](lv2_cond& cond) const auto cond = idm::check<lv2_obj, lv2_cond>(cond_id, [&, notify = lv2_obj::notify_all_t()](lv2_cond& cond)
{ {
if (atomic_storage<ppu_thread*>::load(cond.sq)) if (atomic_storage<ppu_thread*>::load(cond.sq))
{ {
std::lock_guard lock(cond.mutex->mutex); std::lock_guard lock(cond.mutex->mutex);
if (ppu.state & cpu_flag::suspend)
{
// Test if another signal caused the current thread to be suspended, in which case it needs to wait until the thread wakes up (otherwise the signal may cause unexpected results)
finished = false;
return;
}
if (const auto cpu = cond.schedule<ppu_thread>(cond.sq, cond.mutex->protocol)) if (const auto cpu = cond.schedule<ppu_thread>(cond.sq, cond.mutex->protocol))
{ {
if (static_cast<ppu_thread*>(cpu)->state & cpu_flag::again) if (static_cast<ppu_thread*>(cpu)->state & cpu_flag::again)
@ -165,8 +184,22 @@ error_code sys_cond_signal(ppu_thread& ppu, u32 cond_id)
} }
} }
} }
else
{
cond.mutex->mutex.lock_unlock();
if (ppu.state & cpu_flag::suspend)
{
finished = false;
}
}
}); });
if (!finished)
{
continue;
}
if (!cond) if (!cond)
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -174,6 +207,7 @@ error_code sys_cond_signal(ppu_thread& ppu, u32 cond_id)
return CELL_OK; return CELL_OK;
} }
}
error_code sys_cond_signal_all(ppu_thread& ppu, u32 cond_id) error_code sys_cond_signal_all(ppu_thread& ppu, u32 cond_id)
{ {
@ -181,12 +215,31 @@ error_code sys_cond_signal_all(ppu_thread& ppu, u32 cond_id)
sys_cond.trace("sys_cond_signal_all(cond_id=0x%x)", cond_id); sys_cond.trace("sys_cond_signal_all(cond_id=0x%x)", cond_id);
while (true)
{
if (ppu.test_stopped())
{
ppu.state += cpu_flag::again;
return {};
}
bool finished = true;
ppu.state += cpu_flag::wait;
const auto cond = idm::check<lv2_obj, lv2_cond>(cond_id, [&, notify = lv2_obj::notify_all_t()](lv2_cond& cond) const auto cond = idm::check<lv2_obj, lv2_cond>(cond_id, [&, notify = lv2_obj::notify_all_t()](lv2_cond& cond)
{ {
if (atomic_storage<ppu_thread*>::load(cond.sq)) if (atomic_storage<ppu_thread*>::load(cond.sq))
{ {
std::lock_guard lock(cond.mutex->mutex); std::lock_guard lock(cond.mutex->mutex);
if (ppu.state & cpu_flag::suspend)
{
// Test if another signal caused the current thread to be suspended, in which case it needs to wait until the thread wakes up (otherwise the signal may cause unexpected results)
finished = false;
return;
}
for (auto cpu = +cond.sq; cpu; cpu = cpu->next_cpu) for (auto cpu = +cond.sq; cpu; cpu = cpu->next_cpu)
{ {
if (cpu->state & cpu_flag::again) if (cpu->state & cpu_flag::again)
@ -213,8 +266,22 @@ error_code sys_cond_signal_all(ppu_thread& ppu, u32 cond_id)
cond.awake(result); cond.awake(result);
} }
} }
else
{
cond.mutex->mutex.lock_unlock();
if (ppu.state & cpu_flag::suspend)
{
finished = false;
}
}
}); });
if (!finished)
{
continue;
}
if (!cond) if (!cond)
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -222,6 +289,7 @@ error_code sys_cond_signal_all(ppu_thread& ppu, u32 cond_id)
return CELL_OK; return CELL_OK;
} }
}
error_code sys_cond_signal_to(ppu_thread& ppu, u32 cond_id, u32 thread_id) error_code sys_cond_signal_to(ppu_thread& ppu, u32 cond_id, u32 thread_id)
{ {
@ -229,7 +297,19 @@ error_code sys_cond_signal_to(ppu_thread& ppu, 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); sys_cond.trace("sys_cond_signal_to(cond_id=0x%x, thread_id=0x%x)", cond_id, thread_id);
const auto cond = idm::check<lv2_obj, lv2_cond>(cond_id, [&, notify = lv2_obj::notify_all_t()](lv2_cond& cond) -> int while (true)
{
if (ppu.test_stopped())
{
ppu.state += cpu_flag::again;
return {};
}
bool finished = true;
ppu.state += cpu_flag::wait;
const auto cond = idm::check<lv2_obj, lv2_cond>(cond_id, [&, notify = lv2_obj::notify_all_t()](lv2_cond& cond)
{ {
if (!idm::check_unlocked<named_thread<ppu_thread>>(thread_id)) if (!idm::check_unlocked<named_thread<ppu_thread>>(thread_id))
{ {
@ -240,6 +320,13 @@ error_code sys_cond_signal_to(ppu_thread& ppu, u32 cond_id, u32 thread_id)
{ {
std::lock_guard lock(cond.mutex->mutex); std::lock_guard lock(cond.mutex->mutex);
if (ppu.state & cpu_flag::suspend)
{
// Test if another signal caused the current thread to be suspended, in which case it needs to wait until the thread wakes up (otherwise the signal may cause unexpected results)
finished = false;
return 0;
}
for (auto cpu = +cond.sq; cpu; cpu = cpu->next_cpu) for (auto cpu = +cond.sq; cpu; cpu = cpu->next_cpu)
{ {
if (cpu->id == thread_id) if (cpu->id == thread_id)
@ -261,10 +348,25 @@ error_code sys_cond_signal_to(ppu_thread& ppu, u32 cond_id, u32 thread_id)
} }
} }
} }
else
{
cond.mutex->mutex.lock_unlock();
if (ppu.state & cpu_flag::suspend)
{
finished = false;
return 0;
}
}
return 0; return 0;
}); });
if (!finished)
{
continue;
}
if (!cond || cond.ret == -1) if (!cond || cond.ret == -1)
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -277,6 +379,7 @@ error_code sys_cond_signal_to(ppu_thread& ppu, u32 cond_id, u32 thread_id)
return CELL_OK; return CELL_OK;
} }
}
error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout) error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
{ {

View file

@ -155,6 +155,18 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u6
fmt::throw_exception("Unknown mode (%d)", mode); fmt::throw_exception("Unknown mode (%d)", mode);
} }
while (true)
{
if (ppu.test_stopped())
{
ppu.state += cpu_flag::again;
return {};
}
bool finished = true;
ppu.state += cpu_flag::wait;
const auto cond = idm::check<lv2_obj, lv2_lwcond>(lwcond_id, [&, notify = lv2_obj::notify_all_t()](lv2_lwcond& cond) -> int const auto cond = idm::check<lv2_obj, lv2_lwcond>(lwcond_id, [&, notify = lv2_obj::notify_all_t()](lv2_lwcond& cond) -> int
{ {
ppu_thread* cpu = nullptr; ppu_thread* cpu = nullptr;
@ -185,6 +197,13 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u6
{ {
std::lock_guard lock(cond.mutex); std::lock_guard lock(cond.mutex);
if (ppu.state & cpu_flag::suspend)
{
// Test if another signal caused the current thread to be suspended, in which case it needs to wait until the thread wakes up (otherwise the signal may cause unexpected results)
finished = false;
return 0;
}
if (cpu) if (cpu)
{ {
if (static_cast<ppu_thread*>(cpu)->state & cpu_flag::again) if (static_cast<ppu_thread*>(cpu)->state & cpu_flag::again)
@ -209,10 +228,7 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u6
{ {
static_cast<ppu_thread*>(result)->gpr[3] = CELL_EBUSY; static_cast<ppu_thread*>(result)->gpr[3] = CELL_EBUSY;
} }
else if (mode == 3 && mutex->load_sq()) [[unlikely]]
if (mode != 2)
{
if (mode == 3 && mutex->load_sq()) [[unlikely]]
{ {
std::lock_guard lock(mutex->mutex); std::lock_guard lock(mutex->mutex);
@ -237,7 +253,6 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u6
mutex->try_own(result, true); mutex->try_own(result, true);
result = nullptr; result = nullptr;
} }
}
if (result) if (result)
{ {
@ -247,10 +262,25 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u6
return 1; return 1;
} }
} }
else
{
cond.mutex.lock_unlock();
if (ppu.state & cpu_flag::suspend)
{
finished = false;
return 0;
}
}
return 0; return 0;
}); });
if (!finished)
{
continue;
}
if (!cond || cond.ret == -1) if (!cond || cond.ret == -1)
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -275,6 +305,7 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u6
return CELL_OK; return CELL_OK;
} }
}
error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u32 mode) error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u32 mode)
{ {
@ -290,7 +321,19 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
fmt::throw_exception("Unknown mode (%d)", mode); fmt::throw_exception("Unknown mode (%d)", mode);
} }
const auto cond = idm::check<lv2_obj, lv2_lwcond>(lwcond_id, [&, notify = lv2_obj::notify_all_t()](lv2_lwcond& cond) -> s32 while (true)
{
if (ppu.test_stopped())
{
ppu.state += cpu_flag::again;
return {};
}
bool finished = true;
ppu.state += cpu_flag::wait;
const auto cond = idm::check<lv2_obj, lv2_lwcond>(lwcond_id, [&, notify = lv2_obj::notify_all_t()](lv2_lwcond& cond) -> int
{ {
lv2_lwmutex* mutex{}; lv2_lwmutex* mutex{};
@ -308,6 +351,13 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
{ {
std::lock_guard lock(cond.mutex); std::lock_guard lock(cond.mutex);
if (ppu.state & cpu_flag::suspend)
{
// Test if another signal caused the current thread to be suspended, in which case it needs to wait until the thread wakes up (otherwise the signal may cause unexpected results)
finished = false;
return 0;
}
u32 result = 0; u32 result = 0;
for (auto cpu = +cond.sq; cpu; cpu = cpu->next_cpu) for (auto cpu = +cond.sq; cpu; cpu = cpu->next_cpu)
@ -348,10 +398,25 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
return result; return result;
} }
else
{
cond.mutex.lock_unlock();
if (ppu.state & cpu_flag::suspend)
{
finished = false;
return 0;
}
}
return 0; return 0;
}); });
if (!finished)
{
continue;
}
if (!cond || cond.ret == -1) if (!cond || cond.ret == -1)
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -365,6 +430,7 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
return CELL_OK; return CELL_OK;
} }
}
error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout) error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout)
{ {

View file

@ -338,22 +338,50 @@ error_code sys_ppu_thread_get_priority(ppu_thread& ppu, u32 thread_id, vm::ptr<s
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
sys_ppu_thread.trace("sys_ppu_thread_get_priority(thread_id=0x%x, priop=*0x%x)", thread_id, priop); sys_ppu_thread.trace("sys_ppu_thread_get_priority(thread_id=0x%x, priop=*0x%x)", thread_id, priop);
u32 prio{};
if (thread_id == ppu.id) if (thread_id == ppu.id)
{ {
// Fast path for self // Fast path for self
for (; !ppu.is_stopped(); std::this_thread::yield())
{
if (reader_lock lock(lv2_obj::g_mutex); cpu_flag::suspend - ppu.state)
{
prio = ppu.prio.load().prio;
break;
}
ppu.check_state(); ppu.check_state();
*priop = ppu.prio.load().prio; ppu.state += cpu_flag::wait;
}
ppu.check_state();
*priop = prio;
return CELL_OK; return CELL_OK;
} }
u32 prio{}; for (; !ppu.is_stopped(); std::this_thread::yield())
{
bool check_state = false;
const auto thread = idm::check<named_thread<ppu_thread>>(thread_id, [&](ppu_thread& thread) const auto thread = idm::check<named_thread<ppu_thread>>(thread_id, [&](ppu_thread& thread)
{
if (reader_lock lock(lv2_obj::g_mutex); cpu_flag::suspend - ppu.state)
{ {
prio = thread.prio.load().prio; prio = thread.prio.load().prio;
}
else
{
check_state = true;
}
}); });
if (check_state)
{
ppu.check_state();
ppu.state += cpu_flag::wait;
continue;
}
if (!thread) if (!thread)
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -361,6 +389,9 @@ error_code sys_ppu_thread_get_priority(ppu_thread& ppu, u32 thread_id, vm::ptr<s
ppu.check_state(); ppu.check_state();
*priop = prio; *priop = prio;
break;
}
return CELL_OK; return CELL_OK;
} }