mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-09 21:31:04 +00:00
semaphore: Fix determining wait status when canceled/deleted (#3490)
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
|
|
||||||
constexpr int ORBIS_KERNEL_SEM_VALUE_MAX = 0x7FFFFFFF;
|
constexpr s32 ORBIS_KERNEL_SEM_VALUE_MAX = 0x7FFFFFFF;
|
||||||
|
|
||||||
struct PthreadSem {
|
struct PthreadSem {
|
||||||
explicit PthreadSem(s32 value_) : semaphore{value_}, value{value_} {}
|
explicit PthreadSem(s32 value_) : semaphore{value_}, value{value_} {}
|
||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
is_fifo{is_fifo} {}
|
is_fifo{is_fifo} {}
|
||||||
~OrbisSem() = default;
|
~OrbisSem() = default;
|
||||||
|
|
||||||
int Wait(bool can_block, s32 need_count, u32* timeout) {
|
s32 Wait(bool can_block, s32 need_count, u32* timeout) {
|
||||||
std::unique_lock lk{mutex};
|
std::unique_lock lk{mutex};
|
||||||
if (token_count >= need_count) {
|
if (token_count >= need_count) {
|
||||||
token_count -= need_count;
|
token_count -= need_count;
|
||||||
@@ -84,13 +84,13 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Cancel(s32 set_count, s32* num_waiters) {
|
s32 Cancel(s32 set_count, s32* num_waiters) {
|
||||||
std::scoped_lock lk{mutex};
|
std::scoped_lock lk{mutex};
|
||||||
if (num_waiters) {
|
if (num_waiters) {
|
||||||
*num_waiters = wait_list.size();
|
*num_waiters = static_cast<s32>(wait_list.size());
|
||||||
}
|
}
|
||||||
for (auto* waiter : wait_list) {
|
for (auto* waiter : wait_list) {
|
||||||
waiter->was_cancled = true;
|
waiter->was_canceled = true;
|
||||||
waiter->sem.release();
|
waiter->sem.release();
|
||||||
}
|
}
|
||||||
wait_list.clear();
|
wait_list.clear();
|
||||||
@@ -115,7 +115,7 @@ public:
|
|||||||
std::string thr_name;
|
std::string thr_name;
|
||||||
bool was_signaled{};
|
bool was_signaled{};
|
||||||
bool was_deleted{};
|
bool was_deleted{};
|
||||||
bool was_cancled{};
|
bool was_canceled{};
|
||||||
|
|
||||||
explicit WaitingThread(s32 need_count, bool is_fifo)
|
explicit WaitingThread(s32 need_count, bool is_fifo)
|
||||||
: sem{0}, priority{0}, need_count{need_count} {
|
: sem{0}, priority{0}, need_count{need_count} {
|
||||||
@@ -127,40 +127,40 @@ public:
|
|||||||
thr_name = g_curthread->name;
|
thr_name = g_curthread->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetResult(bool timed_out) {
|
s32 GetResult() const {
|
||||||
if (timed_out) {
|
if (was_signaled) {
|
||||||
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
if (was_deleted) {
|
if (was_deleted) {
|
||||||
return ORBIS_KERNEL_ERROR_EACCES;
|
return ORBIS_KERNEL_ERROR_EACCES;
|
||||||
}
|
}
|
||||||
if (was_cancled) {
|
if (was_canceled) {
|
||||||
return ORBIS_KERNEL_ERROR_ECANCELED;
|
return ORBIS_KERNEL_ERROR_ECANCELED;
|
||||||
}
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Wait(std::unique_lock<std::mutex>& lk, u32* timeout) {
|
s32 Wait(std::unique_lock<std::mutex>& lk, u32* timeout) {
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
// Wait indefinitely until we are woken up.
|
// Wait indefinitely until we are woken up.
|
||||||
sem.acquire();
|
sem.acquire();
|
||||||
lk.lock();
|
lk.lock();
|
||||||
return GetResult(false);
|
|
||||||
}
|
|
||||||
// Wait until timeout runs out, recording how much remaining time there was.
|
|
||||||
const auto start = std::chrono::high_resolution_clock::now();
|
|
||||||
sem.try_acquire_for(std::chrono::microseconds(*timeout));
|
|
||||||
const auto end = std::chrono::high_resolution_clock::now();
|
|
||||||
const auto time =
|
|
||||||
std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
|
||||||
lk.lock();
|
|
||||||
if (was_signaled) {
|
|
||||||
*timeout -= time;
|
|
||||||
} else {
|
} else {
|
||||||
*timeout = 0;
|
// Wait until timeout runs out, recording how much remaining time there was.
|
||||||
|
const auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
sem.try_acquire_for(std::chrono::microseconds(*timeout));
|
||||||
|
const auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
const auto time =
|
||||||
|
std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
||||||
|
lk.lock();
|
||||||
|
if (was_signaled) {
|
||||||
|
*timeout -= time;
|
||||||
|
} else {
|
||||||
|
*timeout = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return GetResult(!was_signaled);
|
return GetResult();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -228,14 +228,14 @@ s32 PS4_SYSV_ABI sceKernelPollSema(OrbisKernelSema sem, s32 needCount) {
|
|||||||
return orbis_sems[sem]->Wait(false, needCount, nullptr);
|
return orbis_sems[sem]->Wait(false, needCount, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelCancelSema(OrbisKernelSema sem, s32 setCount, s32* pNumWaitThreads) {
|
s32 PS4_SYSV_ABI sceKernelCancelSema(OrbisKernelSema sem, s32 setCount, s32* pNumWaitThreads) {
|
||||||
if (!orbis_sems.is_allocated(sem)) {
|
if (!orbis_sems.is_allocated(sem)) {
|
||||||
return ORBIS_KERNEL_ERROR_ESRCH;
|
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||||
}
|
}
|
||||||
return orbis_sems[sem]->Cancel(setCount, pNumWaitThreads);
|
return orbis_sems[sem]->Cancel(setCount, pNumWaitThreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelDeleteSema(OrbisKernelSema sem) {
|
s32 PS4_SYSV_ABI sceKernelDeleteSema(OrbisKernelSema sem) {
|
||||||
if (!orbis_sems.is_allocated(sem)) {
|
if (!orbis_sems.is_allocated(sem)) {
|
||||||
return ORBIS_KERNEL_ERROR_ESRCH;
|
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||||
}
|
}
|
||||||
@@ -244,18 +244,18 @@ int PS4_SYSV_ABI sceKernelDeleteSema(OrbisKernelSema sem) {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_sem_init(PthreadSem** sem, int pshared, u32 value) {
|
s32 PS4_SYSV_ABI posix_sem_init(PthreadSem** sem, s32 pshared, u32 value) {
|
||||||
if (value > ORBIS_KERNEL_SEM_VALUE_MAX) {
|
if (value > ORBIS_KERNEL_SEM_VALUE_MAX) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (sem != nullptr) {
|
if (sem != nullptr) {
|
||||||
*sem = new PthreadSem(value);
|
*sem = new PthreadSem(static_cast<s32>(value));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_sem_destroy(PthreadSem** sem) {
|
s32 PS4_SYSV_ABI posix_sem_destroy(PthreadSem** sem) {
|
||||||
if (sem == nullptr || *sem == nullptr) {
|
if (sem == nullptr || *sem == nullptr) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -265,7 +265,7 @@ int PS4_SYSV_ABI posix_sem_destroy(PthreadSem** sem) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_sem_wait(PthreadSem** sem) {
|
s32 PS4_SYSV_ABI posix_sem_wait(PthreadSem** sem) {
|
||||||
if (sem == nullptr || *sem == nullptr) {
|
if (sem == nullptr || *sem == nullptr) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -275,7 +275,7 @@ int PS4_SYSV_ABI posix_sem_wait(PthreadSem** sem) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_sem_trywait(PthreadSem** sem) {
|
s32 PS4_SYSV_ABI posix_sem_trywait(PthreadSem** sem) {
|
||||||
if (sem == nullptr || *sem == nullptr) {
|
if (sem == nullptr || *sem == nullptr) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -288,7 +288,7 @@ int PS4_SYSV_ABI posix_sem_trywait(PthreadSem** sem) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_sem_timedwait(PthreadSem** sem, const OrbisKernelTimespec* t) {
|
s32 PS4_SYSV_ABI posix_sem_timedwait(PthreadSem** sem, const OrbisKernelTimespec* t) {
|
||||||
if (sem == nullptr || *sem == nullptr) {
|
if (sem == nullptr || *sem == nullptr) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -301,7 +301,7 @@ int PS4_SYSV_ABI posix_sem_timedwait(PthreadSem** sem, const OrbisKernelTimespec
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_sem_post(PthreadSem** sem) {
|
s32 PS4_SYSV_ABI posix_sem_post(PthreadSem** sem) {
|
||||||
if (sem == nullptr || *sem == nullptr) {
|
if (sem == nullptr || *sem == nullptr) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -315,7 +315,7 @@ int PS4_SYSV_ABI posix_sem_post(PthreadSem** sem) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_sem_getvalue(PthreadSem** sem, int* sval) {
|
s32 PS4_SYSV_ABI posix_sem_getvalue(PthreadSem** sem, s32* sval) {
|
||||||
if (sem == nullptr || *sem == nullptr) {
|
if (sem == nullptr || *sem == nullptr) {
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -326,7 +326,7 @@ int PS4_SYSV_ABI posix_sem_getvalue(PthreadSem** sem, int* sval) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePthreadSemInit(PthreadSem** sem, int flag, u32 value, const char* name) {
|
s32 PS4_SYSV_ABI scePthreadSemInit(PthreadSem** sem, s32 flag, u32 value, const char* name) {
|
||||||
if (flag != 0) {
|
if (flag != 0) {
|
||||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
@@ -388,7 +388,7 @@ s32 PS4_SYSV_ABI scePthreadSemPost(PthreadSem** sem) {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePthreadSemGetvalue(PthreadSem** sem, int* sval) {
|
s32 PS4_SYSV_ABI scePthreadSemGetvalue(PthreadSem** sem, s32* sval) {
|
||||||
s32 ret = posix_sem_getvalue(sem, sval);
|
s32 ret = posix_sem_getvalue(sem, sval);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ErrnoToSceKernelError(*__Error());
|
return ErrnoToSceKernelError(*__Error());
|
||||||
|
|||||||
Reference in New Issue
Block a user