src/thread/pthread/SDL_systhread.c
author Ozkan Sezer
Thu, 29 Oct 2020 20:00:20 +0300
changeset 14209 467540bb2114
parent 13852 99e30511f83d
permissions -rw-r--r--
SDL_stdinc.h: define _DARWIN_C_SOURCE on macOS for memset_pattern4()

hopefully fixes https://bugzilla.libsdl.org/show_bug.cgi?id=5107
     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 
    22 #include "../../SDL_internal.h"
    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 #include "SDL_assert.h"
    64 
    65 #ifndef __NACL__
    66 /* List of signals to mask in the subthreads */
    67 static const int sig_list[] = {
    68     SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
    69     SIGVTALRM, SIGPROF, 0
    70 };
    71 #endif
    72 
    73 static void *
    74 RunThread(void *data)
    75 {
    76 #ifdef __ANDROID__
    77     Android_JNI_SetupThread();
    78 #endif
    79     SDL_RunThread((SDL_Thread *) data);
    80     return NULL;
    81 }
    82 
    83 #if defined(__MACOSX__) || defined(__IPHONEOS__)
    84 static SDL_bool checked_setname = SDL_FALSE;
    85 static int (*ppthread_setname_np)(const char*) = NULL;
    86 #elif defined(__LINUX__)
    87 static SDL_bool checked_setname = SDL_FALSE;
    88 static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
    89 #endif
    90 int
    91 SDL_SYS_CreateThread(SDL_Thread * thread)
    92 {
    93     pthread_attr_t type;
    94 
    95     /* do this here before any threads exist, so there's no race condition. */
    96     #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
    97     if (!checked_setname) {
    98         void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
    99         #if defined(__MACOSX__) || defined(__IPHONEOS__)
   100         ppthread_setname_np = (int(*)(const char*)) fn;
   101         #elif defined(__LINUX__)
   102         ppthread_setname_np = (int(*)(pthread_t, const char*)) fn;
   103         #endif
   104         checked_setname = SDL_TRUE;
   105     }
   106     #endif
   107 
   108     /* Set the thread attributes */
   109     if (pthread_attr_init(&type) != 0) {
   110         return SDL_SetError("Couldn't initialize pthread attributes");
   111     }
   112     pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
   113     
   114     /* Set caller-requested stack size. Otherwise: use the system default. */
   115     if (thread->stacksize) {
   116         pthread_attr_setstacksize(&type, thread->stacksize);
   117     }
   118 
   119     /* Create the thread and go! */
   120     if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {
   121         return SDL_SetError("Not enough resources to create thread");
   122     }
   123 
   124     return 0;
   125 }
   126 
   127 void
   128 SDL_SYS_SetupThread(const char *name)
   129 {
   130 #if !defined(__NACL__)
   131     int i;
   132     sigset_t mask;
   133 #endif /* !__NACL__ */
   134 
   135     if (name != NULL) {
   136         #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
   137         SDL_assert(checked_setname);
   138         if (ppthread_setname_np != NULL) {
   139             #if defined(__MACOSX__) || defined(__IPHONEOS__)
   140             ppthread_setname_np(name);
   141             #elif defined(__LINUX__)
   142             ppthread_setname_np(pthread_self(), name);
   143             #endif
   144         }
   145         #elif HAVE_PTHREAD_SETNAME_NP
   146             #if defined(__NETBSD__)
   147             pthread_setname_np(pthread_self(), "%s", name);
   148             #else
   149             pthread_setname_np(pthread_self(), name);
   150             #endif
   151         #elif HAVE_PTHREAD_SET_NAME_NP
   152             pthread_set_name_np(pthread_self(), name);
   153         #elif defined(__HAIKU__)
   154             /* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */
   155             char namebuf[B_OS_NAME_LENGTH];
   156             SDL_snprintf(namebuf, sizeof (namebuf), "%s", name);
   157             namebuf[sizeof (namebuf) - 1] = '\0';
   158             rename_thread(find_thread(NULL), namebuf);
   159         #endif
   160     }
   161 
   162    /* NativeClient does not yet support signals.*/
   163 #if !defined(__NACL__)
   164     /* Mask asynchronous signals for this thread */
   165     sigemptyset(&mask);
   166     for (i = 0; sig_list[i]; ++i) {
   167         sigaddset(&mask, sig_list[i]);
   168     }
   169     pthread_sigmask(SIG_BLOCK, &mask, 0);
   170 #endif /* !__NACL__ */
   171 
   172 
   173 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
   174     /* Allow ourselves to be asynchronously cancelled */
   175     {
   176         int oldstate;
   177         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
   178     }
   179 #endif
   180 }
   181 
   182 SDL_threadID
   183 SDL_ThreadID(void)
   184 {
   185     return ((SDL_threadID) pthread_self());
   186 }
   187 
   188 #if __LINUX__
   189 /**
   190    \brief Sets the SDL priority (not nice level) for a thread, using setpriority() if appropriate, and RealtimeKit if available.
   191    Differs from SDL_LinuxSetThreadPriority in also taking the desired scheduler policy,
   192    such as SCHED_OTHER or SCHED_RR.
   193 
   194    \return 0 on success, or -1 on error.
   195  */
   196 extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy);
   197 #endif
   198 
   199 int
   200 SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
   201 {
   202 #if __NACL__ || __RISCOS__
   203     /* FIXME: Setting thread priority does not seem to be supported in NACL */
   204     return 0;
   205 #else
   206     struct sched_param sched;
   207     int policy;
   208     int pri_policy;
   209     pthread_t thread = pthread_self();
   210     const char *policyhint = SDL_GetHint(SDL_HINT_THREAD_PRIORITY_POLICY);
   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         pri_policy = SCHED_RR;
   227         break;
   228     default:
   229         pri_policy = policy;
   230         break;
   231     }
   232 
   233     if (policyhint) {
   234         if (SDL_strcmp(policyhint, "current") == 0) {
   235             /* Leave current thread scheduler policy unchanged */
   236         } else if (SDL_strcmp(policyhint, "other") == 0) {
   237             policy = SCHED_OTHER;
   238         } else if (SDL_strcmp(policyhint, "rr") == 0) {
   239             policy = SCHED_RR;
   240         } else if (SDL_strcmp(policyhint, "fifo") == 0) {
   241             policy = SCHED_FIFO;
   242         } else {
   243             policy = pri_policy;
   244         }
   245     } else {
   246         policy = pri_policy;
   247     }
   248 
   249 #if __LINUX__
   250     {
   251         pid_t linuxTid = syscall(SYS_gettid);
   252         return SDL_LinuxSetThreadPriorityAndPolicy(linuxTid, priority, policy);
   253     }
   254 #else
   255     if (priority == SDL_THREAD_PRIORITY_LOW) {
   256         sched.sched_priority = sched_get_priority_min(policy);
   257     } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
   258         sched.sched_priority = sched_get_priority_max(policy);
   259     } else {
   260         int min_priority = sched_get_priority_min(policy);
   261         int max_priority = sched_get_priority_max(policy);
   262 
   263 #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
   264         if (min_priority == 15 && max_priority == 47) {
   265             /* Apple has a specific set of thread priorities */
   266             if (priority == SDL_THREAD_PRIORITY_HIGH) {
   267                 sched.sched_priority = 45;
   268             } else {
   269                 sched.sched_priority = 37;
   270             }
   271         } else
   272 #endif /* __MACOSX__ || __IPHONEOS__ || __TVOS__ */
   273         {
   274             sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
   275             if (priority == SDL_THREAD_PRIORITY_HIGH) {
   276                 sched.sched_priority += ((max_priority - min_priority) / 4);
   277             }
   278         }
   279     }
   280     if (pthread_setschedparam(thread, policy, &sched) != 0) {
   281         return SDL_SetError("pthread_setschedparam() failed");
   282     }
   283     return 0;
   284 #endif /* linux */
   285 #endif /* #if __NACL__ || __RISCOS__ */
   286 }
   287 
   288 void
   289 SDL_SYS_WaitThread(SDL_Thread * thread)
   290 {
   291     pthread_join(thread->handle, 0);
   292 }
   293 
   294 void
   295 SDL_SYS_DetachThread(SDL_Thread * thread)
   296 {
   297     pthread_detach(thread->handle);
   298 }
   299 
   300 /* vi: set ts=4 sw=4 expandtab: */