From 43d60a8ac9e5b0f44c50c8fa263ac24957b8eeaf Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sun, 28 Jul 2024 16:31:15 -0700 Subject: [PATCH] Add sem_timedwait polyfill for macOS. --- CMakeLists.txt | 6 ++- .../libraries/kernel/thread_management.cpp | 37 ++++++++++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08cc4103..9cb5f0ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,12 +85,16 @@ if (APPLE) find_package(date 3.0.1 CONFIG) endif() +# Note: Windows always has these functions through winpthreads include(CheckSymbolExists) check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK) -# Windows always has the function through winpthreads if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32) add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK) endif() +check_symbol_exists(sem_timedwait "semaphore.h" HAVE_SEM_TIMEDWAIT) +if(HAVE_SEM_TIMEDWAIT OR WIN32) + add_compile_options(-DHAVE_SEM_TIMEDWAIT) +endif() add_subdirectory(externals) include_directories(src) diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 0992009a..d5e2adea 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -1382,13 +1382,38 @@ int PS4_SYSV_ABI posix_sem_wait(sem_t* sem) { return sem_wait(sem); } -int PS4_SYSV_ABI posix_sem_timedwait(sem_t* sem, const timespec* t) { -#ifndef __APPLE__ - return sem_timedwait(sem, t); -#else - LOG_ERROR(Kernel_Pthread, "Apple doesn't support sem_timedwait yet"); - return 0; // unsupported for apple yet +#ifndef HAVE_SEM_TIMEDWAIT +int sem_timedwait(sem_t* sem, const struct timespec* abstime) { + int rc; + while ((rc = sem_trywait(sem)) == EAGAIN) { + struct timespec curr_time; + clock_gettime(CLOCK_REALTIME, &curr_time); + + s64 remaining_ns = 0; + remaining_ns += + (static_cast(abstime->tv_sec) - static_cast(curr_time.tv_sec)) * 1000000000L; + remaining_ns += static_cast(abstime->tv_nsec) - static_cast(curr_time.tv_nsec); + + if (remaining_ns <= 0) { + return ETIMEDOUT; + } + + struct timespec sleep_time; + sleep_time.tv_sec = 0; + if (remaining_ns < 5000000L) { + sleep_time.tv_nsec = remaining_ns; + } else { + sleep_time.tv_nsec = 5000000; + } + + nanosleep(&sleep_time, nullptr); + } + return rc; +} #endif + +int PS4_SYSV_ABI posix_sem_timedwait(sem_t* sem, const timespec* t) { + return sem_timedwait(sem, t); } int PS4_SYSV_ABI posix_sem_post(sem_t* sem) {