Path: blob/master/thirdparty/sdl/thread/pthread/SDL_systhread.c
10279 views
/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/20#include "SDL_internal.h"2122#include <pthread.h>2324#ifdef HAVE_PTHREAD_NP_H25#include <pthread_np.h>26#endif2728#ifdef HAVE_SIGNAL_H29#include <signal.h>30#endif31#include <errno.h>3233#ifdef SDL_PLATFORM_LINUX34#include <sys/time.h>35#include <sys/resource.h>36#include <sys/syscall.h>37#include <unistd.h>3839#include "../../core/linux/SDL_dbus.h"40#endif // SDL_PLATFORM_LINUX4142#if (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)) && defined(HAVE_DLOPEN)43#include <dlfcn.h>44#ifndef RTLD_DEFAULT45#define RTLD_DEFAULT NULL46#endif47#endif4849#include "../SDL_thread_c.h"50#include "../SDL_systhread.h"51#ifdef SDL_PLATFORM_ANDROID52#include "../../core/android/SDL_android.h"53#endif5455#ifdef SDL_PLATFORM_HAIKU56#include <kernel/OS.h>57#endif5859#ifdef HAVE_SIGNAL_H60// List of signals to mask in the subthreads61static const int sig_list[] = {62SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,63SIGVTALRM, SIGPROF, 064};65#endif6667static void *RunThread(void *data)68{69#ifdef SDL_PLATFORM_ANDROID70Android_JNI_SetupThread();71#endif72SDL_RunThread((SDL_Thread *)data);73return NULL;74}7576#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)) && defined(HAVE_DLOPEN)77static bool checked_setname = false;78static int (*ppthread_setname_np)(const char *) = NULL;79#elif (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)80static bool checked_setname = false;81static int (*ppthread_setname_np)(pthread_t, const char *) = NULL;82#endif83bool SDL_SYS_CreateThread(SDL_Thread *thread,84SDL_FunctionPointer pfnBeginThread,85SDL_FunctionPointer pfnEndThread)86{87pthread_attr_t type;8889// do this here before any threads exist, so there's no race condition.90#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)91if (!checked_setname) {92void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");93#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)94ppthread_setname_np = (int (*)(const char *))fn;95#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)96ppthread_setname_np = (int (*)(pthread_t, const char *))fn;97#endif98checked_setname = true;99}100#endif101102// Set the thread attributes103if (pthread_attr_init(&type) != 0) {104return SDL_SetError("Couldn't initialize pthread attributes");105}106pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);107108// Set caller-requested stack size. Otherwise: use the system default.109if (thread->stacksize) {110pthread_attr_setstacksize(&type, thread->stacksize);111}112113// Create the thread and go!114if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {115return SDL_SetError("Not enough resources to create thread");116}117118return true;119}120121void SDL_SYS_SetupThread(const char *name)122{123#ifdef HAVE_SIGNAL_H124int i;125sigset_t mask;126#endif127128if (name) {129#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)130SDL_assert(checked_setname);131if (ppthread_setname_np) {132#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)133ppthread_setname_np(name);134#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)135if (ppthread_setname_np(pthread_self(), name) == ERANGE) {136char namebuf[16]; // Limited to 16 char137SDL_strlcpy(namebuf, name, sizeof(namebuf));138ppthread_setname_np(pthread_self(), namebuf);139}140#endif141}142#elif defined(HAVE_PTHREAD_SETNAME_NP)143#ifdef SDL_PLATFORM_NETBSD144pthread_setname_np(pthread_self(), "%s", name);145#else146if (pthread_setname_np(pthread_self(), name) == ERANGE) {147char namebuf[16]; // Limited to 16 char148SDL_strlcpy(namebuf, name, sizeof(namebuf));149pthread_setname_np(pthread_self(), namebuf);150}151#endif152#elif defined(HAVE_PTHREAD_SET_NAME_NP)153pthread_set_name_np(pthread_self(), name);154#elif defined(SDL_PLATFORM_HAIKU)155// The docs say the thread name can't be longer than B_OS_NAME_LENGTH.156char namebuf[B_OS_NAME_LENGTH];157SDL_strlcpy(namebuf, name, sizeof(namebuf));158rename_thread(find_thread(NULL), namebuf);159#endif160}161162#ifdef HAVE_SIGNAL_H163// Mask asynchronous signals for this thread164sigemptyset(&mask);165for (i = 0; sig_list[i]; ++i) {166sigaddset(&mask, sig_list[i]);167}168pthread_sigmask(SIG_BLOCK, &mask, 0);169#endif170171#ifdef PTHREAD_CANCEL_ASYNCHRONOUS172// Allow ourselves to be asynchronously cancelled173{174int oldstate;175pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);176}177#endif178}179180SDL_ThreadID SDL_GetCurrentThreadID(void)181{182return (SDL_ThreadID)pthread_self();183}184185bool SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)186{187#ifdef SDL_PLATFORM_RISCOS188// FIXME: Setting thread priority does not seem to be supported189return true;190#else191struct sched_param sched;192int policy;193int pri_policy;194pthread_t thread = pthread_self();195const char *policyhint = SDL_GetHint(SDL_HINT_THREAD_PRIORITY_POLICY);196const bool timecritical_realtime_hint = SDL_GetHintBoolean(SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL, false);197198if (pthread_getschedparam(thread, &policy, &sched) != 0) {199return SDL_SetError("pthread_getschedparam() failed");200}201202/* Higher priority levels may require changing the pthread scheduler policy203* for the thread. SDL will make such changes by default but there is204* also a hint allowing that behavior to be overridden. */205switch (priority) {206case SDL_THREAD_PRIORITY_LOW:207case SDL_THREAD_PRIORITY_NORMAL:208pri_policy = SCHED_OTHER;209break;210case SDL_THREAD_PRIORITY_HIGH:211case SDL_THREAD_PRIORITY_TIME_CRITICAL:212#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)213// Apple requires SCHED_RR for high priority threads214pri_policy = SCHED_RR;215break;216#else217pri_policy = SCHED_OTHER;218break;219#endif220default:221pri_policy = policy;222break;223}224225if (timecritical_realtime_hint && priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {226pri_policy = SCHED_RR;227}228229if (policyhint) {230if (SDL_strcmp(policyhint, "current") == 0) {231// Leave current thread scheduler policy unchanged232} else if (SDL_strcmp(policyhint, "other") == 0) {233policy = SCHED_OTHER;234} else if (SDL_strcmp(policyhint, "rr") == 0) {235policy = SCHED_RR;236} else if (SDL_strcmp(policyhint, "fifo") == 0) {237policy = SCHED_FIFO;238} else {239policy = pri_policy;240}241} else {242policy = pri_policy;243}244245#ifdef SDL_PLATFORM_LINUX246{247pid_t linuxTid = syscall(SYS_gettid);248return SDL_SetLinuxThreadPriorityAndPolicy(linuxTid, priority, policy);249}250#else251if (priority == SDL_THREAD_PRIORITY_LOW) {252sched.sched_priority = sched_get_priority_min(policy);253} else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {254sched.sched_priority = sched_get_priority_max(policy);255} else {256int min_priority = sched_get_priority_min(policy);257int max_priority = sched_get_priority_max(policy);258259#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)260if (min_priority == 15 && max_priority == 47) {261// Apple has a specific set of thread priorities262if (priority == SDL_THREAD_PRIORITY_HIGH) {263sched.sched_priority = 45;264} else {265sched.sched_priority = 37;266}267} else268#endif // SDL_PLATFORM_MACOS || SDL_PLATFORM_IOS || SDL_PLATFORM_TVOS269{270sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);271if (priority == SDL_THREAD_PRIORITY_HIGH) {272sched.sched_priority += ((max_priority - min_priority) / 4);273}274}275}276if (pthread_setschedparam(thread, policy, &sched) != 0) {277return SDL_SetError("pthread_setschedparam() failed");278}279return true;280#endif // linux281#endif // #if SDL_PLATFORM_RISCOS282}283284void SDL_SYS_WaitThread(SDL_Thread *thread)285{286pthread_join(thread->handle, 0);287}288289void SDL_SYS_DetachThread(SDL_Thread *thread)290{291pthread_detach(thread->handle);292}293294295