initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled

This commit is contained in:
2025-09-16 20:46:46 -04:00
commit 9d30169a8d
13378 changed files with 7050105 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include "SDL_sysmutex_c.h"
struct SDL_Condition
{
pthread_cond_t cond;
};
// Create a condition variable
SDL_Condition *SDL_CreateCondition(void)
{
SDL_Condition *cond;
cond = (SDL_Condition *)SDL_malloc(sizeof(SDL_Condition));
if (cond) {
if (pthread_cond_init(&cond->cond, NULL) != 0) {
SDL_SetError("pthread_cond_init() failed");
SDL_free(cond);
cond = NULL;
}
}
return cond;
}
// Destroy a condition variable
void SDL_DestroyCondition(SDL_Condition *cond)
{
if (cond) {
pthread_cond_destroy(&cond->cond);
SDL_free(cond);
}
}
// Restart one of the threads that are waiting on the condition variable
void SDL_SignalCondition(SDL_Condition *cond)
{
if (!cond) {
return;
}
pthread_cond_signal(&cond->cond);
}
// Restart all threads that are waiting on the condition variable
void SDL_BroadcastCondition(SDL_Condition *cond)
{
if (!cond) {
return;
}
pthread_cond_broadcast(&cond->cond);
}
bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS)
{
#ifndef HAVE_CLOCK_GETTIME
struct timeval delta;
#endif
struct timespec abstime;
if (!cond || !mutex) {
return true;
}
if (timeoutNS < 0) {
return (pthread_cond_wait(&cond->cond, &mutex->id) == 0);
}
#ifdef HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += (timeoutNS / SDL_NS_PER_SECOND);
abstime.tv_nsec += (timeoutNS % SDL_NS_PER_SECOND);
#else
gettimeofday(&delta, NULL);
abstime.tv_sec = delta.tv_sec + (timeoutNS / SDL_NS_PER_SECOND);
abstime.tv_nsec = SDL_US_TO_NS(delta.tv_usec) + (timeoutNS % SDL_NS_PER_SECOND);
#endif
while (abstime.tv_nsec >= 1000000000) {
abstime.tv_sec += 1;
abstime.tv_nsec -= 1000000000;
}
bool result;
int rc;
tryagain:
rc = pthread_cond_timedwait(&cond->cond, &mutex->id, &abstime);
switch (rc) {
case EINTR:
goto tryagain;
// break; -Wunreachable-code-break
case ETIMEDOUT:
result = false;
break;
default:
result = true;
break;
}
return result;
}

View File

@@ -0,0 +1,154 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 <errno.h>
#include <pthread.h>
#include "SDL_sysmutex_c.h"
SDL_Mutex *SDL_CreateMutex(void)
{
SDL_Mutex *mutex;
pthread_mutexattr_t attr;
// Allocate the structure
mutex = (SDL_Mutex *)SDL_calloc(1, sizeof(*mutex));
if (mutex) {
pthread_mutexattr_init(&attr);
#ifdef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#elif defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP)
pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#else
// No extra attributes necessary
#endif
if (pthread_mutex_init(&mutex->id, &attr) != 0) {
SDL_SetError("pthread_mutex_init() failed");
SDL_free(mutex);
mutex = NULL;
}
}
return mutex;
}
void SDL_DestroyMutex(SDL_Mutex *mutex)
{
if (mutex) {
pthread_mutex_destroy(&mutex->id);
SDL_free(mutex);
}
}
void SDL_LockMutex(SDL_Mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (mutex) {
#ifdef FAKE_RECURSIVE_MUTEX
pthread_t this_thread = pthread_self();
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.
*/
const int rc = pthread_mutex_lock(&mutex->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
mutex->owner = this_thread;
mutex->recursive = 0;
}
#else
const int rc = pthread_mutex_lock(&mutex->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
#endif
}
}
bool SDL_TryLockMutex(SDL_Mutex *mutex)
{
bool result = true;
if (mutex) {
#ifdef FAKE_RECURSIVE_MUTEX
pthread_t this_thread = pthread_self();
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.
*/
const int rc = pthread_mutex_trylock(&mutex->id);
if (rc == 0) {
mutex->owner = this_thread;
mutex->recursive = 0;
} else if (rc == EBUSY) {
result = false;
} else {
SDL_assert(!"Error trying to lock mutex"); // assume we're in a lot of trouble if this assert fails.
result = false;
}
}
#else
const int rc = pthread_mutex_trylock(&mutex->id);
if (rc != 0) {
if (rc == EBUSY) {
result = false;
} else {
SDL_assert(!"Error trying to lock mutex"); // assume we're in a lot of trouble if this assert fails.
result = false;
}
}
#endif
}
return result;
}
void SDL_UnlockMutex(SDL_Mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (mutex) {
#ifdef FAKE_RECURSIVE_MUTEX
// We can only unlock the mutex if we own it
if (pthread_self() == mutex->owner) {
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;
pthread_mutex_unlock(&mutex->id);
}
} else {
SDL_SetError("mutex not owned by this thread");
return;
}
#else
const int rc = pthread_mutex_unlock(&mutex->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
#endif // FAKE_RECURSIVE_MUTEX
}
}

View File

@@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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"
#ifndef SDL_mutex_c_h_
#define SDL_mutex_c_h_
#if !(defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX) || \
defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP))
#define FAKE_RECURSIVE_MUTEX
#endif
struct SDL_Mutex
{
pthread_mutex_t id;
#ifdef FAKE_RECURSIVE_MUTEX
int recursive;
pthread_t owner;
#endif
};
#endif // SDL_mutex_c_h_

View File

@@ -0,0 +1,113 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 <errno.h>
#include <pthread.h>
struct SDL_RWLock
{
pthread_rwlock_t id;
};
SDL_RWLock *SDL_CreateRWLock(void)
{
SDL_RWLock *rwlock;
// Allocate the structure
rwlock = (SDL_RWLock *)SDL_calloc(1, sizeof(*rwlock));
if (rwlock) {
if (pthread_rwlock_init(&rwlock->id, NULL) != 0) {
SDL_SetError("pthread_rwlock_init() failed");
SDL_free(rwlock);
rwlock = NULL;
}
}
return rwlock;
}
void SDL_DestroyRWLock(SDL_RWLock *rwlock)
{
if (rwlock) {
pthread_rwlock_destroy(&rwlock->id);
SDL_free(rwlock);
}
}
void SDL_LockRWLockForReading(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (rwlock) {
const int rc = pthread_rwlock_rdlock(&rwlock->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
}
}
void SDL_LockRWLockForWriting(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (rwlock) {
const int rc = pthread_rwlock_wrlock(&rwlock->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
}
}
bool SDL_TryLockRWLockForReading(SDL_RWLock *rwlock)
{
bool result = true;
if (rwlock) {
const int rc = pthread_rwlock_tryrdlock(&rwlock->id);
if (rc != 0) {
result = false;
if (rc != EBUSY) {
SDL_assert(!"Error trying to lock rwlock for reading"); // assume we're in a lot of trouble if this assert fails.
}
}
}
return result;
}
bool SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock)
{
bool result = true;
if (rwlock) {
const int rc = pthread_rwlock_trywrlock(&rwlock->id);
if (rc != 0) {
result = false;
if (rc != EBUSY) {
SDL_assert(!"Error trying to lock rwlock for writing"); // assume we're in a lot of trouble if this assert fails.
}
}
}
return result;
}
void SDL_UnlockRWLock(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (rwlock) {
const int rc = pthread_rwlock_unlock(&rwlock->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
}
}

View File

@@ -0,0 +1,160 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <time.h>
// Wrapper around POSIX 1003.1b semaphores
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)
// macOS doesn't support sem_getvalue() as of version 10.4
#include "../generic/SDL_syssem.c"
#else
struct SDL_Semaphore
{
sem_t sem;
};
// Create a semaphore, initialized with value
SDL_Semaphore *SDL_CreateSemaphore(Uint32 initial_value)
{
SDL_Semaphore *sem = (SDL_Semaphore *)SDL_malloc(sizeof(SDL_Semaphore));
if (sem) {
if (sem_init(&sem->sem, 0, initial_value) < 0) {
SDL_SetError("sem_init() failed");
SDL_free(sem);
sem = NULL;
}
}
return sem;
}
void SDL_DestroySemaphore(SDL_Semaphore *sem)
{
if (sem) {
sem_destroy(&sem->sem);
SDL_free(sem);
}
}
bool SDL_WaitSemaphoreTimeoutNS(SDL_Semaphore *sem, Sint64 timeoutNS)
{
#ifdef HAVE_SEM_TIMEDWAIT
#ifndef HAVE_CLOCK_GETTIME
struct timeval now;
#endif
struct timespec ts_timeout;
#else
Uint64 stop_time;
#endif
if (!sem) {
return true;
}
// Try the easy cases first
if (timeoutNS == 0) {
return (sem_trywait(&sem->sem) == 0);
}
if (timeoutNS < 0) {
int rc;
do {
rc = sem_wait(&sem->sem);
} while (rc < 0 && errno == EINTR);
return (rc == 0);
}
#ifdef HAVE_SEM_TIMEDWAIT
/* Setup the timeout. sem_timedwait doesn't wait for
* a lapse of time, but until we reach a certain time.
* This time is now plus the timeout.
*/
#ifdef HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &ts_timeout);
// Add our timeout to current time
ts_timeout.tv_sec += (timeoutNS / SDL_NS_PER_SECOND);
ts_timeout.tv_nsec += (timeoutNS % SDL_NS_PER_SECOND);
#else
gettimeofday(&now, NULL);
// Add our timeout to current time
ts_timeout.tv_sec = now.tv_sec + (timeoutNS / SDL_NS_PER_SECOND);
ts_timeout.tv_nsec = SDL_US_TO_NS(now.tv_usec) + (timeoutNS % SDL_NS_PER_SECOND);
#endif
// Wrap the second if needed
while (ts_timeout.tv_nsec >= 1000000000) {
ts_timeout.tv_sec += 1;
ts_timeout.tv_nsec -= 1000000000;
}
// Wait.
int rc;
do {
rc = sem_timedwait(&sem->sem, &ts_timeout);
} while (rc < 0 && errno == EINTR);
return (rc == 0);
#else
stop_time = SDL_GetTicksNS() + timeoutNS;
while (sem_trywait(&sem->sem) != 0) {
if (SDL_GetTicksNS() >= stop_time) {
return false;
}
SDL_DelayNS(100);
}
return true;
#endif // HAVE_SEM_TIMEDWAIT
}
Uint32 SDL_GetSemaphoreValue(SDL_Semaphore *sem)
{
int ret = 0;
if (!sem) {
return 0;
}
sem_getvalue(&sem->sem, &ret);
if (ret < 0) {
ret = 0;
}
return (Uint32)ret;
}
void SDL_SignalSemaphore(SDL_Semaphore *sem)
{
if (!sem) {
return;
}
sem_post(&sem->sem);
}
#endif // SDL_PLATFORM_MACOS

View File

@@ -0,0 +1,293 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <errno.h>
#ifdef SDL_PLATFORM_LINUX
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "../../core/linux/SDL_dbus.h"
#endif // SDL_PLATFORM_LINUX
#if (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)) && defined(HAVE_DLOPEN)
#include <dlfcn.h>
#ifndef RTLD_DEFAULT
#define RTLD_DEFAULT NULL
#endif
#endif
#include "../SDL_thread_c.h"
#include "../SDL_systhread.h"
#ifdef SDL_PLATFORM_ANDROID
#include "../../core/android/SDL_android.h"
#endif
#ifdef SDL_PLATFORM_HAIKU
#include <kernel/OS.h>
#endif
#ifdef HAVE_SIGNAL_H
// List of signals to mask in the subthreads
static const int sig_list[] = {
SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
SIGVTALRM, SIGPROF, 0
};
#endif
static void *RunThread(void *data)
{
#ifdef SDL_PLATFORM_ANDROID
Android_JNI_SetupThread();
#endif
SDL_RunThread((SDL_Thread *)data);
return NULL;
}
#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)) && defined(HAVE_DLOPEN)
static bool checked_setname = false;
static int (*ppthread_setname_np)(const char *) = NULL;
#elif (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)
static bool checked_setname = false;
static int (*ppthread_setname_np)(pthread_t, const char *) = NULL;
#endif
bool SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{
pthread_attr_t type;
// do this here before any threads exist, so there's no race condition.
#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)
if (!checked_setname) {
void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)
ppthread_setname_np = (int (*)(const char *))fn;
#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)
ppthread_setname_np = (int (*)(pthread_t, const char *))fn;
#endif
checked_setname = true;
}
#endif
// Set the thread attributes
if (pthread_attr_init(&type) != 0) {
return SDL_SetError("Couldn't initialize pthread attributes");
}
pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
// Set caller-requested stack size. Otherwise: use the system default.
if (thread->stacksize) {
pthread_attr_setstacksize(&type, thread->stacksize);
}
// Create the thread and go!
if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {
return SDL_SetError("Not enough resources to create thread");
}
return true;
}
void SDL_SYS_SetupThread(const char *name)
{
#ifdef HAVE_SIGNAL_H
int i;
sigset_t mask;
#endif
if (name) {
#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)
SDL_assert(checked_setname);
if (ppthread_setname_np) {
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)
ppthread_setname_np(name);
#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)
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 defined(HAVE_PTHREAD_SETNAME_NP)
#ifdef SDL_PLATFORM_NETBSD
pthread_setname_np(pthread_self(), "%s", name);
#else
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 defined(HAVE_PTHREAD_SET_NAME_NP)
pthread_set_name_np(pthread_self(), name);
#elif defined(SDL_PLATFORM_HAIKU)
// The docs say the thread name can't be longer than B_OS_NAME_LENGTH.
char namebuf[B_OS_NAME_LENGTH];
SDL_strlcpy(namebuf, name, sizeof(namebuf));
rename_thread(find_thread(NULL), namebuf);
#endif
}
#ifdef HAVE_SIGNAL_H
// Mask asynchronous signals for this thread
sigemptyset(&mask);
for (i = 0; sig_list[i]; ++i) {
sigaddset(&mask, sig_list[i]);
}
pthread_sigmask(SIG_BLOCK, &mask, 0);
#endif
#ifdef PTHREAD_CANCEL_ASYNCHRONOUS
// Allow ourselves to be asynchronously cancelled
{
int oldstate;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
}
#endif
}
SDL_ThreadID SDL_GetCurrentThreadID(void)
{
return (SDL_ThreadID)pthread_self();
}
bool SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
{
#ifdef SDL_PLATFORM_RISCOS
// FIXME: Setting thread priority does not seem to be supported
return true;
#else
struct sched_param sched;
int policy;
int pri_policy;
pthread_t thread = pthread_self();
const char *policyhint = SDL_GetHint(SDL_HINT_THREAD_PRIORITY_POLICY);
const bool timecritical_realtime_hint = SDL_GetHintBoolean(SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL, false);
if (pthread_getschedparam(thread, &policy, &sched) != 0) {
return SDL_SetError("pthread_getschedparam() failed");
}
/* Higher priority levels may require changing the pthread scheduler policy
* for the thread. SDL will make such changes by default but there is
* also a hint allowing that behavior to be overridden. */
switch (priority) {
case SDL_THREAD_PRIORITY_LOW:
case SDL_THREAD_PRIORITY_NORMAL:
pri_policy = SCHED_OTHER;
break;
case SDL_THREAD_PRIORITY_HIGH:
case SDL_THREAD_PRIORITY_TIME_CRITICAL:
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
// Apple requires SCHED_RR for high priority threads
pri_policy = SCHED_RR;
break;
#else
pri_policy = SCHED_OTHER;
break;
#endif
default:
pri_policy = policy;
break;
}
if (timecritical_realtime_hint && priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
pri_policy = SCHED_RR;
}
if (policyhint) {
if (SDL_strcmp(policyhint, "current") == 0) {
// Leave current thread scheduler policy unchanged
} else if (SDL_strcmp(policyhint, "other") == 0) {
policy = SCHED_OTHER;
} else if (SDL_strcmp(policyhint, "rr") == 0) {
policy = SCHED_RR;
} else if (SDL_strcmp(policyhint, "fifo") == 0) {
policy = SCHED_FIFO;
} else {
policy = pri_policy;
}
} else {
policy = pri_policy;
}
#ifdef SDL_PLATFORM_LINUX
{
pid_t linuxTid = syscall(SYS_gettid);
return SDL_SetLinuxThreadPriorityAndPolicy(linuxTid, priority, policy);
}
#else
if (priority == SDL_THREAD_PRIORITY_LOW) {
sched.sched_priority = sched_get_priority_min(policy);
} else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
sched.sched_priority = sched_get_priority_max(policy);
} else {
int min_priority = sched_get_priority_min(policy);
int max_priority = sched_get_priority_max(policy);
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
if (min_priority == 15 && max_priority == 47) {
// Apple has a specific set of thread priorities
if (priority == SDL_THREAD_PRIORITY_HIGH) {
sched.sched_priority = 45;
} else {
sched.sched_priority = 37;
}
} else
#endif // SDL_PLATFORM_MACOS || SDL_PLATFORM_IOS || SDL_PLATFORM_TVOS
{
sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
if (priority == SDL_THREAD_PRIORITY_HIGH) {
sched.sched_priority += ((max_priority - min_priority) / 4);
}
}
}
if (pthread_setschedparam(thread, policy, &sched) != 0) {
return SDL_SetError("pthread_setschedparam() failed");
}
return true;
#endif // linux
#endif // #if SDL_PLATFORM_RISCOS
}
void SDL_SYS_WaitThread(SDL_Thread *thread)
{
pthread_join(thread->handle, 0);
}
void SDL_SYS_DetachThread(SDL_Thread *thread)
{
pthread_detach(thread->handle);
}

View File

@@ -0,0 +1,25 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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 <pthread.h>
typedef pthread_t SYS_ThreadHandle;

View File

@@ -0,0 +1,78 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 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_systhread.h"
#include "../SDL_thread_c.h"
#include <pthread.h>
#define INVALID_PTHREAD_KEY ((pthread_key_t)-1)
static pthread_key_t thread_local_storage = INVALID_PTHREAD_KEY;
static bool generic_local_storage = false;
void SDL_SYS_InitTLSData(void)
{
if (thread_local_storage == INVALID_PTHREAD_KEY && !generic_local_storage) {
if (pthread_key_create(&thread_local_storage, NULL) != 0) {
thread_local_storage = INVALID_PTHREAD_KEY;
SDL_Generic_InitTLSData();
generic_local_storage = true;
}
}
}
SDL_TLSData *SDL_SYS_GetTLSData(void)
{
if (generic_local_storage) {
return SDL_Generic_GetTLSData();
}
if (thread_local_storage != INVALID_PTHREAD_KEY) {
return (SDL_TLSData *)pthread_getspecific(thread_local_storage);
}
return NULL;
}
bool SDL_SYS_SetTLSData(SDL_TLSData *data)
{
if (generic_local_storage) {
return SDL_Generic_SetTLSData(data);
}
if (pthread_setspecific(thread_local_storage, data) != 0) {
return SDL_SetError("pthread_setspecific() failed");
}
return true;
}
void SDL_SYS_QuitTLSData(void)
{
if (generic_local_storage) {
SDL_Generic_QuitTLSData();
generic_local_storage = false;
} else {
if (thread_local_storage != INVALID_PTHREAD_KEY) {
pthread_key_delete(thread_local_storage);
thread_local_storage = INVALID_PTHREAD_KEY;
}
}
}