sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_systhread.c (9435B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 #include "../../SDL_internal.h"
     22 
     23 #include "SDL_system.h"
     24 #include "SDL_hints.h"
     25 
     26 #include <pthread.h>
     27 
     28 #if HAVE_PTHREAD_NP_H
     29 #include <pthread_np.h>
     30 #endif
     31 
     32 #include <signal.h>
     33 
     34 #ifdef __LINUX__
     35 #include <sys/time.h>
     36 #include <sys/resource.h>
     37 #include <sys/syscall.h>
     38 #include <unistd.h>
     39 #include <errno.h>
     40 
     41 #include "../../core/linux/SDL_dbus.h"
     42 #endif /* __LINUX__ */
     43 
     44 #if defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__)
     45 #include <dlfcn.h>
     46 #ifndef RTLD_DEFAULT
     47 #define RTLD_DEFAULT NULL
     48 #endif
     49 #endif
     50 
     51 #include "SDL_platform.h"
     52 #include "SDL_thread.h"
     53 #include "../SDL_thread_c.h"
     54 #include "../SDL_systhread.h"
     55 #ifdef __ANDROID__
     56 #include "../../core/android/SDL_android.h"
     57 #endif
     58 
     59 #ifdef __HAIKU__
     60 #include <kernel/OS.h>
     61 #endif
     62 
     63 
     64 #ifndef __NACL__
     65 /* List of signals to mask in the subthreads */
     66 static const int sig_list[] = {
     67     SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
     68     SIGVTALRM, SIGPROF, 0
     69 };
     70 #endif
     71 
     72 static void *
     73 RunThread(void *data)
     74 {
     75 #ifdef __ANDROID__
     76     Android_JNI_SetupThread();
     77 #endif
     78     SDL_RunThread((SDL_Thread *) data);
     79     return NULL;
     80 }
     81 
     82 #if defined(__MACOSX__) || defined(__IPHONEOS__)
     83 static SDL_bool checked_setname = SDL_FALSE;
     84 static int (*ppthread_setname_np)(const char*) = NULL;
     85 #elif defined(__LINUX__)
     86 static SDL_bool checked_setname = SDL_FALSE;
     87 static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
     88 #endif
     89 int
     90 SDL_SYS_CreateThread(SDL_Thread * thread)
     91 {
     92     pthread_attr_t type;
     93 
     94     /* do this here before any threads exist, so there's no race condition. */
     95     #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
     96     if (!checked_setname) {
     97         void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
     98         #if defined(__MACOSX__) || defined(__IPHONEOS__)
     99         ppthread_setname_np = (int(*)(const char*)) fn;
    100         #elif defined(__LINUX__)
    101         ppthread_setname_np = (int(*)(pthread_t, const char*)) fn;
    102         #endif
    103         checked_setname = SDL_TRUE;
    104     }
    105     #endif
    106 
    107     /* Set the thread attributes */
    108     if (pthread_attr_init(&type) != 0) {
    109         return SDL_SetError("Couldn't initialize pthread attributes");
    110     }
    111     pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
    112     
    113     /* Set caller-requested stack size. Otherwise: use the system default. */
    114     if (thread->stacksize) {
    115         pthread_attr_setstacksize(&type, thread->stacksize);
    116     }
    117 
    118     /* Create the thread and go! */
    119     if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {
    120         return SDL_SetError("Not enough resources to create thread");
    121     }
    122 
    123     return 0;
    124 }
    125 
    126 void
    127 SDL_SYS_SetupThread(const char *name)
    128 {
    129 #if !defined(__NACL__)
    130     int i;
    131     sigset_t mask;
    132 #endif /* !__NACL__ */
    133 
    134     if (name != NULL) {
    135         #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
    136         SDL_assert(checked_setname);
    137         if (ppthread_setname_np != NULL) {
    138             #if defined(__MACOSX__) || defined(__IPHONEOS__)
    139             ppthread_setname_np(name);
    140             #elif defined(__LINUX__)
    141             ppthread_setname_np(pthread_self(), name);
    142             #endif
    143         }
    144         #elif HAVE_PTHREAD_SETNAME_NP
    145             #if defined(__NETBSD__)
    146             pthread_setname_np(pthread_self(), "%s", name);
    147             #else
    148             pthread_setname_np(pthread_self(), name);
    149             #endif
    150         #elif HAVE_PTHREAD_SET_NAME_NP
    151             pthread_set_name_np(pthread_self(), name);
    152         #elif defined(__HAIKU__)
    153             /* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */
    154             char namebuf[B_OS_NAME_LENGTH];
    155             SDL_snprintf(namebuf, sizeof (namebuf), "%s", name);
    156             namebuf[sizeof (namebuf) - 1] = '\0';
    157             rename_thread(find_thread(NULL), namebuf);
    158         #endif
    159     }
    160 
    161    /* NativeClient does not yet support signals.*/
    162 #if !defined(__NACL__)
    163     /* Mask asynchronous signals for this thread */
    164     sigemptyset(&mask);
    165     for (i = 0; sig_list[i]; ++i) {
    166         sigaddset(&mask, sig_list[i]);
    167     }
    168     pthread_sigmask(SIG_BLOCK, &mask, 0);
    169 #endif /* !__NACL__ */
    170 
    171 
    172 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
    173     /* Allow ourselves to be asynchronously cancelled */
    174     {
    175         int oldstate;
    176         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
    177     }
    178 #endif
    179 }
    180 
    181 SDL_threadID
    182 SDL_ThreadID(void)
    183 {
    184     return ((SDL_threadID) pthread_self());
    185 }
    186 
    187 #if __LINUX__
    188 /**
    189    \brief Sets the SDL priority (not nice level) for a thread, using setpriority() if appropriate, and RealtimeKit if available.
    190    Differs from SDL_LinuxSetThreadPriority in also taking the desired scheduler policy,
    191    such as SCHED_OTHER or SCHED_RR.
    192 
    193    \return 0 on success, or -1 on error.
    194  */
    195 extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy);
    196 #endif
    197 
    198 int
    199 SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
    200 {
    201 #if __NACL__ || __RISCOS__
    202     /* FIXME: Setting thread priority does not seem to be supported in NACL */
    203     return 0;
    204 #else
    205     struct sched_param sched;
    206     int policy;
    207     int pri_policy;
    208     pthread_t thread = pthread_self();
    209     const char *policyhint = SDL_GetHint(SDL_HINT_THREAD_PRIORITY_POLICY);
    210     const SDL_bool timecritical_realtime_hint = SDL_GetHintBoolean(SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL, SDL_FALSE);
    211 
    212     if (pthread_getschedparam(thread, &policy, &sched) != 0) {
    213         return SDL_SetError("pthread_getschedparam() failed");
    214     }
    215 
    216     /* Higher priority levels may require changing the pthread scheduler policy
    217      * for the thread.  SDL will make such changes by default but there is
    218      * also a hint allowing that behavior to be overridden. */
    219     switch (priority) {
    220     case SDL_THREAD_PRIORITY_LOW:
    221     case SDL_THREAD_PRIORITY_NORMAL:
    222         pri_policy = SCHED_OTHER;
    223         break;
    224     case SDL_THREAD_PRIORITY_HIGH:
    225     case SDL_THREAD_PRIORITY_TIME_CRITICAL:
    226 #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
    227         /* Apple requires SCHED_RR for high priority threads */
    228         pri_policy = SCHED_RR;
    229         break;
    230 #else
    231         pri_policy = SCHED_OTHER;
    232         break;
    233 #endif
    234     default:
    235         pri_policy = policy;
    236         break;
    237     }
    238 
    239     if (timecritical_realtime_hint && priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
    240         pri_policy = SCHED_RR;
    241     }
    242 
    243     if (policyhint) {
    244         if (SDL_strcmp(policyhint, "current") == 0) {
    245             /* Leave current thread scheduler policy unchanged */
    246         } else if (SDL_strcmp(policyhint, "other") == 0) {
    247             policy = SCHED_OTHER;
    248         } else if (SDL_strcmp(policyhint, "rr") == 0) {
    249             policy = SCHED_RR;
    250         } else if (SDL_strcmp(policyhint, "fifo") == 0) {
    251             policy = SCHED_FIFO;
    252         } else {
    253             policy = pri_policy;
    254         }
    255     } else {
    256         policy = pri_policy;
    257     }
    258 
    259 #if __LINUX__
    260     {
    261         pid_t linuxTid = syscall(SYS_gettid);
    262         return SDL_LinuxSetThreadPriorityAndPolicy(linuxTid, priority, policy);
    263     }
    264 #else
    265     if (priority == SDL_THREAD_PRIORITY_LOW) {
    266         sched.sched_priority = sched_get_priority_min(policy);
    267     } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
    268         sched.sched_priority = sched_get_priority_max(policy);
    269     } else {
    270         int min_priority = sched_get_priority_min(policy);
    271         int max_priority = sched_get_priority_max(policy);
    272 
    273 #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
    274         if (min_priority == 15 && max_priority == 47) {
    275             /* Apple has a specific set of thread priorities */
    276             if (priority == SDL_THREAD_PRIORITY_HIGH) {
    277                 sched.sched_priority = 45;
    278             } else {
    279                 sched.sched_priority = 37;
    280             }
    281         } else
    282 #endif /* __MACOSX__ || __IPHONEOS__ || __TVOS__ */
    283         {
    284             sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
    285             if (priority == SDL_THREAD_PRIORITY_HIGH) {
    286                 sched.sched_priority += ((max_priority - min_priority) / 4);
    287             }
    288         }
    289     }
    290     if (pthread_setschedparam(thread, policy, &sched) != 0) {
    291         return SDL_SetError("pthread_setschedparam() failed");
    292     }
    293     return 0;
    294 #endif /* linux */
    295 #endif /* #if __NACL__ || __RISCOS__ */
    296 }
    297 
    298 void
    299 SDL_SYS_WaitThread(SDL_Thread * thread)
    300 {
    301     pthread_join(thread->handle, 0);
    302 }
    303 
    304 void
    305 SDL_SYS_DetachThread(SDL_Thread * thread)
    306 {
    307     pthread_detach(thread->handle);
    308 }
    309 
    310 /* vi: set ts=4 sw=4 expandtab: */