src/thread/pthread/SDL_systhread.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sat, 15 Aug 2015 21:21:29 +0200
changeset 9846 9f0a0c7de41a
parent 9755 e4f04633f291
child 9987 d64783aac765
permissions -rw-r--r--
Removed not needed call to pthread_attr_getstacksize() for SDL_CreateThread().
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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 
    24 #include <pthread.h>
    25 
    26 #if HAVE_PTHREAD_NP_H
    27 #include <pthread_np.h>
    28 #endif
    29 
    30 #include <signal.h>
    31 
    32 #ifdef __LINUX__
    33 #include <sys/time.h>
    34 #include <sys/resource.h>
    35 #include <sys/syscall.h>
    36 #include <unistd.h>
    37 #endif /* __LINUX__ */
    38 
    39 #if defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__)
    40 #include <dlfcn.h>
    41 #ifndef RTLD_DEFAULT
    42 #define RTLD_DEFAULT NULL
    43 #endif
    44 #endif
    45 
    46 #include "SDL_platform.h"
    47 #include "SDL_thread.h"
    48 #include "SDL_hints.h"
    49 #include "../SDL_thread_c.h"
    50 #include "../SDL_systhread.h"
    51 #ifdef __ANDROID__
    52 #include "../../core/android/SDL_android.h"
    53 #endif
    54 
    55 #ifdef __HAIKU__
    56 #include <be/kernel/OS.h>
    57 #endif
    58 
    59 #include "SDL_assert.h"
    60 
    61 #ifndef __NACL__
    62 /* List of signals to mask in the subthreads */
    63 static const int sig_list[] = {
    64     SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
    65     SIGVTALRM, SIGPROF, 0
    66 };
    67 #endif
    68 
    69 static void *
    70 RunThread(void *data)
    71 {
    72 #ifdef __ANDROID__
    73     Android_JNI_SetupThread();
    74 #endif
    75     SDL_RunThread(data);
    76     return NULL;
    77 }
    78 
    79 #if defined(__MACOSX__) || defined(__IPHONEOS__)
    80 static SDL_bool checked_setname = SDL_FALSE;
    81 static int (*ppthread_setname_np)(const char*) = NULL;
    82 #elif defined(__LINUX__)
    83 static SDL_bool checked_setname = SDL_FALSE;
    84 static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
    85 #endif
    86 int
    87 SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
    88 {
    89     pthread_attr_t type;
    90     const char *hint = SDL_GetHint(SDL_HINT_THREAD_STACK_SIZE);
    91 
    92     /* do this here before any threads exist, so there's no race condition. */
    93     #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
    94     if (!checked_setname) {
    95         void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
    96         #if defined(__MACOSX__) || defined(__IPHONEOS__)
    97         ppthread_setname_np = (int(*)(const char*)) fn;
    98         #elif defined(__LINUX__)
    99         ppthread_setname_np = (int(*)(pthread_t, const char*)) fn;
   100         #endif
   101         checked_setname = SDL_TRUE;
   102     }
   103     #endif
   104 
   105     /* Set the thread attributes */
   106     if (pthread_attr_init(&type) != 0) {
   107         return SDL_SetError("Couldn't initialize pthread attributes");
   108     }
   109     pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
   110     
   111     /* If the SDL_HINT_THREAD_STACK_SIZE exists and it seems to be a positive number, use it */
   112     if (hint && hint[0] >= '0' && hint[0] <= '9') {
   113         const size_t stacksize = (size_t) SDL_atoi(hint);
   114         if (stacksize > 0) {
   115             pthread_attr_setstacksize(&type, stacksize);
   116         }
   117     }
   118 
   119     /* Create the thread and go! */
   120     if (pthread_create(&thread->handle, &type, RunThread, args) != 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(__ANDROID__) && !defined(__NACL__)
   131     int i;
   132     sigset_t mask;
   133 #endif /* !__ANDROID__ && !__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             pthread_setname_np(pthread_self(), name);
   147         #elif HAVE_PTHREAD_SET_NAME_NP
   148             pthread_set_name_np(pthread_self(), name);
   149         #elif defined(__HAIKU__)
   150             /* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */
   151             char namebuf[B_OS_NAME_LENGTH];
   152             SDL_snprintf(namebuf, sizeof (namebuf), "%s", name);
   153             namebuf[sizeof (namebuf) - 1] = '\0';
   154             rename_thread(find_thread(NULL), namebuf);
   155         #endif
   156     }
   157 
   158    /* NativeClient does not yet support signals.*/
   159 #if !defined(__ANDROID__) && !defined(__NACL__)
   160     /* Mask asynchronous signals for this thread */
   161     sigemptyset(&mask);
   162     for (i = 0; sig_list[i]; ++i) {
   163         sigaddset(&mask, sig_list[i]);
   164     }
   165     pthread_sigmask(SIG_BLOCK, &mask, 0);
   166 #endif /* !__ANDROID__ && !__NACL__ */
   167 
   168 
   169 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
   170     /* Allow ourselves to be asynchronously cancelled */
   171     {
   172         int oldstate;
   173         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
   174     }
   175 #endif
   176 }
   177 
   178 SDL_threadID
   179 SDL_ThreadID(void)
   180 {
   181     return ((SDL_threadID) pthread_self());
   182 }
   183 
   184 int
   185 SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
   186 {
   187 #if __NACL__ 
   188     /* FIXME: Setting thread priority does not seem to be supported in NACL */
   189     return 0;
   190 #elif __LINUX__
   191     int value;
   192 
   193     if (priority == SDL_THREAD_PRIORITY_LOW) {
   194         value = 19;
   195     } else if (priority == SDL_THREAD_PRIORITY_HIGH) {
   196         value = -20;
   197     } else {
   198         value = 0;
   199     }
   200     if (setpriority(PRIO_PROCESS, syscall(SYS_gettid), value) < 0) {
   201         /* Note that this fails if you're trying to set high priority
   202            and you don't have root permission. BUT DON'T RUN AS ROOT!
   203          */
   204         return SDL_SetError("setpriority() failed");
   205     }
   206     return 0;
   207 #else
   208     struct sched_param sched;
   209     int policy;
   210     pthread_t thread = pthread_self();
   211 
   212     if (pthread_getschedparam(thread, &policy, &sched) < 0) {
   213         return SDL_SetError("pthread_getschedparam() failed");
   214     }
   215     if (priority == SDL_THREAD_PRIORITY_LOW) {
   216         sched.sched_priority = sched_get_priority_min(policy);
   217     } else if (priority == SDL_THREAD_PRIORITY_HIGH) {
   218         sched.sched_priority = sched_get_priority_max(policy);
   219     } else {
   220         int min_priority = sched_get_priority_min(policy);
   221         int max_priority = sched_get_priority_max(policy);
   222         sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
   223     }
   224     if (pthread_setschedparam(thread, policy, &sched) < 0) {
   225         return SDL_SetError("pthread_setschedparam() failed");
   226     }
   227     return 0;
   228 #endif /* linux */
   229 }
   230 
   231 void
   232 SDL_SYS_WaitThread(SDL_Thread * thread)
   233 {
   234     pthread_join(thread->handle, 0);
   235 }
   236 
   237 void
   238 SDL_SYS_DetachThread(SDL_Thread * thread)
   239 {
   240     pthread_detach(thread->handle);
   241 }
   242 
   243 /* vi: set ts=4 sw=4 expandtab: */