src/thread/pthread/SDL_systhread.c
author Ryan C. Gordon
Wed, 05 Dec 2018 16:51:22 -0500
changeset 12456 f8041c025fd3
parent 12454 762a775a58cd
child 12462 b57435750c5b
permissions -rw-r--r--
linux: Move SDL_LinuxSetThreadPriority() elsewhere to fix build.

Fixes Bugzilla #4393.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 
    25 #include <pthread.h>
    26 
    27 #if HAVE_PTHREAD_NP_H
    28 #include <pthread_np.h>
    29 #endif
    30 
    31 #include <signal.h>
    32 
    33 #ifdef __LINUX__
    34 #include <sys/time.h>
    35 #include <sys/resource.h>
    36 #include <sys/syscall.h>
    37 #include <unistd.h>
    38 #include <errno.h>
    39 
    40 #include "../../core/linux/SDL_dbus.h"
    41 #endif /* __LINUX__ */
    42 
    43 #if defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__)
    44 #include <dlfcn.h>
    45 #ifndef RTLD_DEFAULT
    46 #define RTLD_DEFAULT NULL
    47 #endif
    48 #endif
    49 
    50 #include "SDL_log.h"
    51 #include "SDL_platform.h"
    52 #include "SDL_thread.h"
    53 #include "SDL_system.h"
    54 #include "../SDL_thread_c.h"
    55 #include "../SDL_systhread.h"
    56 #ifdef __ANDROID__
    57 #include "../../core/android/SDL_android.h"
    58 #endif
    59 
    60 #ifdef __HAIKU__
    61 #include <kernel/OS.h>
    62 #endif
    63 
    64 #include "SDL_assert.h"
    65 
    66 #ifndef __NACL__
    67 /* List of signals to mask in the subthreads */
    68 static const int sig_list[] = {
    69     SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
    70     SIGVTALRM, SIGPROF, 0
    71 };
    72 #endif
    73 
    74 static void *
    75 RunThread(void *data)
    76 {
    77 #ifdef __ANDROID__
    78     Android_JNI_SetupThread();
    79 #endif
    80     SDL_RunThread(data);
    81     return NULL;
    82 }
    83 
    84 #if defined(__MACOSX__) || defined(__IPHONEOS__)
    85 static SDL_bool checked_setname = SDL_FALSE;
    86 static int (*ppthread_setname_np)(const char*) = NULL;
    87 #elif defined(__LINUX__)
    88 static SDL_bool checked_setname = SDL_FALSE;
    89 static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
    90 #endif
    91 int
    92 SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
    93 {
    94     pthread_attr_t type;
    95 
    96     /* do this here before any threads exist, so there's no race condition. */
    97     #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
    98     if (!checked_setname) {
    99         void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
   100         #if defined(__MACOSX__) || defined(__IPHONEOS__)
   101         ppthread_setname_np = (int(*)(const char*)) fn;
   102         #elif defined(__LINUX__)
   103         ppthread_setname_np = (int(*)(pthread_t, const char*)) fn;
   104         #endif
   105         checked_setname = SDL_TRUE;
   106     }
   107     #endif
   108 
   109     /* Set the thread attributes */
   110     if (pthread_attr_init(&type) != 0) {
   111         return SDL_SetError("Couldn't initialize pthread attributes");
   112     }
   113     pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
   114     
   115     /* Set caller-requested stack size. Otherwise: use the system default. */
   116     if (thread->stacksize) {
   117         pthread_attr_setstacksize(&type, (size_t) thread->stacksize);
   118     }
   119 
   120     /* Create the thread and go! */
   121     if (pthread_create(&thread->handle, &type, RunThread, args) != 0) {
   122         return SDL_SetError("Not enough resources to create thread");
   123     }
   124 
   125     return 0;
   126 }
   127 
   128 void
   129 SDL_SYS_SetupThread(const char *name)
   130 {
   131 #if !defined(__NACL__)
   132     int i;
   133     sigset_t mask;
   134 #endif /* !__NACL__ */
   135 
   136     if (name != NULL) {
   137         #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
   138         SDL_assert(checked_setname);
   139         if (ppthread_setname_np != NULL) {
   140             #if defined(__MACOSX__) || defined(__IPHONEOS__)
   141             ppthread_setname_np(name);
   142             #elif defined(__LINUX__)
   143             ppthread_setname_np(pthread_self(), name);
   144             #endif
   145         }
   146         #elif HAVE_PTHREAD_SETNAME_NP
   147             #if defined(__NETBSD__)
   148             pthread_setname_np(pthread_self(), "%s", name);
   149             #else
   150             pthread_setname_np(pthread_self(), name);
   151             #endif
   152         #elif HAVE_PTHREAD_SET_NAME_NP
   153             pthread_set_name_np(pthread_self(), name);
   154         #elif defined(__HAIKU__)
   155             /* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */
   156             char namebuf[B_OS_NAME_LENGTH];
   157             SDL_snprintf(namebuf, sizeof (namebuf), "%s", name);
   158             namebuf[sizeof (namebuf) - 1] = '\0';
   159             rename_thread(find_thread(NULL), namebuf);
   160         #endif
   161     }
   162 
   163    /* NativeClient does not yet support signals.*/
   164 #if !defined(__NACL__)
   165     /* Mask asynchronous signals for this thread */
   166     sigemptyset(&mask);
   167     for (i = 0; sig_list[i]; ++i) {
   168         sigaddset(&mask, sig_list[i]);
   169     }
   170     pthread_sigmask(SIG_BLOCK, &mask, 0);
   171 #endif /* !__NACL__ */
   172 
   173 
   174 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
   175     /* Allow ourselves to be asynchronously cancelled */
   176     {
   177         int oldstate;
   178         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
   179     }
   180 #endif
   181 }
   182 
   183 SDL_threadID
   184 SDL_ThreadID(void)
   185 {
   186     return ((SDL_threadID) pthread_self());
   187 }
   188 
   189 int
   190 SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
   191 {
   192 #if __NACL__ 
   193     /* FIXME: Setting thread priority does not seem to be supported in NACL */
   194     return 0;
   195 #elif __LINUX__
   196     int value;
   197     pid_t thread = syscall(SYS_gettid);
   198 
   199     if (priority == SDL_THREAD_PRIORITY_LOW) {
   200         value = 19;
   201     } else if (priority == SDL_THREAD_PRIORITY_HIGH) {
   202         value = -10;
   203     } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
   204         value = -20;
   205     } else {
   206         value = 0;
   207     }
   208     return SDL_LinuxSetThreadPriority(thread, value);
   209 #else
   210     struct sched_param sched;
   211     int policy;
   212     pthread_t thread = pthread_self();
   213 
   214     if (pthread_getschedparam(thread, &policy, &sched) != 0) {
   215         return SDL_SetError("pthread_getschedparam() failed");
   216     }
   217     if (priority == SDL_THREAD_PRIORITY_LOW) {
   218         sched.sched_priority = sched_get_priority_min(policy);
   219     } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
   220         sched.sched_priority = sched_get_priority_max(policy);
   221     } else {
   222         int min_priority = sched_get_priority_min(policy);
   223         int max_priority = sched_get_priority_max(policy);
   224         sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
   225         if (priority == SDL_THREAD_PRIORITY_HIGH) {
   226             sched.sched_priority += ((max_priority - min_priority) / 4);
   227         }
   228     }
   229     if (pthread_setschedparam(thread, policy, &sched) != 0) {
   230         return SDL_SetError("pthread_setschedparam() failed");
   231     }
   232     return 0;
   233 #endif /* linux */
   234 }
   235 
   236 void
   237 SDL_SYS_WaitThread(SDL_Thread * thread)
   238 {
   239     pthread_join(thread->handle, 0);
   240 }
   241 
   242 void
   243 SDL_SYS_DetachThread(SDL_Thread * thread)
   244 {
   245     pthread_detach(thread->handle);
   246 }
   247 
   248 /* vi: set ts=4 sw=4 expandtab: */