mirror of
https://github.com/Pecusx/libretro-atari800.git
synced 2026-05-21 14:49:36 +02:00
path_mkdir instead of mkdir
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (gx_pthread.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _GX_PTHREAD_WRAP_GX_
|
||||
#define _GX_PTHREAD_WRAP_GX_
|
||||
|
||||
#include <ogcsys.h>
|
||||
#include <gccore.h>
|
||||
#include <ogc/cond.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#ifndef OSThread
|
||||
#define OSThread lwp_t
|
||||
#endif
|
||||
|
||||
#ifndef OSCond
|
||||
#define OSCond lwpq_t
|
||||
#endif
|
||||
|
||||
#ifndef OSThreadQueue
|
||||
#define OSThreadQueue lwpq_t
|
||||
#endif
|
||||
|
||||
#ifndef OSInitMutex
|
||||
#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
|
||||
#endif
|
||||
|
||||
#ifndef OSLockMutex
|
||||
#define OSLockMutex(mutex) LWP_MutexLock(mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSUnlockMutex
|
||||
#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSTryLockMutex
|
||||
#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSInitCond
|
||||
#define OSInitCond(cond) LWP_CondInit(cond)
|
||||
#endif
|
||||
|
||||
#ifndef OSWaitCond
|
||||
#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSInitThreadQueue
|
||||
#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
|
||||
#endif
|
||||
|
||||
#ifndef OSSleepThread
|
||||
#define OSSleepThread(queue) LWP_ThreadSleep(queue)
|
||||
#endif
|
||||
|
||||
#ifndef OSJoinThread
|
||||
#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)
|
||||
#endif
|
||||
|
||||
#ifndef OSCreateThread
|
||||
#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)
|
||||
#endif
|
||||
|
||||
#define STACKSIZE (8 * 1024)
|
||||
|
||||
typedef OSThread pthread_t;
|
||||
typedef mutex_t pthread_mutex_t;
|
||||
typedef void* pthread_mutexattr_t;
|
||||
typedef int pthread_attr_t;
|
||||
typedef OSCond pthread_cond_t;
|
||||
typedef OSCond pthread_condattr_t;
|
||||
|
||||
static INLINE int pthread_create(pthread_t *thread,
|
||||
const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
|
||||
{
|
||||
*thread = 0;
|
||||
return OSCreateThread(thread, start_routine, 0 /* unused */, arg,
|
||||
0, STACKSIZE, 64, 0 /* unused */);
|
||||
}
|
||||
|
||||
static INLINE pthread_t pthread_self(void)
|
||||
{
|
||||
/* zero 20-mar-2016: untested */
|
||||
return LWP_GetSelf();
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||
const pthread_mutexattr_t *attr)
|
||||
{
|
||||
return OSInitMutex(mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
return LWP_MutexDestroy(*mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSLockMutex(*mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSUnlockMutex(*mutex);
|
||||
}
|
||||
|
||||
static INLINE void pthread_exit(void *retval)
|
||||
{
|
||||
/* FIXME: No LWP equivalent for this? */
|
||||
(void)retval;
|
||||
}
|
||||
|
||||
static INLINE int pthread_detach(pthread_t thread)
|
||||
{
|
||||
/* FIXME: pthread_detach equivalent missing? */
|
||||
(void)thread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int pthread_join(pthread_t thread, void **retval)
|
||||
{
|
||||
return OSJoinThread(thread, retval);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSTryLockMutex(*mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_wait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSWaitCond(*cond, *mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
return LWP_CondTimedWait(*cond, *mutex, abstime);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *attr)
|
||||
{
|
||||
return OSInitCond(cond);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
return LWP_CondSignal(*cond);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
return LWP_CondBroadcast(*cond);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
return LWP_CondDestroy(*cond);
|
||||
}
|
||||
|
||||
extern int pthread_equal(pthread_t t1, pthread_t t2);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (psp_pthread.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* FIXME: unfinished on PSP, mutexes and condition variables basically a stub. */
|
||||
#ifndef _PSP_PTHREAD_WRAP__
|
||||
#define _PSP_PTHREAD_WRAP__
|
||||
|
||||
#ifdef VITA
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <pspkernel.h>
|
||||
#include <pspthreadman.h>
|
||||
#include <pspthreadman_kernel.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#define STACKSIZE (8 * 1024)
|
||||
|
||||
typedef SceUID pthread_t;
|
||||
typedef SceUID pthread_mutex_t;
|
||||
typedef void* pthread_mutexattr_t;
|
||||
typedef int pthread_attr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SceUID mutex;
|
||||
SceUID sema;
|
||||
int waiting;
|
||||
} pthread_cond_t;
|
||||
|
||||
typedef SceUID pthread_condattr_t;
|
||||
|
||||
/* Use pointer values to create unique names for threads/mutexes */
|
||||
char name_buffer[256];
|
||||
|
||||
typedef void* (*sthreadEntry)(void *argp);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* arg;
|
||||
sthreadEntry start_routine;
|
||||
} sthread_args_struct;
|
||||
|
||||
|
||||
static int psp_thread_wrap(SceSize args, void *argp)
|
||||
{
|
||||
sthread_args_struct* sthread_args = (sthread_args_struct*)argp;
|
||||
|
||||
return (int)sthread_args->start_routine(sthread_args->arg);
|
||||
}
|
||||
|
||||
static INLINE int pthread_create(pthread_t *thread,
|
||||
const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
|
||||
{
|
||||
sprintf(name_buffer, "0x%08X", (uint32_t) thread);
|
||||
|
||||
#ifdef VITA
|
||||
*thread = sceKernelCreateThread(name_buffer, psp_thread_wrap,
|
||||
0x10000100, 0x10000, 0, 0, NULL);
|
||||
#else
|
||||
*thread = sceKernelCreateThread(name_buffer,
|
||||
psp_thread_wrap, 0x20, STACKSIZE, 0, NULL);
|
||||
#endif
|
||||
|
||||
sthread_args_struct sthread_args;
|
||||
sthread_args.arg = arg;
|
||||
sthread_args.start_routine = start_routine;
|
||||
|
||||
return sceKernelStartThread(*thread, sizeof(sthread_args), &sthread_args);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||
const pthread_mutexattr_t *attr)
|
||||
{
|
||||
sprintf(name_buffer, "0x%08X", (uint32_t) mutex);
|
||||
|
||||
#ifdef VITA
|
||||
*mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);
|
||||
if(*mutex<0)
|
||||
return *mutex;
|
||||
return 0;
|
||||
#else
|
||||
return *mutex = sceKernelCreateSema(name_buffer, 0, 1, 1, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
return sceKernelDeleteMutex(*mutex);
|
||||
#else
|
||||
return sceKernelDeleteSema(*mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = sceKernelLockMutex(*mutex, 1, 0);
|
||||
//sceClibPrintf("pthread_mutex_lock: %x\n",ret);
|
||||
return ret;
|
||||
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = sceKernelUnlockMutex(*mutex, 1);
|
||||
//sceClibPrintf("pthread_mutex_unlock: %x\n",ret);
|
||||
return ret;
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static INLINE int pthread_join(pthread_t thread, void **retval)
|
||||
{
|
||||
|
||||
#ifdef VITA
|
||||
int res = sceKernelWaitThreadEnd(thread, 0, 0);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
return sceKernelDeleteThread(thread);
|
||||
#else
|
||||
SceUInt timeout = (SceUInt)-1;
|
||||
sceKernelWaitThreadEnd(thread, &timeout);
|
||||
exit_status = sceKernelGetThreadExitStatus(thread);
|
||||
sceKernelDeleteThread(thread);
|
||||
return exit_status;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
return sceKernelTryLockMutex(*mutex, 1 /* not sure about this last param */);
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_wait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = pthread_mutex_lock(&cond->mutex);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
++cond->waiting;
|
||||
pthread_mutex_unlock(mutex);
|
||||
pthread_mutex_unlock(&cond->mutex);
|
||||
|
||||
ret = sceKernelWaitSema(cond->sema, 1, 0);
|
||||
if (ret < 0) {
|
||||
sceClibPrintf("Premature wakeup: %08X", ret);
|
||||
}
|
||||
pthread_mutex_lock(mutex);
|
||||
return ret;
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
sceKernelDelayThread(10000);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = pthread_mutex_lock(&cond->mutex);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
++cond->waiting;
|
||||
pthread_mutex_unlock(mutex);
|
||||
pthread_mutex_unlock(&cond->mutex);
|
||||
|
||||
SceUInt timeout = 0;
|
||||
|
||||
timeout = abstime->tv_sec;
|
||||
timeout += abstime->tv_nsec / 1.0e6;
|
||||
|
||||
ret = sceKernelWaitSema(cond->sema, 1, &timeout);
|
||||
if (ret < 0) {
|
||||
sceClibPrintf("Premature wakeup: %08X", ret);
|
||||
}
|
||||
pthread_mutex_lock(mutex);
|
||||
return ret;
|
||||
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *attr)
|
||||
{
|
||||
#ifdef VITA
|
||||
|
||||
pthread_mutex_init(&cond->mutex,NULL);
|
||||
sceClibPrintf("pthread_cond_init: mutex %x\n",cond->mutex);
|
||||
if(cond->mutex<0){
|
||||
return cond->mutex;
|
||||
}
|
||||
sprintf(name_buffer, "0x%08X", (uint32_t) cond);
|
||||
//cond->sema = sceKernelCreateCond(name_buffer, 0, cond->mutex, 0);
|
||||
cond->sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);
|
||||
sceClibPrintf("pthread_cond_init: sema %x\n",cond->sema);
|
||||
if(cond->sema<0){
|
||||
pthread_mutex_destroy(&cond->mutex);
|
||||
return cond->sema;
|
||||
}
|
||||
|
||||
cond->waiting = 0;
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
#ifdef VITA
|
||||
pthread_mutex_lock(&cond->mutex);
|
||||
if (cond->waiting) {
|
||||
--cond->waiting;
|
||||
int ret = sceKernelSignalSema(cond->sema, 1);
|
||||
sceClibPrintf("pthread_cond_signal: %x\n",ret);
|
||||
}
|
||||
pthread_mutex_unlock(&cond->mutex);
|
||||
return 0;
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = sceKernelDeleteSema(cond->sema);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
return sceKernelDeleteMutex(cond->mutex);
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static INLINE int pthread_detach(pthread_t thread)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE void pthread_exit(void *retval)
|
||||
{
|
||||
#ifdef VITA
|
||||
sceKernelExitDeleteThread(sceKernelGetThreadId());
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE pthread_t pthread_self(void)
|
||||
{
|
||||
/* zero 20-mar-2016: untested */
|
||||
return sceKernelGetThreadId();
|
||||
}
|
||||
|
||||
static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
|
||||
{
|
||||
return t1 == t2;
|
||||
}
|
||||
|
||||
#endif //_PSP_PTHREAD_WRAP__
|
||||
@@ -0,0 +1,133 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rsemaphore.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef __unix__
|
||||
#define _POSIX_C_SOURCE 199309
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rthreads/rthreads.h>
|
||||
#include <rthreads/rsemaphore.h>
|
||||
|
||||
struct ssem
|
||||
{
|
||||
int value;
|
||||
int wakeups;
|
||||
slock_t *mutex;
|
||||
scond_t *cond;
|
||||
};
|
||||
|
||||
ssem_t *ssem_new(int value)
|
||||
{
|
||||
ssem_t *semaphore = (ssem_t*)calloc(1, sizeof(*semaphore));
|
||||
|
||||
if (!semaphore)
|
||||
goto error;
|
||||
|
||||
semaphore->value = value;
|
||||
semaphore->wakeups = 0;
|
||||
semaphore->mutex = slock_new();
|
||||
|
||||
if (!semaphore->mutex)
|
||||
goto error;
|
||||
|
||||
semaphore->cond = scond_new();
|
||||
|
||||
if (!semaphore->cond)
|
||||
goto error;
|
||||
|
||||
return semaphore;
|
||||
|
||||
error:
|
||||
if (semaphore)
|
||||
{
|
||||
if (semaphore->mutex)
|
||||
slock_free(semaphore->mutex);
|
||||
semaphore->mutex = NULL;
|
||||
free((void*)semaphore);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ssem_free(ssem_t *semaphore)
|
||||
{
|
||||
if (!semaphore)
|
||||
return;
|
||||
|
||||
scond_free(semaphore->cond);
|
||||
slock_free(semaphore->mutex);
|
||||
free((void*)semaphore);
|
||||
}
|
||||
|
||||
int ssem_get(ssem_t *semaphore)
|
||||
{
|
||||
int val = 0;
|
||||
if (!semaphore)
|
||||
return 0;
|
||||
|
||||
slock_lock(semaphore->mutex);
|
||||
|
||||
val = semaphore->value;
|
||||
|
||||
slock_unlock(semaphore->mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void ssem_wait(ssem_t *semaphore)
|
||||
{
|
||||
if (!semaphore)
|
||||
return;
|
||||
|
||||
slock_lock(semaphore->mutex);
|
||||
semaphore->value--;
|
||||
|
||||
if (semaphore->value < 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
scond_wait(semaphore->cond, semaphore->mutex);
|
||||
}while (semaphore->wakeups < 1);
|
||||
|
||||
semaphore->wakeups--;
|
||||
}
|
||||
|
||||
slock_unlock(semaphore->mutex);
|
||||
}
|
||||
|
||||
void ssem_signal(ssem_t *semaphore)
|
||||
{
|
||||
if (!semaphore)
|
||||
return;
|
||||
|
||||
slock_lock(semaphore->mutex);
|
||||
semaphore->value++;
|
||||
|
||||
if (semaphore->value <= 0)
|
||||
{
|
||||
semaphore->wakeups++;
|
||||
scond_signal(semaphore->cond);
|
||||
}
|
||||
|
||||
slock_unlock(semaphore->mutex);
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rthreads.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef __unix__
|
||||
#define _POSIX_C_SOURCE 199309
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
/* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32. Maybe only supported in MSVC>=2005 */
|
||||
|
||||
#if defined(_WIN32) && !defined(RETRO_WIN32_USE_PTHREADS)
|
||||
#define USE_WIN32_THREADS
|
||||
#ifdef _XBOX
|
||||
#include <xtl.h>
|
||||
#else
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#elif defined(GEKKO)
|
||||
#include "gx_pthread.h"
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
#include "psp_pthread.h"
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#include <pthread.h>
|
||||
#include <sys/sys_time.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(VITA)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
struct thread_data
|
||||
{
|
||||
void (*func)(void*);
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
struct sthread
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
HANDLE thread;
|
||||
#else
|
||||
pthread_t id;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct slock
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
HANDLE lock;
|
||||
#else
|
||||
pthread_mutex_t lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct scond
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
HANDLE event;
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
static DWORD CALLBACK thread_wrap(void *data_)
|
||||
#else
|
||||
static void *thread_wrap(void *data_)
|
||||
#endif
|
||||
{
|
||||
struct thread_data *data = (struct thread_data*)data_;
|
||||
if (!data)
|
||||
return 0;
|
||||
data->func(data->userdata);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_create:
|
||||
* @start_routine : thread entry callback function
|
||||
* @userdata : pointer to userdata that will be made
|
||||
* available in thread entry callback function
|
||||
*
|
||||
* Create a new thread.
|
||||
*
|
||||
* Returns: pointer to new thread if successful, otherwise NULL.
|
||||
*/
|
||||
sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
|
||||
{
|
||||
bool thread_created = false;
|
||||
struct thread_data *data = NULL;
|
||||
sthread_t *thread = (sthread_t*)calloc(1, sizeof(*thread));
|
||||
|
||||
if (!thread)
|
||||
return NULL;
|
||||
|
||||
data = (struct thread_data*)calloc(1, sizeof(*data));
|
||||
if (!data)
|
||||
goto error;
|
||||
|
||||
data->func = thread_func;
|
||||
data->userdata = userdata;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
thread->thread = CreateThread(NULL, 0, thread_wrap, data, 0, NULL);
|
||||
thread_created = !!thread->thread;
|
||||
#else
|
||||
thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
|
||||
#endif
|
||||
|
||||
if (!thread_created)
|
||||
goto error;
|
||||
|
||||
return thread;
|
||||
|
||||
error:
|
||||
if (data)
|
||||
free(data);
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_detach:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Detach a thread. When a detached thread terminates, its
|
||||
* resource sare automatically released back to the system
|
||||
* without the need for another thread to join with the
|
||||
* terminated thread.
|
||||
*
|
||||
* Returns: 0 on success, otherwise it returns a non-zero error number.
|
||||
*/
|
||||
int sthread_detach(sthread_t *thread)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
CloseHandle(thread->thread);
|
||||
free(thread);
|
||||
return 0;
|
||||
#else
|
||||
return pthread_detach(thread->id);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_join:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Join with a terminated thread. Waits for the thread specified by
|
||||
* @thread to terminate. If that thread has already terminated, then
|
||||
* it will return immediately. The thread specified by @thread must
|
||||
* be joinable.
|
||||
*
|
||||
* Returns: 0 on success, otherwise it returns a non-zero error number.
|
||||
*/
|
||||
void sthread_join(sthread_t *thread)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
WaitForSingleObject(thread->thread, INFINITE);
|
||||
CloseHandle(thread->thread);
|
||||
#else
|
||||
pthread_join(thread->id, NULL);
|
||||
#endif
|
||||
free(thread);
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_isself:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Join with a terminated thread. Waits for the thread specified by
|
||||
* @thread to terminate. If that thread has already terminated, then
|
||||
* it will return immediately. The thread specified by @thread must
|
||||
* be joinable.
|
||||
*
|
||||
* Returns: true (1) if calling thread is the specified thread
|
||||
*/
|
||||
bool sthread_isself(sthread_t *thread)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
return GetCurrentThread() == thread->thread;
|
||||
#else
|
||||
return pthread_equal(pthread_self(),thread->id);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_new:
|
||||
*
|
||||
* Create and initialize a new mutex. Must be manually
|
||||
* freed.
|
||||
*
|
||||
* Returns: pointer to a new mutex if successful, otherwise NULL.
|
||||
**/
|
||||
slock_t *slock_new(void)
|
||||
{
|
||||
slock_t *lock = (slock_t*)calloc(1, sizeof(*lock));
|
||||
if (!lock)
|
||||
return NULL;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
lock->lock = CreateMutex(NULL, FALSE, NULL);
|
||||
if (!lock->lock)
|
||||
goto error;
|
||||
#else
|
||||
if ((pthread_mutex_init(&lock->lock, NULL) < 0))
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
return lock;
|
||||
|
||||
error:
|
||||
slock_free(lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_free:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Frees a mutex.
|
||||
**/
|
||||
void slock_free(slock_t *lock)
|
||||
{
|
||||
if (!lock)
|
||||
return;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
CloseHandle(lock->lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&lock->lock);
|
||||
#endif
|
||||
free(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_lock:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Locks a mutex. If a mutex is already locked by
|
||||
* another thread, the calling thread shall block until
|
||||
* the mutex becomes available.
|
||||
**/
|
||||
void slock_lock(slock_t *lock)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
WaitForSingleObject(lock->lock, INFINITE);
|
||||
#else
|
||||
pthread_mutex_lock(&lock->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_unlock:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Unlocks a mutex.
|
||||
**/
|
||||
void slock_unlock(slock_t *lock)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
ReleaseMutex(lock->lock);
|
||||
#else
|
||||
pthread_mutex_unlock(&lock->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_new:
|
||||
*
|
||||
* Creates and initializes a condition variable. Must
|
||||
* be manually freed.
|
||||
*
|
||||
* Returns: pointer to new condition variable on success,
|
||||
* otherwise NULL.
|
||||
**/
|
||||
scond_t *scond_new(void)
|
||||
{
|
||||
bool event_created = false;
|
||||
scond_t *cond = (scond_t*)calloc(1, sizeof(*cond));
|
||||
|
||||
if (!cond)
|
||||
return NULL;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
cond->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
event_created = !!cond->event;
|
||||
#else
|
||||
event_created = (pthread_cond_init(&cond->cond, NULL) == 0);
|
||||
#endif
|
||||
|
||||
if (!event_created)
|
||||
goto error;
|
||||
|
||||
return cond;
|
||||
|
||||
error:
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_free:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Frees a condition variable.
|
||||
**/
|
||||
void scond_free(scond_t *cond)
|
||||
{
|
||||
if (!cond)
|
||||
return;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
CloseHandle(cond->event);
|
||||
#else
|
||||
pthread_cond_destroy(&cond->cond);
|
||||
#endif
|
||||
free(cond);
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_wait:
|
||||
* @cond : pointer to condition variable object
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Block on a condition variable (i.e. wait on a condition).
|
||||
**/
|
||||
void scond_wait(scond_t *cond, slock_t *lock)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
WaitForSingleObject(cond->event, 0);
|
||||
|
||||
SignalObjectAndWait(lock->lock, cond->event, INFINITE, FALSE);
|
||||
slock_lock(lock);
|
||||
#else
|
||||
pthread_cond_wait(&cond->cond, &lock->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_broadcast:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Broadcast a condition. Unblocks all threads currently blocked
|
||||
* on the specified condition variable @cond.
|
||||
**/
|
||||
int scond_broadcast(scond_t *cond)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
/* FIXME _- check how this function should differ
|
||||
* from scond_signal implementation. */
|
||||
SetEvent(cond->event);
|
||||
return 0;
|
||||
#else
|
||||
return pthread_cond_broadcast(&cond->cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_signal:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Signal a condition. Unblocks at least one of the threads currently blocked
|
||||
* on the specified condition variable @cond.
|
||||
**/
|
||||
void scond_signal(scond_t *cond)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
SetEvent(cond->event);
|
||||
#else
|
||||
pthread_cond_signal(&cond->cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_wait_timeout:
|
||||
* @cond : pointer to condition variable object
|
||||
* @lock : pointer to mutex object
|
||||
* @timeout_us : timeout (in microseconds)
|
||||
*
|
||||
* Try to block on a condition variable (i.e. wait on a condition) until
|
||||
* @timeout_us elapses.
|
||||
*
|
||||
* Returns: false (0) if timeout elapses before condition variable is
|
||||
* signaled or broadcast, otherwise true (1).
|
||||
**/
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
DWORD ret;
|
||||
|
||||
WaitForSingleObject(cond->event, 0);
|
||||
ret = SignalObjectAndWait(lock->lock, cond->event,
|
||||
(DWORD)(timeout_us) / 1000, FALSE);
|
||||
|
||||
slock_lock(lock);
|
||||
return ret == WAIT_OBJECT_0;
|
||||
#else
|
||||
int ret;
|
||||
int64_t seconds, remainder;
|
||||
struct timespec now = {0};
|
||||
|
||||
#ifdef __MACH__
|
||||
/* OSX doesn't have clock_gettime. */
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
now.tv_sec = mts.tv_sec;
|
||||
now.tv_nsec = mts.tv_nsec;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
sys_time_sec_t s;
|
||||
sys_time_nsec_t n;
|
||||
|
||||
sys_time_get_current_time(&s, &n);
|
||||
now.tv_sec = s;
|
||||
now.tv_nsec = n;
|
||||
#elif defined(__mips__) || defined(VITA)
|
||||
struct timeval tm;
|
||||
|
||||
gettimeofday(&tm, NULL);
|
||||
now.tv_sec = tm.tv_sec;
|
||||
now.tv_nsec = tm.tv_usec * 1000;
|
||||
#elif defined(RETRO_WIN32_USE_PTHREADS)
|
||||
_ftime64_s(&now);
|
||||
#elif !defined(GEKKO)
|
||||
/* timeout on libogc is duration, not end time. */
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
#endif
|
||||
|
||||
seconds = timeout_us / INT64_C(1000000);
|
||||
remainder = timeout_us % INT64_C(1000000);
|
||||
|
||||
now.tv_sec += seconds;
|
||||
now.tv_nsec += remainder * INT64_C(1000);
|
||||
|
||||
ret = pthread_cond_timedwait(&cond->cond, &lock->lock, &now);
|
||||
return (ret == 0);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (xenon_sdl_threads.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;)
|
||||
|
||||
#include "SDL_thread.h"
|
||||
#include "SDL_mutex.h"
|
||||
#include <stdlib.h>
|
||||
#include <boolean.h>
|
||||
|
||||
SDL_cond *SDL_CreateCond(void)
|
||||
{
|
||||
bool *sleeping = calloc(1, sizeof(*sleeping));
|
||||
return (SDL_cond*)sleeping;
|
||||
}
|
||||
|
||||
void SDL_DestroyCond(SDL_cond *sleeping)
|
||||
{
|
||||
free(sleeping);
|
||||
}
|
||||
|
||||
int SDL_CondWait(SDL_cond *cond, SDL_mutex *lock)
|
||||
{
|
||||
(void)lock;
|
||||
volatile bool *sleeping = (volatile bool*)cond;
|
||||
|
||||
SDL_mutexV(lock);
|
||||
*sleeping = true;
|
||||
while (*sleeping); /* Yeah, we all love busyloops don't we? ._. */
|
||||
SDL_mutexP(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDL_CondSignal(SDL_cond *cond)
|
||||
{
|
||||
*(volatile bool*)cond = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user