This commit is contained in:
AzaezelX 2022-03-23 01:43:08 -05:00
parent ee4253c982
commit 2614274639
1225 changed files with 148950 additions and 51674 deletions

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -82,7 +82,7 @@ SDL_TLSSet(SDL_TLSID id, const void *value, void (SDLCALL *destructor)(void *))
return 0;
}
static void
void
SDL_TLSCleanup()
{
SDL_TLSData *storage;
@ -141,10 +141,10 @@ SDL_Generic_GetTLSData(void)
}
SDL_AtomicUnlock(&tls_lock);
}
#endif /* SDL_THREADS_DISABLED */
SDL_MemoryBarrierAcquire();
SDL_LockMutex(SDL_generic_TLS_mutex);
#endif /* SDL_THREADS_DISABLED */
for (entry = SDL_generic_TLS; entry; entry = entry->next) {
if (entry->thread == thread) {
storage = entry->storage;

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -34,6 +34,8 @@
#include "windows/SDL_systhread_c.h"
#elif SDL_THREAD_PSP
#include "psp/SDL_systhread_c.h"
#elif SDL_THREAD_VITA
#include "vita/SDL_systhread_c.h"
#elif SDL_THREAD_STDCPP
#include "stdcpp/SDL_systhread_c.h"
#elif SDL_THREAD_OS2

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -28,41 +28,57 @@
#include "SDL_thread.h"
struct SDL_cond
#include "../generic/SDL_syscond_c.h"
/* If two implementations are to be compiled into SDL (the active one
* will be chosen at runtime), the function names need to be
* suffixed
*/
#if !SDL_THREAD_GENERIC_COND_SUFFIX
#define SDL_CreateCond_generic SDL_CreateCond
#define SDL_DestroyCond_generic SDL_DestroyCond
#define SDL_CondSignal_generic SDL_CondSignal
#define SDL_CondBroadcast_generic SDL_CondBroadcast
#define SDL_CondWait_generic SDL_CondWait
#define SDL_CondWaitTimeout_generic SDL_CondWaitTimeout
#endif
typedef struct SDL_cond_generic
{
SDL_mutex *lock;
int waiting;
int signals;
SDL_sem *wait_sem;
SDL_sem *wait_done;
};
} SDL_cond_generic;
/* Create a condition variable */
SDL_cond *
SDL_CreateCond(void)
SDL_CreateCond_generic(void)
{
SDL_cond *cond;
SDL_cond_generic *cond;
cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond));
cond = (SDL_cond_generic *) SDL_malloc(sizeof(SDL_cond_generic));
if (cond) {
cond->lock = SDL_CreateMutex();
cond->wait_sem = SDL_CreateSemaphore(0);
cond->wait_done = SDL_CreateSemaphore(0);
cond->waiting = cond->signals = 0;
if (!cond->lock || !cond->wait_sem || !cond->wait_done) {
SDL_DestroyCond(cond);
SDL_DestroyCond_generic((SDL_cond *)cond);
cond = NULL;
}
} else {
SDL_OutOfMemory();
}
return (cond);
return (SDL_cond *)cond;
}
/* Destroy a condition variable */
void
SDL_DestroyCond(SDL_cond * cond)
SDL_DestroyCond_generic(SDL_cond * _cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (cond) {
if (cond->wait_sem) {
SDL_DestroySemaphore(cond->wait_sem);
@ -79,10 +95,11 @@ SDL_DestroyCond(SDL_cond * cond)
/* Restart one of the threads that are waiting on the condition variable */
int
SDL_CondSignal(SDL_cond * cond)
SDL_CondSignal_generic(SDL_cond * _cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
/* If there are waiting threads not already signalled, then
@ -103,10 +120,11 @@ SDL_CondSignal(SDL_cond * cond)
/* Restart all threads that are waiting on the condition variable */
int
SDL_CondBroadcast(SDL_cond * cond)
SDL_CondBroadcast_generic(SDL_cond * _cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
/* If there are waiting threads not already signalled, then
@ -157,12 +175,13 @@ Thread B:
SDL_UnlockMutex(lock);
*/
int
SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
SDL_CondWaitTimeout_generic(SDL_cond * _cond, SDL_mutex * mutex, Uint32 ms)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
int retval;
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
/* Obtain the protection mutex, and increment the number of waiters.
@ -212,9 +231,9 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
/* Wait on the condition variable forever */
int
SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex)
SDL_CondWait_generic(SDL_cond * cond, SDL_mutex * mutex)
{
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
return SDL_CondWaitTimeout_generic(cond, mutex, SDL_MUTEX_MAXWAIT);
}
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "SDL_thread.h"
#ifndef SDL_syscond_generic_h_
#define SDL_syscond_generic_h_
#if SDL_THREAD_GENERIC_COND_SUFFIX
SDL_cond * SDL_CreateCond_generic(void);
void SDL_DestroyCond_generic(SDL_cond * cond);
int SDL_CondSignal_generic(SDL_cond * cond);
int SDL_CondBroadcast_generic(SDL_cond * cond);
int SDL_CondWait_generic(SDL_cond * cond, SDL_mutex * mutex);
int SDL_CondWaitTimeout_generic(SDL_cond * cond,
SDL_mutex * mutex, Uint32 ms);
#endif /* SDL_THREAD_GENERIC_COND_SUFFIX */
#endif /* SDL_syscond_generic_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -78,7 +78,7 @@ SDL_LockMutex(SDL_mutex * mutex)
SDL_threadID this_thread;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
this_thread = SDL_ThreadID();
@ -109,7 +109,7 @@ SDL_TryLockMutex(SDL_mutex * mutex)
SDL_threadID this_thread;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
this_thread = SDL_ThreadID();
@ -139,7 +139,7 @@ SDL_mutexV(SDL_mutex * mutex)
return 0;
#else
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
/* If we don't own the mutex, we can't unlock it */

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -132,7 +132,7 @@ SDL_SemTryWait(SDL_sem * sem)
int retval;
if (!sem) {
return SDL_SetError("Passed a NULL semaphore");
return SDL_InvalidParamError("sem");
}
retval = SDL_MUTEX_TIMEDOUT;
@ -152,7 +152,7 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
int retval;
if (!sem) {
return SDL_SetError("Passed a NULL semaphore");
return SDL_InvalidParamError("sem");
}
/* A timeout of 0 is an easy case */
@ -200,7 +200,7 @@ int
SDL_SemPost(SDL_sem * sem)
{
if (!sem) {
return SDL_SetError("Passed a NULL semaphore");
return SDL_InvalidParamError("sem");
}
SDL_LockMutex(sem->count_lock);

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -73,7 +73,7 @@ SDL_LockMutex(SDL_mutex * mutex)
HMTX hMtx = (HMTX)mutex;
if (hMtx == NULLHANDLE)
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
ulRC = DosRequestMutexSem(hMtx, SEM_INDEFINITE_WAIT);
if (ulRC != NO_ERROR) {
@ -92,7 +92,7 @@ SDL_TryLockMutex(SDL_mutex * mutex)
HMTX hMtx = (HMTX)mutex;
if (hMtx == NULLHANDLE)
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
ulRC = DosRequestMutexSem(hMtx, SEM_IMMEDIATE_RETURN);
@ -115,7 +115,7 @@ SDL_UnlockMutex(SDL_mutex * mutex)
HMTX hMtx = (HMTX)mutex;
if (hMtx == NULLHANDLE)
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
ulRC = DosReleaseMutexSem(hMtx);
if (ulRC != NO_ERROR)

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -89,7 +89,7 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
ULONG cPost;
if (sem == NULL)
return SDL_SetError("Passed a NULL sem");
return SDL_InvalidParamError("sem");
if (timeout != SEM_INDEFINITE_WAIT)
DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &ulStartTime, sizeof(ULONG));
@ -147,7 +147,7 @@ SDL_SemValue(SDL_sem * sem)
ULONG ulRC;
if (sem == NULL) {
SDL_SetError("Passed a NULL sem");
SDL_InvalidParamError("sem");
return 0;
}
@ -167,7 +167,7 @@ SDL_SemPost(SDL_sem * sem)
ULONG ulRC;
if (sem == NULL)
return SDL_SetError("Passed a NULL sem");
return SDL_InvalidParamError("sem");
ulRC = DosRequestMutexSem(sem->hMtx, SEM_INDEFINITE_WAIT);
if (ulRC != NO_ERROR)

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -84,7 +84,7 @@ int
SDL_CondSignal(SDL_cond * cond)
{
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
/* If there are waiting threads not already signalled, then
@ -108,7 +108,7 @@ int
SDL_CondBroadcast(SDL_cond * cond)
{
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
/* If there are waiting threads not already signalled, then
@ -164,7 +164,7 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
int retval;
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
/* Obtain the protection mutex, and increment the number of waiters.

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -27,30 +27,37 @@
#include "SDL_thread.h"
#include "SDL_systhread_c.h"
#include <pspthreadman.h>
#include <pspkerror.h>
#define SCE_KERNEL_MUTEX_ATTR_RECURSIVE 0x0200U
struct SDL_mutex
{
int recursive;
SDL_threadID owner;
SDL_sem *sem;
SceLwMutexWorkarea lock;
};
/* Create a mutex */
SDL_mutex *
SDL_CreateMutex(void)
{
SDL_mutex *mutex;
SDL_mutex *mutex = NULL;
SceInt32 res = 0;
/* Allocate mutex memory */
mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex));
if (mutex) {
/* Create the mutex semaphore, with initial value 1 */
mutex->sem = SDL_CreateSemaphore(1);
mutex->recursive = 0;
mutex->owner = 0;
if (!mutex->sem) {
SDL_free(mutex);
mutex = NULL;
res = sceKernelCreateLwMutex(
&mutex->lock,
"SDL mutex",
SCE_KERNEL_MUTEX_ATTR_RECURSIVE,
0,
NULL
);
if (res < 0) {
SDL_SetError("Error trying to create mutex: %x", res);
}
} else {
SDL_OutOfMemory();
@ -63,37 +70,56 @@ void
SDL_DestroyMutex(SDL_mutex * mutex)
{
if (mutex) {
if (mutex->sem) {
SDL_DestroySemaphore(mutex->sem);
}
sceKernelDeleteLwMutex(&mutex->lock);
SDL_free(mutex);
}
}
/* Lock the semaphore */
/* Try to lock the mutex */
int
SDL_TryLockMutex(SDL_mutex * mutex)
{
#if SDL_THREADS_DISABLED
return 0;
#else
SceInt32 res = 0;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
res = sceKernelTryLockLwMutex(&mutex->lock, 1);
switch (res) {
case SCE_KERNEL_ERROR_OK:
return 0;
break;
case SCE_KERNEL_ERROR_WAIT_TIMEOUT:
return SDL_MUTEX_TIMEDOUT;
break;
default:
return SDL_SetError("Error trying to lock mutex: %x", res);
break;
}
return -1;
#endif /* SDL_THREADS_DISABLED */
}
/* Lock the mutex */
int
SDL_mutexP(SDL_mutex * mutex)
{
#if SDL_THREADS_DISABLED
return 0;
#else
SDL_threadID this_thread;
SceInt32 res = 0;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
this_thread = SDL_ThreadID();
if (mutex->owner == this_thread) {
++mutex->recursive;
} else {
/* The order of operations is important.
We set the locking thread id after we obtain the lock
so unlocks from other threads will fail.
*/
SDL_SemWait(mutex->sem);
mutex->owner = this_thread;
mutex->recursive = 0;
res = sceKernelLockLwMutex(&mutex->lock, 1, NULL);
if (res != SCE_KERNEL_ERROR_OK) {
return SDL_SetError("Error trying to lock mutex: %x", res);
}
return 0;
@ -107,30 +133,20 @@ SDL_mutexV(SDL_mutex * mutex)
#if SDL_THREADS_DISABLED
return 0;
#else
SceInt32 res = 0;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
/* If we don't own the mutex, we can't unlock it */
if (SDL_ThreadID() != mutex->owner) {
return SDL_SetError("mutex not owned by this thread");
res = sceKernelUnlockLwMutex(&mutex->lock, 1);
if (res != 0) {
return SDL_SetError("Error trying to unlock mutex: %x", res);
}
if (mutex->recursive) {
--mutex->recursive;
} else {
/* The order of operations is important.
First reset the owner so another thread doesn't lock
the mutex and set the ownership before we reset it,
then release the lock semaphore.
*/
mutex->owner = 0;
SDL_SemPost(mutex->sem);
}
return 0;
#endif /* SDL_THREADS_DISABLED */
}
#endif /* SDL_THREAD_PSP */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -43,13 +43,13 @@ SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
{
SDL_sem *sem;
sem = (SDL_sem *) malloc(sizeof(*sem));
sem = (SDL_sem *) SDL_malloc(sizeof(*sem));
if (sem != NULL) {
/* TODO: Figure out the limit on the maximum value. */
sem->semid = sceKernelCreateSema("SDL sema", 0, initial_value, 255, NULL);
if (sem->semid < 0) {
SDL_SetError("Couldn't create semaphore");
free(sem);
SDL_free(sem);
sem = NULL;
}
} else {
@ -68,7 +68,7 @@ void SDL_DestroySemaphore(SDL_sem *sem)
sem->semid = 0;
}
free(sem);
SDL_free(sem);
}
}
@ -82,7 +82,7 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int res;
if (sem == NULL) {
SDL_SetError("Passed a NULL sem");
SDL_InvalidParamError("sem");
return 0;
}
@ -128,7 +128,7 @@ Uint32 SDL_SemValue(SDL_sem *sem)
SceKernelSemaInfo info;
if (sem == NULL) {
SDL_SetError("Passed a NULL sem");
SDL_InvalidParamError("sem");
return 0;
}
@ -144,7 +144,7 @@ int SDL_SemPost(SDL_sem *sem)
int res;
if (sem == NULL) {
return SDL_SetError("Passed a NULL sem");
return SDL_InvalidParamError("sem");
}
res = sceKernelSignalSema(sem->semid, 1);

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -95,13 +95,13 @@ int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
int value;
if (priority == SDL_THREAD_PRIORITY_LOW) {
value = 19;
value = 111;
} else if (priority == SDL_THREAD_PRIORITY_HIGH) {
value = -10;
value = 32;
} else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
value = -20;
value = 16;
} else {
value = 0;
value = 50;
}
return sceKernelChangeThreadPriority(sceKernelGetThreadId(),value);

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -68,7 +68,7 @@ SDL_CondSignal(SDL_cond * cond)
int retval;
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
retval = 0;
@ -85,7 +85,7 @@ SDL_CondBroadcast(SDL_cond * cond)
int retval;
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
retval = 0;
@ -105,7 +105,7 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
struct timespec abstime;
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
}
#ifdef HAVE_CLOCK_GETTIME
@ -148,7 +148,7 @@ int
SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex)
{
if (!cond) {
return SDL_SetError("Passed a NULL condition variable");
return SDL_InvalidParamError("cond");
} else if (pthread_cond_wait(&cond->cond, &mutex->id) != 0) {
return SDL_SetError("pthread_cond_wait() failed");
}

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -85,7 +85,7 @@ SDL_LockMutex(SDL_mutex * mutex)
#endif
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
#if FAKE_RECURSIVE_MUTEX
@ -122,7 +122,7 @@ SDL_TryLockMutex(SDL_mutex * mutex)
#endif
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
retval = 0;
@ -162,7 +162,7 @@ int
SDL_UnlockMutex(SDL_mutex * mutex)
{
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
#if FAKE_RECURSIVE_MUTEX

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -73,7 +73,7 @@ SDL_SemTryWait(SDL_sem * sem)
int retval;
if (!sem) {
return SDL_SetError("Passed a NULL semaphore");
return SDL_InvalidParamError("sem");
}
retval = SDL_MUTEX_TIMEDOUT;
if (sem_trywait(&sem->sem) == 0) {
@ -88,7 +88,7 @@ SDL_SemWait(SDL_sem * sem)
int retval;
if (!sem) {
return SDL_SetError("Passed a NULL semaphore");
return SDL_InvalidParamError("sem");
}
do {
@ -115,7 +115,7 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
#endif
if (!sem) {
return SDL_SetError("Passed a NULL semaphore");
return SDL_InvalidParamError("sem");
}
/* Try the easy cases first */
@ -195,7 +195,7 @@ SDL_SemPost(SDL_sem * sem)
int retval;
if (!sem) {
return SDL_SetError("Passed a NULL semaphore");
return SDL_InvalidParamError("sem");
}
retval = sem_post(&sem->sem);

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -30,25 +30,24 @@
#endif
#include <signal.h>
#include <errno.h>
#ifdef __LINUX__
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <errno.h>
#include "../../core/linux/SDL_dbus.h"
#endif /* __LINUX__ */
#if defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__)
#if (defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__)) && defined(HAVE_DLOPEN)
#include <dlfcn.h>
#ifndef RTLD_DEFAULT
#define RTLD_DEFAULT NULL
#endif
#endif
#include "SDL_platform.h"
#include "SDL_thread.h"
#include "../SDL_thread_c.h"
#include "../SDL_systhread.h"
@ -79,10 +78,10 @@ RunThread(void *data)
return NULL;
}
#if defined(__MACOSX__) || defined(__IPHONEOS__)
#if (defined(__MACOSX__) || defined(__IPHONEOS__)) && defined(HAVE_DLOPEN)
static SDL_bool checked_setname = SDL_FALSE;
static int (*ppthread_setname_np)(const char*) = NULL;
#elif defined(__LINUX__)
#elif defined(__LINUX__) && defined(HAVE_DLOPEN)
static SDL_bool checked_setname = SDL_FALSE;
static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
#endif
@ -92,7 +91,7 @@ SDL_SYS_CreateThread(SDL_Thread * thread)
pthread_attr_t type;
/* do this here before any threads exist, so there's no race condition. */
#if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
#if (defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)) && defined(HAVE_DLOPEN)
if (!checked_setname) {
void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
#if defined(__MACOSX__) || defined(__IPHONEOS__)
@ -132,28 +131,35 @@ SDL_SYS_SetupThread(const char *name)
#endif /* !__NACL__ */
if (name != NULL) {
#if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
#if (defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)) && defined(HAVE_DLOPEN)
SDL_assert(checked_setname);
if (ppthread_setname_np != NULL) {
#if defined(__MACOSX__) || defined(__IPHONEOS__)
ppthread_setname_np(name);
#elif defined(__LINUX__)
ppthread_setname_np(pthread_self(), name);
if (ppthread_setname_np(pthread_self(), name) == ERANGE) {
char namebuf[16]; /* Limited to 16 char */
SDL_strlcpy(namebuf, name, sizeof (namebuf));
ppthread_setname_np(pthread_self(), namebuf);
}
#endif
}
#elif HAVE_PTHREAD_SETNAME_NP
#if defined(__NETBSD__)
pthread_setname_np(pthread_self(), "%s", name);
#else
pthread_setname_np(pthread_self(), name);
if (pthread_setname_np(pthread_self(), name) == ERANGE) {
char namebuf[16]; /* Limited to 16 char */
SDL_strlcpy(namebuf, name, sizeof (namebuf));
pthread_setname_np(pthread_self(), namebuf);
}
#endif
#elif HAVE_PTHREAD_SET_NAME_NP
pthread_set_name_np(pthread_self(), name);
#elif defined(__HAIKU__)
/* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */
char namebuf[B_OS_NAME_LENGTH];
SDL_snprintf(namebuf, sizeof (namebuf), "%s", name);
namebuf[sizeof (namebuf) - 1] = '\0';
SDL_strlcpy(namebuf, name, sizeof (namebuf));
rename_thread(find_thread(NULL), namebuf);
#endif
}
@ -184,21 +190,10 @@ SDL_ThreadID(void)
return ((SDL_threadID) pthread_self());
}
#if __LINUX__
/**
\brief Sets the SDL priority (not nice level) for a thread, using setpriority() if appropriate, and RealtimeKit if available.
Differs from SDL_LinuxSetThreadPriority in also taking the desired scheduler policy,
such as SCHED_OTHER or SCHED_RR.
\return 0 on success, or -1 on error.
*/
extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy);
#endif
int
SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
{
#if __NACL__ || __RISCOS__
#if __NACL__ || __RISCOS__ || __OS2__
/* FIXME: Setting thread priority does not seem to be supported in NACL */
return 0;
#else

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -70,8 +70,7 @@ int
SDL_CondSignal(SDL_cond * cond)
{
if (!cond) {
SDL_SetError("Passed a NULL condition variable");
return -1;
return SDL_InvalidParamError("cond");
}
cond->cpp_cond.notify_one();
@ -84,8 +83,7 @@ int
SDL_CondBroadcast(SDL_cond * cond)
{
if (!cond) {
SDL_SetError("Passed a NULL condition variable");
return -1;
return SDL_InvalidParamError("cond");
}
cond->cpp_cond.notify_all();
@ -118,13 +116,11 @@ int
SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
{
if (!cond) {
SDL_SetError("Passed a NULL condition variable");
return -1;
return SDL_InvalidParamError("cond");
}
if (!mutex) {
SDL_SetError("Passed a NULL mutex variable");
return -1;
return SDL_InvalidParamError("mutex");
}
try {
@ -148,8 +144,7 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
}
}
} catch (std::system_error & ex) {
SDL_SetError("unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what());
return -1;
return SDL_SetError("unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what());
}
}

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -65,16 +65,14 @@ int
SDL_mutexP(SDL_mutex * mutex)
{
if (mutex == NULL) {
SDL_SetError("Passed a NULL mutex");
return -1;
return SDL_InvalidParamError("mutex");
}
try {
mutex->cpp_mutex.lock();
return 0;
} catch (std::system_error & ex) {
SDL_SetError("unable to lock a C++ mutex: code=%d; %s", ex.code(), ex.what());
return -1;
return SDL_SetError("unable to lock a C++ mutex: code=%d; %s", ex.code(), ex.what());
}
}
@ -84,7 +82,7 @@ SDL_TryLockMutex(SDL_mutex * mutex)
{
int retval = 0;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
if (mutex->cpp_mutex.try_lock() == false) {
@ -99,8 +97,7 @@ int
SDL_mutexV(SDL_mutex * mutex)
{
if (mutex == NULL) {
SDL_SetError("Passed a NULL mutex");
return -1;
return SDL_InvalidParamError("mutex");
}
mutex->cpp_mutex.unlock();

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -52,11 +52,9 @@ SDL_SYS_CreateThread(SDL_Thread * thread)
thread->handle = (void *) new std::thread(std::move(cpp_thread));
return 0;
} catch (std::system_error & ex) {
SDL_SetError("unable to start a C++ thread: code=%d; %s", ex.code(), ex.what());
return -1;
return SDL_SetError("unable to start a C++ thread: code=%d; %s", ex.code(), ex.what());
} catch (std::bad_alloc &) {
SDL_OutOfMemory();
return -1;
return SDL_OutOfMemory();
}
}

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -0,0 +1,224 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_THREAD_VITA
/* An implementation of condition variables using semaphores and mutexes */
/*
This implementation borrows heavily from the BeOS condition variable
implementation, written by Christopher Tate and Owen Smith. Thanks!
*/
#include "SDL_thread.h"
struct SDL_cond
{
SDL_mutex *lock;
int waiting;
int signals;
SDL_sem *wait_sem;
SDL_sem *wait_done;
};
/* Create a condition variable */
SDL_cond *
SDL_CreateCond(void)
{
SDL_cond *cond;
cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond));
if (cond) {
cond->lock = SDL_CreateMutex();
cond->wait_sem = SDL_CreateSemaphore(0);
cond->wait_done = SDL_CreateSemaphore(0);
cond->waiting = cond->signals = 0;
if (!cond->lock || !cond->wait_sem || !cond->wait_done) {
SDL_DestroyCond(cond);
cond = NULL;
}
} else {
SDL_OutOfMemory();
}
return (cond);
}
/* Destroy a condition variable */
void
SDL_DestroyCond(SDL_cond * cond)
{
if (cond) {
if (cond->wait_sem) {
SDL_DestroySemaphore(cond->wait_sem);
}
if (cond->wait_done) {
SDL_DestroySemaphore(cond->wait_done);
}
if (cond->lock) {
SDL_DestroyMutex(cond->lock);
}
SDL_free(cond);
}
}
/* Restart one of the threads that are waiting on the condition variable */
int
SDL_CondSignal(SDL_cond * cond)
{
if (!cond) {
return SDL_InvalidParamError("cond");
}
/* If there are waiting threads not already signalled, then
signal the condition and wait for the thread to respond.
*/
SDL_LockMutex(cond->lock);
if (cond->waiting > cond->signals) {
++cond->signals;
SDL_SemPost(cond->wait_sem);
SDL_UnlockMutex(cond->lock);
SDL_SemWait(cond->wait_done);
} else {
SDL_UnlockMutex(cond->lock);
}
return 0;
}
/* Restart all threads that are waiting on the condition variable */
int
SDL_CondBroadcast(SDL_cond * cond)
{
if (!cond) {
return SDL_InvalidParamError("cond");
}
/* If there are waiting threads not already signalled, then
signal the condition and wait for the thread to respond.
*/
SDL_LockMutex(cond->lock);
if (cond->waiting > cond->signals) {
int i, num_waiting;
num_waiting = (cond->waiting - cond->signals);
cond->signals = cond->waiting;
for (i = 0; i < num_waiting; ++i) {
SDL_SemPost(cond->wait_sem);
}
/* Now all released threads are blocked here, waiting for us.
Collect them all (and win fabulous prizes!) :-)
*/
SDL_UnlockMutex(cond->lock);
for (i = 0; i < num_waiting; ++i) {
SDL_SemWait(cond->wait_done);
}
} else {
SDL_UnlockMutex(cond->lock);
}
return 0;
}
/* Wait on the condition variable for at most 'ms' milliseconds.
The mutex must be locked before entering this function!
The mutex is unlocked during the wait, and locked again after the wait.
Typical use:
Thread A:
SDL_LockMutex(lock);
while ( ! condition ) {
SDL_CondWait(cond, lock);
}
SDL_UnlockMutex(lock);
Thread B:
SDL_LockMutex(lock);
...
condition = true;
...
SDL_CondSignal(cond);
SDL_UnlockMutex(lock);
*/
int
SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
{
int retval;
if (!cond) {
return SDL_InvalidParamError("cond");
}
/* Obtain the protection mutex, and increment the number of waiters.
This allows the signal mechanism to only perform a signal if there
are waiting threads.
*/
SDL_LockMutex(cond->lock);
++cond->waiting;
SDL_UnlockMutex(cond->lock);
/* Unlock the mutex, as is required by condition variable semantics */
SDL_UnlockMutex(mutex);
/* Wait for a signal */
if (ms == SDL_MUTEX_MAXWAIT) {
retval = SDL_SemWait(cond->wait_sem);
} else {
retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
}
/* Let the signaler know we have completed the wait, otherwise
the signaler can race ahead and get the condition semaphore
if we are stopped between the mutex unlock and semaphore wait,
giving a deadlock. See the following URL for details:
http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html
*/
SDL_LockMutex(cond->lock);
if (cond->signals > 0) {
/* If we timed out, we need to eat a condition signal */
if (retval > 0) {
SDL_SemWait(cond->wait_sem);
}
/* We always notify the signal thread that we are done */
SDL_SemPost(cond->wait_done);
/* Signal handshake complete */
--cond->signals;
}
--cond->waiting;
SDL_UnlockMutex(cond->lock);
/* Lock the mutex, as is required by condition variable semantics */
SDL_LockMutex(mutex);
return retval;
}
/* Wait on the condition variable forever */
int
SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex)
{
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
}
#endif /* SDL_THREAD_VITA */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,149 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_THREAD_VITA
#include "SDL_thread.h"
#include "SDL_systhread_c.h"
#include <psp2/kernel/threadmgr.h>
#include <psp2/kernel/error.h>
struct SDL_mutex
{
SceKernelLwMutexWork lock;
};
/* Create a mutex */
SDL_mutex *
SDL_CreateMutex(void)
{
SDL_mutex *mutex = NULL;
SceInt32 res = 0;
/* Allocate mutex memory */
mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex));
if (mutex) {
res = sceKernelCreateLwMutex(
&mutex->lock,
"SDL mutex",
SCE_KERNEL_MUTEX_ATTR_RECURSIVE,
0,
NULL
);
if (res < 0) {
SDL_SetError("Error trying to create mutex: %x", res);
}
} else {
SDL_OutOfMemory();
}
return mutex;
}
/* Free the mutex */
void
SDL_DestroyMutex(SDL_mutex * mutex)
{
if (mutex) {
sceKernelDeleteLwMutex(&mutex->lock);
SDL_free(mutex);
}
}
/* Try to lock the mutex */
int
SDL_TryLockMutex(SDL_mutex * mutex)
{
#if SDL_THREADS_DISABLED
return 0;
#else
SceInt32 res = 0;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
res = sceKernelTryLockLwMutex(&mutex->lock, 1);
switch (res) {
case SCE_KERNEL_OK:
return 0;
break;
case SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN:
return SDL_MUTEX_TIMEDOUT;
break;
default:
return SDL_SetError("Error trying to lock mutex: %x", res);
break;
}
return -1;
#endif /* SDL_THREADS_DISABLED */
}
/* Lock the mutex */
int
SDL_mutexP(SDL_mutex * mutex)
{
#if SDL_THREADS_DISABLED
return 0;
#else
SceInt32 res = 0;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
res = sceKernelLockLwMutex(&mutex->lock, 1, NULL);
if (res != SCE_KERNEL_OK) {
return SDL_SetError("Error trying to lock mutex: %x", res);
}
return 0;
#endif /* SDL_THREADS_DISABLED */
}
/* Unlock the mutex */
int
SDL_mutexV(SDL_mutex * mutex)
{
#if SDL_THREADS_DISABLED
return 0;
#else
SceInt32 res = 0;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
res = sceKernelUnlockLwMutex(&mutex->lock, 1);
if (res != 0) {
return SDL_SetError("Error trying to unlock mutex: %x", res);
}
return 0;
#endif /* SDL_THREADS_DISABLED */
}
#endif /* SDL_THREAD_VITA */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,23 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,162 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_THREAD_VITA
/* Semaphore functions for the VITA. */
#include <stdio.h>
#include <stdlib.h>
#include "SDL_error.h"
#include "SDL_thread.h"
#include <psp2/types.h>
#include <psp2/kernel/error.h>
#include <psp2/kernel/threadmgr.h>
struct SDL_semaphore {
SceUID semid;
};
/* Create a semaphore */
SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
{
SDL_sem *sem;
sem = (SDL_sem *) SDL_malloc(sizeof(*sem));
if (sem != NULL) {
/* TODO: Figure out the limit on the maximum value. */
sem->semid = sceKernelCreateSema("SDL sema", 0, initial_value, 255, NULL);
if (sem->semid < 0) {
SDL_SetError("Couldn't create semaphore");
SDL_free(sem);
sem = NULL;
}
} else {
SDL_OutOfMemory();
}
return sem;
}
/* Free the semaphore */
void SDL_DestroySemaphore(SDL_sem *sem)
{
if (sem != NULL) {
if (sem->semid > 0) {
sceKernelDeleteSema(sem->semid);
sem->semid = 0;
}
SDL_free(sem);
}
}
/* TODO: This routine is a bit overloaded.
* If the timeout is 0 then just poll the semaphore; if it's SDL_MUTEX_MAXWAIT, pass
* NULL to sceKernelWaitSema() so that it waits indefinitely; and if the timeout
* is specified, convert it to microseconds. */
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
{
Uint32 *pTimeout;
unsigned int res;
if (sem == NULL) {
SDL_InvalidParamError("sem");
return 0;
}
if (timeout == 0) {
res = sceKernelPollSema(sem->semid, 1);
if (res < 0) {
return SDL_MUTEX_TIMEDOUT;
}
return 0;
}
if (timeout == SDL_MUTEX_MAXWAIT) {
pTimeout = NULL;
} else {
timeout *= 1000; /* Convert to microseconds. */
pTimeout = &timeout;
}
res = sceKernelWaitSema(sem->semid, 1, pTimeout);
switch (res) {
case SCE_KERNEL_OK:
return 0;
case SCE_KERNEL_ERROR_WAIT_TIMEOUT:
return SDL_MUTEX_TIMEDOUT;
default:
return SDL_SetError("WaitForSingleObject() failed");
}
}
int SDL_SemTryWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, 0);
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
Uint32 SDL_SemValue(SDL_sem *sem)
{
SceKernelSemaInfo info;
info.size = sizeof(info);
if (sem == NULL) {
SDL_InvalidParamError("sem");
return 0;
}
if (sceKernelGetSemaInfo(sem->semid, &info) >= 0) {
return info.currentCount;
}
return 0;
}
int SDL_SemPost(SDL_sem *sem)
{
int res;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
res = sceKernelSignalSema(sem->semid, 1);
if (res < 0) {
return SDL_SetError("sceKernelSignalSema() failed");
}
return 0;
}
#endif /* SDL_THREAD_VITA */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,138 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_THREAD_VITA
/* VITA thread management routines for SDL */
#include <stdio.h>
#include <stdlib.h>
#include "SDL_error.h"
#include "SDL_thread.h"
#include "../SDL_systhread.h"
#include "../SDL_thread_c.h"
#include <psp2/types.h>
#include <psp2/kernel/threadmgr.h>
#define VITA_THREAD_STACK_SIZE_MIN 0x1000 // 4KiB
#define VITA_THREAD_STACK_SIZE_MAX 0x2000000 // 32MiB
#define VITA_THREAD_STACK_SIZE_DEFAULT 0x10000 // 64KiB
#define VITA_THREAD_NAME_MAX 32
#define VITA_THREAD_PRIORITY_LOW 191
#define VITA_THREAD_PRIORITY_NORMAL 160
#define VITA_THREAD_PRIORITY_HIGH 112
#define VITA_THREAD_PRIORITY_TIME_CRITICAL 64
static int ThreadEntry(SceSize args, void *argp)
{
SDL_RunThread(*(SDL_Thread **) argp);
return 0;
}
int SDL_SYS_CreateThread(SDL_Thread *thread)
{
char thread_name[VITA_THREAD_NAME_MAX];
size_t stack_size = VITA_THREAD_STACK_SIZE_DEFAULT;
SDL_strlcpy(thread_name, "SDL thread", VITA_THREAD_NAME_MAX);
if (thread->name) {
SDL_strlcpy(thread_name, thread->name, VITA_THREAD_NAME_MAX);
}
if (thread->stacksize) {
if (thread->stacksize < VITA_THREAD_STACK_SIZE_MIN) {
thread->stacksize = VITA_THREAD_STACK_SIZE_MIN;
}
if (thread->stacksize > VITA_THREAD_STACK_SIZE_MAX) {
thread->stacksize = VITA_THREAD_STACK_SIZE_MAX;
}
stack_size = thread->stacksize;
}
/* Create new thread with the same priority as the current thread */
thread->handle = sceKernelCreateThread(
thread_name, // name
ThreadEntry, // function to run
0, // priority. 0 means priority of calling thread
stack_size, // stack size
0, // attibutes. always 0
0, // cpu affinity mask. 0 = all CPUs
NULL // opt. always NULL
);
if (thread->handle < 0) {
return SDL_SetError("sceKernelCreateThread() failed");
}
sceKernelStartThread(thread->handle, 4, &thread);
return 0;
}
void SDL_SYS_SetupThread(const char *name)
{
/* Do nothing. */
}
SDL_threadID SDL_ThreadID(void)
{
return (SDL_threadID) sceKernelGetThreadId();
}
void SDL_SYS_WaitThread(SDL_Thread *thread)
{
sceKernelWaitThreadEnd(thread->handle, NULL, NULL);
sceKernelDeleteThread(thread->handle);
}
void SDL_SYS_DetachThread(SDL_Thread *thread)
{
/* Do nothing. */
}
int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
{
int value = VITA_THREAD_PRIORITY_NORMAL;
switch(priority) {
case SDL_THREAD_PRIORITY_LOW:
value = VITA_THREAD_PRIORITY_LOW;
break;
case SDL_THREAD_PRIORITY_NORMAL:
value = VITA_THREAD_PRIORITY_NORMAL;
break;
case SDL_THREAD_PRIORITY_HIGH:
value = VITA_THREAD_PRIORITY_HIGH;
break;
case SDL_THREAD_PRIORITY_TIME_CRITICAL:
value = VITA_THREAD_PRIORITY_TIME_CRITICAL;
break;
}
return sceKernelChangeThreadPriority(0, value);
}
#endif /* SDL_THREAD_VITA */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,26 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <psp2/types.h>
typedef SceUID SYS_ThreadHandle;
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,299 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "SDL_hints.h"
#include "SDL_thread.h"
#include "../generic/SDL_syscond_c.h"
#include "SDL_sysmutex_c.h"
typedef SDL_cond * (*pfnSDL_CreateCond)(void);
typedef void (*pfnSDL_DestroyCond)(SDL_cond *);
typedef int (*pfnSDL_CondSignal)(SDL_cond *);
typedef int (*pfnSDL_CondBroadcast)(SDL_cond *);
typedef int (*pfnSDL_CondWait)(SDL_cond *, SDL_mutex *);
typedef int (*pfnSDL_CondWaitTimeout)(SDL_cond *, SDL_mutex *, Uint32);
typedef struct SDL_cond_impl_t
{
pfnSDL_CreateCond Create;
pfnSDL_DestroyCond Destroy;
pfnSDL_CondSignal Signal;
pfnSDL_CondBroadcast Broadcast;
pfnSDL_CondWait Wait;
pfnSDL_CondWaitTimeout WaitTimeout;
} SDL_cond_impl_t;
/* Implementation will be chosen at runtime based on available Kernel features */
static SDL_cond_impl_t SDL_cond_impl_active = {0};
/**
* Native Windows Condition Variable (SRW Locks)
*/
#ifndef CONDITION_VARIABLE_INIT
#define CONDITION_VARIABLE_INIT {0}
typedef struct CONDITION_VARIABLE {
PVOID Ptr;
} CONDITION_VARIABLE, *PCONDITION_VARIABLE;
#endif
#if __WINRT__
#define pWakeConditionVariable WakeConditionVariable
#define pWakeAllConditionVariable WakeAllConditionVariable
#define pSleepConditionVariableSRW SleepConditionVariableSRW
#define pSleepConditionVariableCS SleepConditionVariableCS
#else
typedef VOID(WINAPI *pfnWakeConditionVariable)(PCONDITION_VARIABLE);
typedef VOID(WINAPI *pfnWakeAllConditionVariable)(PCONDITION_VARIABLE);
typedef BOOL(WINAPI *pfnSleepConditionVariableSRW)(PCONDITION_VARIABLE, PSRWLOCK, DWORD, ULONG);
typedef BOOL(WINAPI* pfnSleepConditionVariableCS)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD);
static pfnWakeConditionVariable pWakeConditionVariable = NULL;
static pfnWakeAllConditionVariable pWakeAllConditionVariable = NULL;
static pfnSleepConditionVariableSRW pSleepConditionVariableSRW = NULL;
static pfnSleepConditionVariableCS pSleepConditionVariableCS = NULL;
#endif
typedef struct SDL_cond_cv
{
CONDITION_VARIABLE cond;
} SDL_cond_cv;
static SDL_cond *
SDL_CreateCond_cv(void)
{
SDL_cond_cv *cond;
/* Relies on CONDITION_VARIABLE_INIT == 0. */
cond = (SDL_cond_cv *) SDL_calloc(1, sizeof(*cond));
if (!cond) {
SDL_OutOfMemory();
}
return (SDL_cond *)cond;
}
static void
SDL_DestroyCond_cv(SDL_cond * cond)
{
if (cond) {
/* There are no kernel allocated resources */
SDL_free(cond);
}
}
static int
SDL_CondSignal_cv(SDL_cond * _cond)
{
SDL_cond_cv *cond = (SDL_cond_cv *)_cond;
if (!cond) {
return SDL_InvalidParamError("cond");
}
pWakeConditionVariable(&cond->cond);
return 0;
}
static int
SDL_CondBroadcast_cv(SDL_cond * _cond)
{
SDL_cond_cv *cond = (SDL_cond_cv *)_cond;
if (!cond) {
return SDL_InvalidParamError("cond");
}
pWakeAllConditionVariable(&cond->cond);
return 0;
}
static int
SDL_CondWaitTimeout_cv(SDL_cond * _cond, SDL_mutex * _mutex, Uint32 ms)
{
SDL_cond_cv *cond = (SDL_cond_cv *)_cond;
DWORD timeout;
int ret;
if (!cond) {
return SDL_InvalidParamError("cond");
}
if (!_mutex) {
return SDL_InvalidParamError("mutex");
}
if (ms == SDL_MUTEX_MAXWAIT) {
timeout = INFINITE;
} else {
timeout = (DWORD) ms;
}
if (SDL_mutex_impl_active.Type == SDL_MUTEX_SRW) {
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
if (mutex->count != 1 || mutex->owner != GetCurrentThreadId()) {
return SDL_SetError("Passed mutex is not locked or locked recursively");
}
/* The mutex must be updated to the released state */
mutex->count = 0;
mutex->owner = 0;
if (pSleepConditionVariableSRW(&cond->cond, &mutex->srw, timeout, 0) == FALSE) {
if (GetLastError() == ERROR_TIMEOUT) {
ret = SDL_MUTEX_TIMEDOUT;
} else {
ret = SDL_SetError("SleepConditionVariableSRW() failed");
}
} else {
ret = 0;
}
/* The mutex is owned by us again, regardless of status of the wait */
SDL_assert(mutex->count == 0 && mutex->owner == 0);
mutex->count = 1;
mutex->owner = GetCurrentThreadId();
} else {
SDL_mutex_cs *mutex = (SDL_mutex_cs *)_mutex;
SDL_assert(SDL_mutex_impl_active.Type == SDL_MUTEX_CS);
if (pSleepConditionVariableCS(&cond->cond, &mutex->cs, timeout) == FALSE) {
if (GetLastError() == ERROR_TIMEOUT) {
ret = SDL_MUTEX_TIMEDOUT;
} else {
ret = SDL_SetError("SleepConditionVariableCS() failed");
}
} else {
ret = 0;
}
}
return ret;
}
static int
SDL_CondWait_cv(SDL_cond * cond, SDL_mutex * mutex) {
return SDL_CondWaitTimeout_cv(cond, mutex, SDL_MUTEX_MAXWAIT);
}
static const SDL_cond_impl_t SDL_cond_impl_cv =
{
&SDL_CreateCond_cv,
&SDL_DestroyCond_cv,
&SDL_CondSignal_cv,
&SDL_CondBroadcast_cv,
&SDL_CondWait_cv,
&SDL_CondWaitTimeout_cv,
};
/**
* Generic Condition Variable implementation using SDL_mutex and SDL_sem
*/
static const SDL_cond_impl_t SDL_cond_impl_generic =
{
&SDL_CreateCond_generic,
&SDL_DestroyCond_generic,
&SDL_CondSignal_generic,
&SDL_CondBroadcast_generic,
&SDL_CondWait_generic,
&SDL_CondWaitTimeout_generic,
};
SDL_cond *
SDL_CreateCond(void)
{
if (SDL_cond_impl_active.Create == NULL) {
/* Default to generic implementation, works with all mutex implementations */
const SDL_cond_impl_t * impl = &SDL_cond_impl_generic;
if (SDL_mutex_impl_active.Type == SDL_MUTEX_INVALID) {
/* The mutex implementation isn't decided yet, trigger it */
SDL_mutex *mutex = SDL_CreateMutex();
if (!mutex) {
return NULL;
}
SDL_DestroyMutex(mutex);
SDL_assert(SDL_mutex_impl_active.Type != SDL_MUTEX_INVALID);
}
#if __WINRT__
/* Link statically on this platform */
impl = &SDL_cond_impl_cv;
#else
{
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
if (kernel32) {
pWakeConditionVariable = (pfnWakeConditionVariable) GetProcAddress(kernel32, "WakeConditionVariable");
pWakeAllConditionVariable = (pfnWakeAllConditionVariable) GetProcAddress(kernel32, "WakeAllConditionVariable");
pSleepConditionVariableSRW = (pfnSleepConditionVariableSRW) GetProcAddress(kernel32, "SleepConditionVariableSRW");
pSleepConditionVariableCS = (pfnSleepConditionVariableCS) GetProcAddress(kernel32, "SleepConditionVariableCS");
if (pWakeConditionVariable && pWakeAllConditionVariable && pSleepConditionVariableSRW && pSleepConditionVariableCS) {
/* Use the Windows provided API */
impl = &SDL_cond_impl_cv;
}
}
}
#endif
SDL_memcpy(&SDL_cond_impl_active, impl, sizeof(SDL_cond_impl_active));
}
return SDL_cond_impl_active.Create();
}
void
SDL_DestroyCond(SDL_cond * cond)
{
SDL_cond_impl_active.Destroy(cond);
}
int
SDL_CondSignal(SDL_cond * cond)
{
return SDL_cond_impl_active.Signal(cond);
}
int
SDL_CondBroadcast(SDL_cond * cond)
{
return SDL_cond_impl_active.Broadcast(cond);
}
int
SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
{
return SDL_cond_impl_active.WaitTimeout(cond, mutex, ms);
}
int
SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex)
{
return SDL_cond_impl_active.Wait(cond, mutex);
}
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -22,26 +22,161 @@
#if SDL_THREAD_WINDOWS
/* Mutex functions using the Win32 API */
#include "../../core/windows/SDL_windows.h"
#include "SDL_mutex.h"
/**
* Mutex functions using the Win32 API
* There are two implementations available based on:
* - Critical Sections. Available on all OS versions since Windows XP.
* - Slim Reader/Writer Locks. Requires Windows 7 or newer.
* which are chosen at runtime.
*/
struct SDL_mutex
#include "SDL_hints.h"
#include "SDL_sysmutex_c.h"
/* Implementation will be chosen at runtime based on available Kernel features */
SDL_mutex_impl_t SDL_mutex_impl_active = {0};
/**
* Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.
*/
#if __WINRT__
/* Functions are guaranteed to be available */
#define pReleaseSRWLockExclusive ReleaseSRWLockExclusive
#define pAcquireSRWLockExclusive AcquireSRWLockExclusive
#define pTryAcquireSRWLockExclusive TryAcquireSRWLockExclusive
#else
typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
#endif
static SDL_mutex *
SDL_CreateMutex_srw(void)
{
CRITICAL_SECTION cs;
SDL_mutex_srw *mutex;
/* Relies on SRWLOCK_INIT == 0. */
mutex = (SDL_mutex_srw *) SDL_calloc(1, sizeof(*mutex));
if (!mutex) {
SDL_OutOfMemory();
}
return (SDL_mutex *)mutex;
}
static void
SDL_DestroyMutex_srw(SDL_mutex * mutex)
{
if (mutex) {
/* There are no kernel allocated resources */
SDL_free(mutex);
}
}
static int
SDL_LockMutex_srw(SDL_mutex * _mutex)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
DWORD this_thread;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
this_thread = GetCurrentThreadId();
if (mutex->owner == this_thread) {
++mutex->count;
} else {
/* The order of operations is important.
We set the locking thread id after we obtain the lock
so unlocks from other threads will fail.
*/
pAcquireSRWLockExclusive(&mutex->srw);
SDL_assert(mutex->count == 0 && mutex->owner == 0);
mutex->owner = this_thread;
mutex->count = 1;
}
return 0;
}
static int
SDL_TryLockMutex_srw(SDL_mutex * _mutex)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
DWORD this_thread;
int retval = 0;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
this_thread = GetCurrentThreadId();
if (mutex->owner == this_thread) {
++mutex->count;
} else {
if (pTryAcquireSRWLockExclusive(&mutex->srw) != 0) {
SDL_assert(mutex->count == 0 && mutex->owner == 0);
mutex->owner = this_thread;
mutex->count = 1;
} else {
retval = SDL_MUTEX_TIMEDOUT;
}
}
return retval;
}
static int
SDL_UnlockMutex_srw(SDL_mutex * _mutex)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
if (mutex->owner == GetCurrentThreadId()) {
if (--mutex->count == 0) {
mutex->owner = 0;
pReleaseSRWLockExclusive(&mutex->srw);
}
} else {
return SDL_SetError("mutex not owned by this thread");
}
return 0;
}
static const SDL_mutex_impl_t SDL_mutex_impl_srw =
{
&SDL_CreateMutex_srw,
&SDL_DestroyMutex_srw,
&SDL_LockMutex_srw,
&SDL_TryLockMutex_srw,
&SDL_UnlockMutex_srw,
SDL_MUTEX_SRW,
};
/**
* Fallback Mutex implementation using Critical Sections (before Win 7)
*/
/* Create a mutex */
SDL_mutex *
SDL_CreateMutex(void)
static SDL_mutex *
SDL_CreateMutex_cs(void)
{
SDL_mutex *mutex;
SDL_mutex_cs *mutex;
/* Allocate mutex memory */
mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex));
mutex = (SDL_mutex_cs *) SDL_malloc(sizeof(*mutex));
if (mutex) {
/* Initialize */
/* On SMP systems, a non-zero spin count generally helps performance */
@ -53,13 +188,14 @@ SDL_CreateMutex(void)
} else {
SDL_OutOfMemory();
}
return (mutex);
return (SDL_mutex *)mutex;
}
/* Free the mutex */
void
SDL_DestroyMutex(SDL_mutex * mutex)
static void
SDL_DestroyMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex) {
DeleteCriticalSection(&mutex->cs);
SDL_free(mutex);
@ -67,24 +203,26 @@ SDL_DestroyMutex(SDL_mutex * mutex)
}
/* Lock the mutex */
int
SDL_LockMutex(SDL_mutex * mutex)
static int
SDL_LockMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
EnterCriticalSection(&mutex->cs);
return (0);
return 0;
}
/* TryLock the mutex */
int
SDL_TryLockMutex(SDL_mutex * mutex)
static int
SDL_TryLockMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
int retval = 0;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
if (TryEnterCriticalSection(&mutex->cs) == 0) {
@ -94,15 +232,84 @@ SDL_TryLockMutex(SDL_mutex * mutex)
}
/* Unlock the mutex */
int
SDL_UnlockMutex(SDL_mutex * mutex)
static int
SDL_UnlockMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex == NULL) {
return SDL_SetError("Passed a NULL mutex");
return SDL_InvalidParamError("mutex");
}
LeaveCriticalSection(&mutex->cs);
return (0);
return 0;
}
static const SDL_mutex_impl_t SDL_mutex_impl_cs =
{
&SDL_CreateMutex_cs,
&SDL_DestroyMutex_cs,
&SDL_LockMutex_cs,
&SDL_TryLockMutex_cs,
&SDL_UnlockMutex_cs,
SDL_MUTEX_CS,
};
/**
* Runtime selection and redirection
*/
SDL_mutex *
SDL_CreateMutex(void)
{
if (SDL_mutex_impl_active.Create == NULL) {
/* Default to fallback implementation */
const SDL_mutex_impl_t * impl = &SDL_mutex_impl_cs;
if (!SDL_GetHintBoolean(SDL_HINT_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS, SDL_FALSE)) {
#if __WINRT__
/* Link statically on this platform */
impl = &SDL_mutex_impl_srw;
#else
/* Try faster implementation for Windows 7 and newer */
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
if (kernel32) {
/* Requires Vista: */
pReleaseSRWLockExclusive = (pfnReleaseSRWLockExclusive) GetProcAddress(kernel32, "ReleaseSRWLockExclusive");
pAcquireSRWLockExclusive = (pfnAcquireSRWLockExclusive) GetProcAddress(kernel32, "AcquireSRWLockExclusive");
/* Requires 7: */
pTryAcquireSRWLockExclusive = (pfnTryAcquireSRWLockExclusive) GetProcAddress(kernel32, "TryAcquireSRWLockExclusive");
if (pReleaseSRWLockExclusive && pAcquireSRWLockExclusive && pTryAcquireSRWLockExclusive) {
impl = &SDL_mutex_impl_srw;
}
}
#endif
}
/* Copy instead of using pointer to save one level of indirection */
SDL_memcpy(&SDL_mutex_impl_active, impl, sizeof(SDL_mutex_impl_active));
}
return SDL_mutex_impl_active.Create();
}
void
SDL_DestroyMutex(SDL_mutex * mutex) {
SDL_mutex_impl_active.Destroy(mutex);
}
int
SDL_LockMutex(SDL_mutex * mutex) {
return SDL_mutex_impl_active.Lock(mutex);
}
int
SDL_TryLockMutex(SDL_mutex * mutex) {
return SDL_mutex_impl_active.TryLock(mutex);
}
int
SDL_UnlockMutex(SDL_mutex * mutex) {
return SDL_mutex_impl_active.Unlock(mutex);
}
#endif /* SDL_THREAD_WINDOWS */

View file

@ -0,0 +1,74 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "../../core/windows/SDL_windows.h"
#include "SDL_mutex.h"
typedef SDL_mutex * (*pfnSDL_CreateMutex)(void);
typedef int (*pfnSDL_LockMutex)(SDL_mutex *);
typedef int (*pfnSDL_TryLockMutex)(SDL_mutex *);
typedef int (*pfnSDL_UnlockMutex)(SDL_mutex *);
typedef void (*pfnSDL_DestroyMutex)(SDL_mutex *);
typedef enum
{
SDL_MUTEX_INVALID = 0,
SDL_MUTEX_SRW,
SDL_MUTEX_CS,
} SDL_MutexType;
typedef struct SDL_mutex_impl_t
{
pfnSDL_CreateMutex Create;
pfnSDL_DestroyMutex Destroy;
pfnSDL_LockMutex Lock;
pfnSDL_TryLockMutex TryLock;
pfnSDL_UnlockMutex Unlock;
/* Needed by SDL_cond: */
SDL_MutexType Type;
} SDL_mutex_impl_t;
extern SDL_mutex_impl_t SDL_mutex_impl_active;
#ifndef SRWLOCK_INIT
#define SRWLOCK_INIT {0}
typedef struct _SRWLOCK {
PVOID Ptr;
} SRWLOCK, *PSRWLOCK;
#endif
typedef struct SDL_mutex_srw
{
SRWLOCK srw;
/* SRW Locks are not recursive, that has to be handled by SDL: */
DWORD count;
DWORD owner;
} SDL_mutex_srw;
typedef struct SDL_mutex_cs
{
CRITICAL_SECTION cs;
} SDL_mutex_cs;
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -22,27 +22,256 @@
#if SDL_THREAD_WINDOWS
/* Semaphore functions using the Win32 API */
/**
* Semaphore functions using the Win32 API
* There are two implementations available based on:
* - Kernel Semaphores. Available on all OS versions. (kern)
* Heavy-weight inter-process kernel objects.
* - Atomics and WaitOnAddress API. (atom)
* Faster due to significantly less context switches.
* Requires Windows 8 or newer.
* which are chosen at runtime.
*/
#include "../../core/windows/SDL_windows.h"
#include "SDL_hints.h"
#include "SDL_thread.h"
#include "SDL_timer.h"
struct SDL_semaphore
typedef SDL_sem * (*pfnSDL_CreateSemaphore)(Uint32);
typedef void (*pfnSDL_DestroySemaphore)(SDL_sem *);
typedef int (*pfnSDL_SemWaitTimeout)(SDL_sem *, Uint32);
typedef int (*pfnSDL_SemTryWait)(SDL_sem *);
typedef int (*pfnSDL_SemWait)(SDL_sem *);
typedef Uint32 (*pfnSDL_SemValue)(SDL_sem *);
typedef int (*pfnSDL_SemPost)(SDL_sem *);
typedef struct SDL_semaphore_impl_t
{
pfnSDL_CreateSemaphore Create;
pfnSDL_DestroySemaphore Destroy;
pfnSDL_SemWaitTimeout WaitTimeout;
pfnSDL_SemTryWait TryWait;
pfnSDL_SemWait Wait;
pfnSDL_SemValue Value;
pfnSDL_SemPost Post;
} SDL_sem_impl_t;
/* Implementation will be chosen at runtime based on available Kernel features */
static SDL_sem_impl_t SDL_sem_impl_active = {0};
/**
* Atomic + WaitOnAddress implementation
*/
/* APIs not available on WinPhone 8.1 */
/* https://www.microsoft.com/en-us/download/details.aspx?id=47328 */
#if (HAVE_WINAPIFAMILY_H) && defined(WINAPI_FAMILY_PHONE_APP)
#define SDL_WINAPI_FAMILY_PHONE (WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
#else
#define SDL_WINAPI_FAMILY_PHONE 0
#endif
#if !SDL_WINAPI_FAMILY_PHONE
#if __WINRT__
/* Functions are guaranteed to be available */
#define pWaitOnAddress WaitOnAddress
#define pWakeByAddressSingle WakeByAddressSingle
#else
typedef BOOL(WINAPI *pfnWaitOnAddress)(volatile VOID*, PVOID, SIZE_T, DWORD);
typedef VOID(WINAPI *pfnWakeByAddressSingle)(PVOID);
static pfnWaitOnAddress pWaitOnAddress = NULL;
static pfnWakeByAddressSingle pWakeByAddressSingle = NULL;
#endif
typedef struct SDL_semaphore_atom
{
LONG count;
} SDL_sem_atom;
static SDL_sem *
SDL_CreateSemaphore_atom(Uint32 initial_value)
{
SDL_sem_atom *sem;
sem = (SDL_sem_atom *) SDL_malloc(sizeof(*sem));
if (sem) {
sem->count = initial_value;
} else {
SDL_OutOfMemory();
}
return (SDL_sem *)sem;
}
static void
SDL_DestroySemaphore_atom(SDL_sem * sem)
{
if (sem) {
SDL_free(sem);
}
}
static int
SDL_SemTryWait_atom(SDL_sem * _sem)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
LONG count;
if (!sem) {
return SDL_InvalidParamError("sem");
}
count = sem->count;
if (count == 0) {
return SDL_MUTEX_TIMEDOUT;
}
if (InterlockedCompareExchange(&sem->count, count - 1, count) == count) {
return 0;
}
return SDL_MUTEX_TIMEDOUT;
}
static int
SDL_SemWait_atom(SDL_sem * _sem)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
LONG count;
if (!sem) {
return SDL_InvalidParamError("sem");
}
for (;;) {
count = sem->count;
while (count == 0) {
if (pWaitOnAddress(&sem->count, &count, sizeof(sem->count), INFINITE) == FALSE) {
return SDL_SetError("WaitOnAddress() failed");
}
count = sem->count;
}
if (InterlockedCompareExchange(&sem->count, count - 1, count) == count) {
return 0;
}
}
}
static int
SDL_SemWaitTimeout_atom(SDL_sem * _sem, Uint32 timeout)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
LONG count;
Uint32 now;
Uint32 deadline;
DWORD timeout_eff;
if (timeout == SDL_MUTEX_MAXWAIT) {
return SDL_SemWait_atom(_sem);
}
if (!sem) {
return SDL_InvalidParamError("sem");
}
/**
* WaitOnAddress is subject to spurious and stolen wakeups so we
* need to recalculate the effective timeout before every wait
*/
now = SDL_GetTicks();
deadline = now + (DWORD) timeout;
for (;;) {
count = sem->count;
/* If no semaphore is available we need to wait */
while (count == 0) {
now = SDL_GetTicks();
if (deadline > now) {
timeout_eff = deadline - now;
} else {
return SDL_MUTEX_TIMEDOUT;
}
if (pWaitOnAddress(&sem->count, &count, sizeof(count), timeout_eff) == FALSE) {
if (GetLastError() == ERROR_TIMEOUT) {
return SDL_MUTEX_TIMEDOUT;
}
return SDL_SetError("WaitOnAddress() failed");
}
count = sem->count;
}
/* Actually the semaphore is only consumed if this succeeds */
/* If it doesn't we need to do everything again */
if (InterlockedCompareExchange(&sem->count, count - 1, count) == count) {
return 0;
}
}
}
static Uint32
SDL_SemValue_atom(SDL_sem * _sem)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
if (!sem) {
SDL_InvalidParamError("sem");
return 0;
}
return (Uint32)sem->count;
}
static int
SDL_SemPost_atom(SDL_sem * _sem)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
if (!sem) {
return SDL_InvalidParamError("sem");
}
InterlockedIncrement(&sem->count);
pWakeByAddressSingle(&sem->count);
return 0;
}
static const SDL_sem_impl_t SDL_sem_impl_atom =
{
&SDL_CreateSemaphore_atom,
&SDL_DestroySemaphore_atom,
&SDL_SemWaitTimeout_atom,
&SDL_SemTryWait_atom,
&SDL_SemWait_atom,
&SDL_SemValue_atom,
&SDL_SemPost_atom,
};
#endif /* !SDL_WINAPI_FAMILY_PHONE */
/**
* Fallback Semaphore implementation using Kernel Semaphores
*/
typedef struct SDL_semaphore_kern
{
HANDLE id;
LONG count;
};
} SDL_sem_kern;
/* Create a semaphore */
SDL_sem *
SDL_CreateSemaphore(Uint32 initial_value)
static SDL_sem *
SDL_CreateSemaphore_kern(Uint32 initial_value)
{
SDL_sem *sem;
SDL_sem_kern *sem;
/* Allocate sem memory */
sem = (SDL_sem *) SDL_malloc(sizeof(*sem));
sem = (SDL_sem_kern *) SDL_malloc(sizeof(*sem));
if (sem) {
/* Create the semaphore, with max value 32K */
#if __WINRT__
@ -59,13 +288,14 @@ SDL_CreateSemaphore(Uint32 initial_value)
} else {
SDL_OutOfMemory();
}
return (sem);
return (SDL_sem *)sem;
}
/* Free the semaphore */
void
SDL_DestroySemaphore(SDL_sem * sem)
static void
SDL_DestroySemaphore_kern(SDL_sem * _sem)
{
SDL_sem_kern *sem = (SDL_sem_kern *)_sem;
if (sem) {
if (sem->id) {
CloseHandle(sem->id);
@ -75,14 +305,15 @@ SDL_DestroySemaphore(SDL_sem * sem)
}
}
int
SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
static int
SDL_SemWaitTimeout_kern(SDL_sem * _sem, Uint32 timeout)
{
SDL_sem_kern *sem = (SDL_sem_kern *)_sem;
int retval;
DWORD dwMilliseconds;
if (!sem) {
return SDL_SetError("Passed a NULL sem");
return SDL_InvalidParamError("sem");
}
if (timeout == SDL_MUTEX_MAXWAIT) {
@ -105,34 +336,36 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
return retval;
}
int
SDL_SemTryWait(SDL_sem * sem)
static int
SDL_SemTryWait_kern(SDL_sem * sem)
{
return SDL_SemWaitTimeout(sem, 0);
return SDL_SemWaitTimeout_kern(sem, 0);
}
int
SDL_SemWait(SDL_sem * sem)
static int
SDL_SemWait_kern(SDL_sem * sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
return SDL_SemWaitTimeout_kern(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
Uint32
SDL_SemValue(SDL_sem * sem)
static Uint32
SDL_SemValue_kern(SDL_sem * _sem)
{
SDL_sem_kern *sem = (SDL_sem_kern *)_sem;
if (!sem) {
SDL_SetError("Passed a NULL sem");
SDL_InvalidParamError("sem");
return 0;
}
return (Uint32)sem->count;
}
int
SDL_SemPost(SDL_sem * sem)
static int
SDL_SemPost_kern(SDL_sem * _sem)
{
SDL_sem_kern *sem = (SDL_sem_kern *)_sem;
if (!sem) {
return SDL_SetError("Passed a NULL sem");
return SDL_InvalidParamError("sem");
}
/* Increase the counter in the first place, because
* after a successful release the semaphore may
@ -147,6 +380,97 @@ SDL_SemPost(SDL_sem * sem)
return 0;
}
static const SDL_sem_impl_t SDL_sem_impl_kern =
{
&SDL_CreateSemaphore_kern,
&SDL_DestroySemaphore_kern,
&SDL_SemWaitTimeout_kern,
&SDL_SemTryWait_kern,
&SDL_SemWait_kern,
&SDL_SemValue_kern,
&SDL_SemPost_kern,
};
/**
* Runtime selection and redirection
*/
SDL_sem *
SDL_CreateSemaphore(Uint32 initial_value)
{
if (SDL_sem_impl_active.Create == NULL) {
/* Default to fallback implementation */
const SDL_sem_impl_t * impl = &SDL_sem_impl_kern;
#if !SDL_WINAPI_FAMILY_PHONE
if (!SDL_GetHintBoolean(SDL_HINT_WINDOWS_FORCE_SEMAPHORE_KERNEL, SDL_FALSE)) {
#if __WINRT__
/* Link statically on this platform */
impl = &SDL_sem_impl_atom;
#else
/* We already statically link to features from this Api
* Set (e.g. WaitForSingleObject). Dynamically loading
* API Sets is not explicitly documented but according to
* Microsoft our specific use case is legal and correct:
* https://github.com/microsoft/STL/pull/593#issuecomment-655799859
*/
HMODULE synch120 = GetModuleHandle(TEXT("api-ms-win-core-synch-l1-2-0.dll"));
if (synch120) {
/* Try to load required functions provided by Win 8 or newer */
pWaitOnAddress = (pfnWaitOnAddress) GetProcAddress(synch120, "WaitOnAddress");
pWakeByAddressSingle = (pfnWakeByAddressSingle) GetProcAddress(synch120, "WakeByAddressSingle");
if(pWaitOnAddress && pWakeByAddressSingle) {
impl = &SDL_sem_impl_atom;
}
}
#endif
}
#endif
/* Copy instead of using pointer to save one level of indirection */
SDL_memcpy(&SDL_sem_impl_active, impl, sizeof(SDL_sem_impl_active));
}
return SDL_sem_impl_active.Create(initial_value);
}
void
SDL_DestroySemaphore(SDL_sem * sem)
{
SDL_sem_impl_active.Destroy(sem);
}
int
SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
{
return SDL_sem_impl_active.WaitTimeout(sem, timeout);
}
int
SDL_SemTryWait(SDL_sem * sem)
{
return SDL_sem_impl_active.TryWait(sem);
}
int
SDL_SemWait(SDL_sem * sem)
{
return SDL_sem_impl_active.Wait(sem);
}
Uint32
SDL_SemValue(SDL_sem * sem)
{
return SDL_sem_impl_active.Value(sem);
}
int
SDL_SemPost(SDL_sem * sem)
{
return SDL_sem_impl_active.Post(sem);
}
#endif /* SDL_THREAD_WINDOWS */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -163,14 +163,14 @@ SDL_SYS_SetupThread(const char *name)
static HMODULE kernel32 = 0;
if (!kernel32) {
kernel32 = LoadLibraryW(L"kernel32.dll");
kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
if (kernel32) {
pSetThreadDescription = (pfnSetThreadDescription) GetProcAddress(kernel32, "SetThreadDescription");
}
}
if (pSetThreadDescription != NULL) {
WCHAR *strw = WIN_UTF8ToString(name);
WCHAR *strw = WIN_UTF8ToStringW(name);
if (strw) {
pSetThreadDescription(GetCurrentThread(), strw);
SDL_free(strw);

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View file

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages