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 "binding-util.h"
#include "sharedstate.h"
#include "mkxp-polyfill.h" // sprintf
namespace mkxp_sandbox {
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'
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>
int main(void) {
pthread_mutex_t mutex;
@ -207,9 +207,9 @@ if not compilers['cpp'].has_header('pthread.h') or not compilers['cpp'].compiles
return result;
}
''', 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'
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>
int main(void) {
sem_t sem;

View file

@ -80,16 +80,33 @@ extern "C" void mkxp_aligned_free(void *ptr) {
#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)
struct mkxp_sem_private {
unsigned int value;
pthread_mutex_t mutex;
pthread_cond_t cond;
mkxp_mutex_t mutex;
mkxp_cond_t cond;
};
#endif
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();
#else
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) {
#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) {
pthread_mutexattr_t 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) {
#ifndef MKXPZ_NO_PTHREAD_H
#ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_mutex_destroy(mutex);
#else
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) {
#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);
#else
++*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) {
#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);
#else
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) {
#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);
#else
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) {
#ifndef MKXPZ_NO_PTHREAD_H
#ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_cond_destroy(cond);
#else
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) {
#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);
#else
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) {
#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);
#else
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) {
#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);
#else
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);
#elif !defined(MKXPZ_NO_PTHREAD_H)
*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) {
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) {
pthread_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex);
mkxp_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex);
return -1;
}
((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
return sem_destroy(sem);
#elif !defined(MKXPZ_NO_PTHREAD_H)
pthread_cond_destroy(&((struct mkxp_sem_private *)*sem)->cond);
pthread_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex);
mkxp_cond_destroy(&((struct mkxp_sem_private *)*sem)->cond);
mkxp_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex);
delete (struct mkxp_sem_private *)*sem;
return 0;
#else
@ -223,10 +281,10 @@ extern "C" int mkxp_sem_post(mkxp_sem_t *sem) {
#ifndef MKXPZ_NO_SEMAPHORE_H
return sem_post(sem);
#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;
pthread_cond_signal(&((struct mkxp_sem_private *)*sem)->cond);
pthread_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex);
mkxp_cond_signal(&((struct mkxp_sem_private *)*sem)->cond);
mkxp_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex);
return 0;
#else
++*sem;
@ -238,14 +296,14 @@ extern "C" int mkxp_sem_wait(mkxp_sem_t *sem) {
#ifndef MKXPZ_NO_SEMAPHORE_H
return sem_wait(sem);
#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 (;;) {
if (((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;
}
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
assert(*sem);

View file

@ -36,21 +36,18 @@
# include <semaphore.h>
#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
#ifndef MKXPZ_NO_PTHREAD_H
#ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
# include <sys/lock.h>
typedef void *mkxp_thread_t;
typedef struct {
union {
_LOCK_T light;
_LOCK_RECURSIVE_T recursive;
} inner;
bool recursive;
} mkxp_mutex_t;
typedef int32_t mkxp_cond_t;
#elif !defined(MKXPZ_NO_PTHREAD_H)
typedef pthread_t mkxp_thread_t;
typedef pthread_mutex_t mkxp_mutex_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
#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
int sprintf(char *buffer, const char *format, ...);
#endif