mkxp-z/src/mkxp-polyfill.cpp

313 lines
8.1 KiB
C++

/*
** mkxp-polyfill.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 - 2021 Amaryllis Kulla <ancurio@mapleshrine.eu>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mkxp-polyfill.h"
#include <cassert>
#include <stb_sprintf.h>
#ifdef MKXPZ_HAVE_ALIGNED_MALLOC
# include <malloc.h>
#endif
#ifdef MKXPZ_NO_SPRINTF
extern "C" int sprintf(char *buffer, const char *format, ...) {
va_list vlist;
va_start(vlist, format);
int result = stbsp_vsprintf(buffer, buf_size, format, vlist);
va_end(vlist);
return result;
}
#endif
#ifdef MKXPZ_NO_SNPRINTF
extern "C" int snprintf(char *buffer, size_t buf_size, const char *format, ...) {
va_list vlist;
va_start(vlist, format);
int result = stbsp_vsnprintf(buffer, buf_size, format, vlist);
va_end(vlist);
return result;
}
#endif
#ifdef MKXPZ_NO_VSPRINTF
extern "C" int vsprintf(char *buffer, const char *format, va_list vlist) {
return stbsp_vsprintf(buffer, buf_size, format, vlist);
}
#endif
#ifdef MKXPZ_NO_VSNPRINTF
extern "C" int vsnprintf(char *buffer, size_t buf_size, const char *format, va_list vlist) {
return stbsp_vsnprintf(buffer, buf_size, format, vlist);
}
#endif
extern "C" void *mkxp_aligned_malloc(size_t alignment, size_t size) {
#if defined(MKXPZ_HAVE_POSIX_MEMALIGN) || defined(MKXPZ_BUILD_XCODE)
void *mem;
return posix_memalign(&mem, alignment, size) ? NULL : mem;
#elif defined(MKXPZ_HAVE_ALIGNED_MALLOC)
return _aligned_malloc(size, alignment);
#elif defined(MKXPZ_HAVE_ALIGNED_ALLOC)
return aligned_alloc(alignment, size);
#else
return std::malloc(size);
#endif
}
extern "C" void mkxp_aligned_free(void *ptr) {
#if defined(MKXPZ_HAVE_ALIGNED_MALLOC)
_aligned_free(ptr);
#else
std::free(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;
mkxp_mutex_t mutex;
mkxp_cond_t cond;
};
#endif
extern "C" mkxp_thread_t mkxp_thread_self() {
#ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return threadGetCurrent();
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_self();
#else
return 42;
#endif
}
extern "C" int mkxp_mutex_init(mkxp_mutex_t *mutex, bool recursive) {
#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)) {
return -1;
}
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) {
return -1;
}
return pthread_mutex_init(mutex, &attr);
} else {
return pthread_mutex_init(mutex, NULL);
}
#else
*mutex = 0;
return 0;
#endif
}
extern "C" int mkxp_mutex_destroy(mkxp_mutex_t *mutex) {
#ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_mutex_destroy(mutex);
#else
assert(!*mutex);
return 0;
#endif
}
extern "C" int mkxp_mutex_lock(mkxp_mutex_t *mutex) {
#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;
return 0;
#endif
}
extern "C" int mkxp_mutex_unlock(mkxp_mutex_t *mutex) {
#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);
--*mutex;
return 0;
#endif
}
extern "C" int mkxp_cond_init(mkxp_cond_t *cond) {
#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;
#endif
}
extern "C" int mkxp_cond_destroy(mkxp_cond_t *cond) {
#ifdef MKXPZ_DEVKITARM_NO_PTHREAD_H
return 0;
#elif !defined(MKXPZ_NO_PTHREAD_H)
return pthread_cond_destroy(cond);
#else
return 0;
#endif
}
extern "C" int mkxp_cond_signal(mkxp_cond_t *cond) {
#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;
#endif
}
extern "C" int mkxp_cond_broadcast(mkxp_cond_t *cond) {
#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;
#endif
}
extern "C" int mkxp_cond_wait(mkxp_cond_t *cond, mkxp_mutex_t *mutex) {
#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;
#endif
}
extern "C" int mkxp_sem_init(mkxp_sem_t *sem, unsigned int value) {
#ifndef MKXPZ_NO_SEMAPHORE_H
return sem_init(sem, 0, value);
#elif !defined(MKXPZ_NO_PTHREAD_H)
*sem = (void *)new mkxp_sem_private;
int mutex_init_result = mkxp_mutex_init(&((struct mkxp_sem_private *)*sem)->mutex, false);
if (mutex_init_result) {
return -1;
}
int cond_init_result = mkxp_cond_init(&((struct mkxp_sem_private *)*sem)->cond);
if (cond_init_result) {
mkxp_mutex_destroy(&((struct mkxp_sem_private *)*sem)->mutex);
return -1;
}
((struct mkxp_sem_private *)*sem)->value = value;
return 0;
#else
*sem = value;
return 0;
#endif
}
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)
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
return 0;
#endif
}
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 (mkxp_mutex_lock(&((struct mkxp_sem_private *)*sem)->mutex)) {}
++((struct mkxp_sem_private *)*sem)->value;
mkxp_cond_signal(&((struct mkxp_sem_private *)*sem)->cond);
mkxp_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex);
return 0;
#else
++*sem;
return 0;
#endif
}
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 (mkxp_mutex_lock(&((struct mkxp_sem_private *)*sem)->mutex)) {}
for (;;) {
if (((struct mkxp_sem_private *)*sem)->value) {
--((struct mkxp_sem_private *)*sem)->value;
mkxp_mutex_unlock(&((struct mkxp_sem_private *)*sem)->mutex);
return 0;
}
while (mkxp_cond_wait(&((struct mkxp_sem_private *)*sem)->cond, &((struct mkxp_sem_private *)*sem)->mutex)) {}
}
#else
assert(*sem);
--*sem;
return 0;
#endif
}