Add mutex and condition variable polyfill for libretro 3DS builds

This commit is contained in:
刘皓 2025-04-27 00:49:47 -04:00
parent a73dec9cad
commit 0b9baa1007
No known key found for this signature in database
GPG key ID: 7901753DB465B711
4 changed files with 111 additions and 41 deletions

View file

@ -26,6 +26,7 @@
#include "etc.h" #include "etc.h"
#include "binding-util.h" #include "binding-util.h"
#include "sharedstate.h" #include "sharedstate.h"
#include "mkxp-polyfill.h" // sprintf
namespace mkxp_sandbox { namespace mkxp_sandbox {
static struct mkxp_sandbox::bindings::rb_data_type color_type; static struct mkxp_sandbox::bindings::rb_data_type color_type;

View file

@ -190,7 +190,7 @@ if not compilers['cpp'].has_header_symbol('thread', 'std::this_thread::yield')
global_args += '-DMKXPZ_NO_STD_THIS_THREAD_YIELD' global_args += '-DMKXPZ_NO_STD_THIS_THREAD_YIELD'
endif endif
if not compilers['cpp'].has_header('pthread.h') or not compilers['cpp'].compiles(''' if not compilers['cpp'].has_header('pthread.h') or not compilers['cpp'].links('''
#include <pthread.h> #include <pthread.h>
int main(void) { int main(void) {
pthread_mutex_t mutex; pthread_mutex_t mutex;
@ -207,9 +207,9 @@ if not compilers['cpp'].has_header('pthread.h') or not compilers['cpp'].compiles
return result; return result;
} }
''', name: 'pthread.h sanity check') ''', name: 'pthread.h sanity check')
global_args += '-DMKXPZ_NO_PTHREAD_H' global_args += is_devkitarm ? '-DMKXPZ_DEVKITARM_NO_PTHREAD_H' : '-DMKXPZ_NO_PTHREAD_H'
global_args += '-DMKXPZ_NO_SEMAPHORE_H' global_args += '-DMKXPZ_NO_SEMAPHORE_H'
elif not compilers['cpp'].has_header('semaphore.h') or not compilers['cpp'].compiles(''' elif not compilers['cpp'].has_header('semaphore.h') or not compilers['cpp'].links('''
#include <semaphore.h> #include <semaphore.h>
int main(void) { int main(void) {
sem_t sem; sem_t sem;

View file

@ -80,16 +80,33 @@ extern "C" void mkxp_aligned_free(void *ptr) {
#endif #endif
} }
#ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
extern "C" {
void *threadGetCurrent(void);
void LightLock_Init(_LOCK_T *);
void LightLock_Lock(_LOCK_T *);
void LightLock_Unlock(_LOCK_T *);
void RecursiveLock_Init(_LOCK_RECURSIVE_T *);
void RecursiveLock_Lock(_LOCK_RECURSIVE_T *);
void RecursiveLock_Unlock(_LOCK_RECURSIVE_T *);
void CondVar_Init(mkxp_cond_t *);
void CondVar_Wait(mkxp_cond_t *, _LOCK_T *);
void CondVar_WakeUp(mkxp_cond_t *, int32_t);
};
#endif
#if defined(MKXPZ_NO_SEMAPHORE_H) && !defined(MKXPZ_NO_PTHREAD_H) #if defined(MKXPZ_NO_SEMAPHORE_H) && !defined(MKXPZ_NO_PTHREAD_H)
struct mkxp_sem_private { struct mkxp_sem_private {
unsigned int value; unsigned int value;
pthread_mutex_t mutex; mkxp_mutex_t mutex;
pthread_cond_t cond; mkxp_cond_t cond;
}; };
#endif #endif
extern "C" mkxp_thread_t mkxp_thread_self() { extern "C" mkxp_thread_t mkxp_thread_self() {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return threadGetCurrent();
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_self(); return pthread_self();
#else #else
return 42; return 42;
@ -97,7 +114,15 @@ extern "C" mkxp_thread_t mkxp_thread_self() {
} }
extern "C" int mkxp_mutex_init(mkxp_mutex_t *mutex, bool recursive) { extern "C" int mkxp_mutex_init(mkxp_mutex_t *mutex, bool recursive) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
mutex->recursive = recursive;
if (recursive) {
RecursiveLock_Init(&mutex->inner.recursive);
} else {
LightLock_Init(&mutex->inner.light);
}
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
if (recursive) { if (recursive) {
pthread_mutexattr_t attr; pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr)) { if (pthread_mutexattr_init(&attr)) {
@ -117,7 +142,9 @@ extern "C" int mkxp_mutex_init(mkxp_mutex_t *mutex, bool recursive) {
} }
extern "C" int mkxp_mutex_destroy(mkxp_mutex_t *mutex) { extern "C" int mkxp_mutex_destroy(mkxp_mutex_t *mutex) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_mutex_destroy(mutex); return pthread_mutex_destroy(mutex);
#else #else
assert(!*mutex); assert(!*mutex);
@ -126,7 +153,14 @@ extern "C" int mkxp_mutex_destroy(mkxp_mutex_t *mutex) {
} }
extern "C" int mkxp_mutex_lock(mkxp_mutex_t *mutex) { extern "C" int mkxp_mutex_lock(mkxp_mutex_t *mutex) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
if (mutex->recursive) {
RecursiveLock_Lock(&mutex->inner.recursive);
} else {
LightLock_Lock(&mutex->inner.light);
}
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_mutex_lock(mutex); return pthread_mutex_lock(mutex);
#else #else
++*mutex; ++*mutex;
@ -135,7 +169,14 @@ extern "C" int mkxp_mutex_lock(mkxp_mutex_t *mutex) {
} }
extern "C" int mkxp_mutex_unlock(mkxp_mutex_t *mutex) { extern "C" int mkxp_mutex_unlock(mkxp_mutex_t *mutex) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
if (mutex->recursive) {
RecursiveLock_Unlock(&mutex->inner.recursive);
} else {
LightLock_Unlock(&mutex->inner.light);
}
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_mutex_unlock(mutex); return pthread_mutex_unlock(mutex);
#else #else
assert(*mutex); assert(*mutex);
@ -145,7 +186,10 @@ extern "C" int mkxp_mutex_unlock(mkxp_mutex_t *mutex) {
} }
extern "C" int mkxp_cond_init(mkxp_cond_t *cond) { extern "C" int mkxp_cond_init(mkxp_cond_t *cond) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
CondVar_Init(cond);
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_cond_init(cond, NULL); return pthread_cond_init(cond, NULL);
#else #else
return 0; return 0;
@ -153,7 +197,9 @@ extern "C" int mkxp_cond_init(mkxp_cond_t *cond) {
} }
extern "C" int mkxp_cond_destroy(mkxp_cond_t *cond) { extern "C" int mkxp_cond_destroy(mkxp_cond_t *cond) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_cond_destroy(cond); return pthread_cond_destroy(cond);
#else #else
return 0; return 0;
@ -161,7 +207,10 @@ extern "C" int mkxp_cond_destroy(mkxp_cond_t *cond) {
} }
extern "C" int mkxp_cond_signal(mkxp_cond_t *cond) { extern "C" int mkxp_cond_signal(mkxp_cond_t *cond) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
CondVar_WakeUp(cond, 1);
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_cond_signal(cond); return pthread_cond_signal(cond);
#else #else
return 0; return 0;
@ -169,7 +218,10 @@ extern "C" int mkxp_cond_signal(mkxp_cond_t *cond) {
} }
extern "C" int mkxp_cond_broadcast(mkxp_cond_t *cond) { extern "C" int mkxp_cond_broadcast(mkxp_cond_t *cond) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
CondVar_WakeUp(cond, -1);
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_cond_broadcast(cond); return pthread_cond_broadcast(cond);
#else #else
return 0; return 0;
@ -177,7 +229,13 @@ extern "C" int mkxp_cond_broadcast(mkxp_cond_t *cond) {
} }
extern "C" int mkxp_cond_wait(mkxp_cond_t *cond, mkxp_mutex_t *mutex) { extern "C" int mkxp_cond_wait(mkxp_cond_t *cond, mkxp_mutex_t *mutex) {
#ifndef MKXPZ_NO_PTHREAD_H #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
if (mutex->recursive) {
std::abort();
}
CondVar_Wait(cond, &mutex->inner.light);
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_cond_wait(cond, mutex); return pthread_cond_wait(cond, mutex);
#else #else
return 0; return 0;
@ -189,13 +247,13 @@ extern "C" int mkxp_sem_init(mkxp_sem_t *sem, unsigned int value) {
return sem_init(sem, 0, value); return sem_init(sem, 0, value);
#elif !defined(MKXPZ_NO_PTHREAD_H) #elif !defined(MKXPZ_NO_PTHREAD_H)
*sem = (void *)new mkxp_sem_private; *sem = (void *)new mkxp_sem_private;
int mutex_init_result = pthread_mutex_init(&((struct mkxp_sem_private *)*sem)->mutex, NULL); int mutex_init_result = mkxp_mutex_init(&((struct mkxp_sem_private *)*sem)->mutex, false);
if (mutex_init_result) { if (mutex_init_result) {
return -1; return -1;
} }
int cond_init_result = pthread_cond_init(&((struct mkxp_sem_private *)*sem)->cond, NULL); int cond_init_result = mkxp_cond_init(&((struct mkxp_sem_private *)*sem)->cond);
if (cond_init_result) { if (cond_init_result) {
pthread_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex); mkxp_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex);
return -1; return -1;
} }
((struct mkxp_sem_private *)*sem)->value = value; ((struct mkxp_sem_private *)*sem)->value = value;
@ -210,8 +268,8 @@ extern "C" int mkxp_sem_destroy(mkxp_sem_t *sem) {
#ifndef MKXPZ_NO_SEMAPHORE_H #ifndef MKXPZ_NO_SEMAPHORE_H
return sem_destroy(sem); return sem_destroy(sem);
#elif !defined(MKXPZ_NO_PTHREAD_H) #elif !defined(MKXPZ_NO_PTHREAD_H)
pthread_cond_destroy(&((struct mkxp_sem_private *)*sem)->cond); mkxp_cond_destroy(&((struct mkxp_sem_private *)*sem)->cond);
pthread_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex); mkxp_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex);
delete (struct mkxp_sem_private *)*sem; delete (struct mkxp_sem_private *)*sem;
return 0; return 0;
#else #else
@ -223,10 +281,10 @@ extern "C" int mkxp_sem_post(mkxp_sem_t *sem) {
#ifndef MKXPZ_NO_SEMAPHORE_H #ifndef MKXPZ_NO_SEMAPHORE_H
return sem_post(sem); return sem_post(sem);
#elif !defined(MKXPZ_NO_PTHREAD_H) #elif !defined(MKXPZ_NO_PTHREAD_H)
while (pthread_mutex_lock(&((struct mkxp_sem_private *)*sem)->mutex)) {} while (mkxp_mutex_lock(&((struct mkxp_sem_private *)*sem)->mutex)) {}
++((struct mkxp_sem_private *)*sem)->value; ++((struct mkxp_sem_private *)*sem)->value;
pthread_cond_signal(&((struct mkxp_sem_private *)*sem)->cond); mkxp_cond_signal(&((struct mkxp_sem_private *)*sem)->cond);
pthread_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex); mkxp_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex);
return 0; return 0;
#else #else
++*sem; ++*sem;
@ -238,14 +296,14 @@ extern "C" int mkxp_sem_wait(mkxp_sem_t *sem) {
#ifndef MKXPZ_NO_SEMAPHORE_H #ifndef MKXPZ_NO_SEMAPHORE_H
return sem_wait(sem); return sem_wait(sem);
#elif !defined(MKXPZ_NO_PTHREAD_H) #elif !defined(MKXPZ_NO_PTHREAD_H)
while (pthread_mutex_lock(&((struct mkxp_sem_private *)*sem)->mutex)) {} while (mkxp_mutex_lock(&((struct mkxp_sem_private *)*sem)->mutex)) {}
for (;;) { for (;;) {
if (((struct mkxp_sem_private *)*sem)->value) { if (((struct mkxp_sem_private *)*sem)->value) {
--((struct mkxp_sem_private *)*sem)->value; --((struct mkxp_sem_private *)*sem)->value;
pthread_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex); mkxp_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex);
return 0; return 0;
} }
while (pthread_cond_wait(&((struct mkxp_sem_private *)*sem)->cond, &((struct mkxp_sem_private *)*sem)->mutex)) {} while (mkxp_cond_wait(&((struct mkxp_sem_private *)*sem)->cond, &((struct mkxp_sem_private *)*sem)->mutex)) {}
} }
#else #else
assert(*sem); assert(*sem);

View file

@ -36,21 +36,18 @@
# include <semaphore.h> # include <semaphore.h>
#endif #endif
#ifdef __cplusplus #ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
#include <array> # include <sys/lock.h>
#include <cstdio> typedef void *mkxp_thread_t;
#include <cstdlib> typedef struct {
#include <mutex> union {
#include <condition_variable> _LOCK_T light;
#include <string> _LOCK_RECURSIVE_T recursive;
} inner;
extern "C" long long strtoll(const char *str, char **str_end, int base); bool recursive;
extern "C" unsigned long long strtoull(const char *str, char **str_end, int base); } mkxp_mutex_t;
typedef int32_t mkxp_cond_t;
extern "C" { #elif !defined(MKXPZ_NO_PTHREAD_H)
#endif
#ifndef MKXPZ_NO_PTHREAD_H
typedef pthread_t mkxp_thread_t; typedef pthread_t mkxp_thread_t;
typedef pthread_mutex_t mkxp_mutex_t; typedef pthread_mutex_t mkxp_mutex_t;
typedef pthread_cond_t mkxp_cond_t; typedef pthread_cond_t mkxp_cond_t;
@ -72,6 +69,20 @@ typedef unsigned int mkxp_sem_t;
# define MKXPZ_HAVE_ANY_ALIGNED_MALLOC 1 # define MKXPZ_HAVE_ANY_ALIGNED_MALLOC 1
#endif #endif
#ifdef __cplusplus
#include <array>
#include <cstdio>
#include <cstdlib>
#include <mutex>
#include <condition_variable>
#include <string>
extern "C" long long strtoll(const char *str, char **str_end, int base);
extern "C" unsigned long long strtoull(const char *str, char **str_end, int base);
extern "C" {
#endif
#ifdef MKXPZ_NO_SPRINTF #ifdef MKXPZ_NO_SPRINTF
int sprintf(char *buffer, const char *format, ...); int sprintf(char *buffer, const char *format, ...);
#endif #endif