src/thread/pthread/SDL_systhread.c
author Gabriel Jacobo <gabomdq@gmail.com>
Fri, 06 Jun 2014 15:45:59 -0300
changeset 8833 ae720d61d14d
parent 8149 681eb46b8ac4
child 8879 f6e4f24df1ac
permissions -rw-r--r--
Chrome's Native Client backend implementation
slouken@1361
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@1361
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1361
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1361
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1361
    20
*/
icculus@5981
    21
icculus@8093
    22
#include "../../SDL_internal.h"
slouken@1361
    23
slouken@1361
    24
#include <pthread.h>
icculus@5969
    25
icculus@5969
    26
#if HAVE_PTHREAD_NP_H
icculus@5969
    27
#include <pthread_np.h>
icculus@5969
    28
#endif
icculus@5969
    29
slouken@1361
    30
#include <signal.h>
icculus@6640
    31
slouken@5513
    32
#ifdef __LINUX__
slouken@5509
    33
#include <sys/time.h>
slouken@5509
    34
#include <sys/resource.h>
slouken@5509
    35
#include <sys/syscall.h>
icculus@5981
    36
#include <unistd.h>
slouken@7191
    37
#endif /* __LINUX__ */
slouken@1361
    38
icculus@6640
    39
#if defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__)
slouken@6605
    40
#include <dlfcn.h>
icculus@6640
    41
#ifndef RTLD_DEFAULT
icculus@6640
    42
#define RTLD_DEFAULT NULL
icculus@6640
    43
#endif
slouken@6605
    44
#endif
slouken@6605
    45
icculus@5969
    46
#include "SDL_platform.h"
slouken@1361
    47
#include "SDL_thread.h"
slouken@1361
    48
#include "../SDL_thread_c.h"
slouken@1361
    49
#include "../SDL_systhread.h"
gabomdq@6354
    50
#ifdef __ANDROID__
gabomdq@6354
    51
#include "../../core/android/SDL_android.h"
gabomdq@6354
    52
#endif
slouken@1361
    53
icculus@7977
    54
#ifdef __HAIKU__
icculus@7977
    55
#include <be/kernel/OS.h>
icculus@7977
    56
#endif
icculus@7977
    57
icculus@6640
    58
#include "SDL_assert.h"
icculus@6640
    59
slouken@1361
    60
/* List of signals to mask in the subthreads */
slouken@3162
    61
static const int sig_list[] = {
slouken@1895
    62
    SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
slouken@1895
    63
    SIGVTALRM, SIGPROF, 0
slouken@1361
    64
};
slouken@1361
    65
slouken@1895
    66
static void *
slouken@1895
    67
RunThread(void *data)
slouken@1361
    68
{
gabomdq@6354
    69
#ifdef __ANDROID__
gabomdq@6354
    70
    Android_JNI_SetupThread();
gabomdq@6354
    71
#endif
slouken@1895
    72
    SDL_RunThread(data);
icculus@5963
    73
    return NULL;
slouken@1361
    74
}
slouken@1361
    75
icculus@6640
    76
#if defined(__MACOSX__) || defined(__IPHONEOS__)
icculus@6640
    77
static SDL_bool checked_setname = SDL_FALSE;
icculus@6641
    78
static int (*ppthread_setname_np)(const char*) = NULL;
icculus@6640
    79
#elif defined(__LINUX__)
icculus@6640
    80
static SDL_bool checked_setname = SDL_FALSE;
icculus@6641
    81
static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
icculus@6640
    82
#endif
slouken@1895
    83
int
slouken@1895
    84
SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
slouken@1361
    85
{
slouken@1895
    86
    pthread_attr_t type;
slouken@1361
    87
icculus@6640
    88
    /* do this here before any threads exist, so there's no race condition. */
icculus@6640
    89
    #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
icculus@6640
    90
    if (!checked_setname) {
icculus@6640
    91
        void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
icculus@6640
    92
        #if defined(__MACOSX__) || defined(__IPHONEOS__)
icculus@6641
    93
        ppthread_setname_np = (int(*)(const char*)) fn;
icculus@6640
    94
        #elif defined(__LINUX__)
icculus@6641
    95
        ppthread_setname_np = (int(*)(pthread_t, const char*)) fn;
icculus@6640
    96
        #endif
icculus@6640
    97
        checked_setname = SDL_TRUE;
icculus@6640
    98
    }
icculus@6640
    99
    #endif
icculus@6640
   100
slouken@1895
   101
    /* Set the thread attributes */
slouken@1895
   102
    if (pthread_attr_init(&type) != 0) {
icculus@7037
   103
        return SDL_SetError("Couldn't initialize pthread attributes");
slouken@1895
   104
    }
slouken@1895
   105
    pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
slouken@1361
   106
slouken@1895
   107
    /* Create the thread and go! */
slouken@1895
   108
    if (pthread_create(&thread->handle, &type, RunThread, args) != 0) {
icculus@7037
   109
        return SDL_SetError("Not enough resources to create thread");
slouken@1895
   110
    }
slouken@1459
   111
icculus@7037
   112
    return 0;
slouken@1361
   113
}
slouken@1361
   114
slouken@1895
   115
void
icculus@5969
   116
SDL_SYS_SetupThread(const char *name)
slouken@1361
   117
{
slouken@1895
   118
    int i;
slouken@1895
   119
    sigset_t mask;
slouken@1361
   120
icculus@6000
   121
    if (name != NULL) {
icculus@6640
   122
        #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__)
icculus@6640
   123
        SDL_assert(checked_setname);
icculus@6641
   124
        if (ppthread_setname_np != NULL) {
icculus@6640
   125
            #if defined(__MACOSX__) || defined(__IPHONEOS__)
icculus@6641
   126
            ppthread_setname_np(name);
icculus@6640
   127
            #elif defined(__LINUX__)
icculus@6641
   128
            ppthread_setname_np(pthread_self(), name);
icculus@6640
   129
            #endif
icculus@6640
   130
        }
icculus@6640
   131
        #elif HAVE_PTHREAD_SETNAME_NP
icculus@6640
   132
            pthread_setname_np(pthread_self(), name);
icculus@6640
   133
        #elif HAVE_PTHREAD_SET_NAME_NP
icculus@6640
   134
            pthread_set_name_np(pthread_self(), name);
icculus@7977
   135
        #elif defined(__HAIKU__)
icculus@7977
   136
            /* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */
icculus@7977
   137
            char namebuf[B_OS_NAME_LENGTH];
icculus@7977
   138
            SDL_snprintf(namebuf, sizeof (namebuf), "%s", name);
icculus@7977
   139
            namebuf[sizeof (namebuf) - 1] = '\0';
icculus@7977
   140
            rename_thread(find_thread(NULL), namebuf);
icculus@6640
   141
        #endif
icculus@6000
   142
    }
icculus@5969
   143
gabomdq@8833
   144
   /* NativeClient does not yet support signals.*/
gabomdq@8833
   145
#ifndef __NACL__
slouken@1895
   146
    /* Mask asynchronous signals for this thread */
slouken@1895
   147
    sigemptyset(&mask);
slouken@1895
   148
    for (i = 0; sig_list[i]; ++i) {
slouken@1895
   149
        sigaddset(&mask, sig_list[i]);
slouken@1895
   150
    }
slouken@1895
   151
    pthread_sigmask(SIG_BLOCK, &mask, 0);
gabomdq@8833
   152
#endif
slouken@1361
   153
slouken@1361
   154
#ifdef PTHREAD_CANCEL_ASYNCHRONOUS
slouken@1895
   155
    /* Allow ourselves to be asynchronously cancelled */
slouken@1895
   156
    {
slouken@1895
   157
        int oldstate;
slouken@1895
   158
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
slouken@1895
   159
    }
slouken@1361
   160
#endif
slouken@1361
   161
}
slouken@1361
   162
slouken@3578
   163
SDL_threadID
slouken@1895
   164
SDL_ThreadID(void)
slouken@1361
   165
{
slouken@3578
   166
    return ((SDL_threadID) pthread_self());
slouken@1361
   167
}
slouken@1361
   168
slouken@5506
   169
int
slouken@5509
   170
SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
slouken@5506
   171
{
gabomdq@8833
   172
#if __NACL__ 
gabomdq@8833
   173
    /* FIXME: Setting thread priority does not seem to be supported in NACL */
gabomdq@8833
   174
    return 0;
gabomdq@8833
   175
#elif __LINUX__
slouken@5509
   176
    int value;
slouken@5509
   177
slouken@5509
   178
    if (priority == SDL_THREAD_PRIORITY_LOW) {
slouken@5509
   179
        value = 19;
slouken@5509
   180
    } else if (priority == SDL_THREAD_PRIORITY_HIGH) {
slouken@5509
   181
        value = -20;
slouken@5509
   182
    } else {
slouken@5509
   183
        value = 0;
slouken@5509
   184
    }
slouken@5509
   185
    if (setpriority(PRIO_PROCESS, syscall(SYS_gettid), value) < 0) {
slouken@5510
   186
        /* Note that this fails if you're trying to set high priority
slouken@5510
   187
           and you don't have root permission. BUT DON'T RUN AS ROOT!
slouken@5510
   188
         */
icculus@7037
   189
        return SDL_SetError("setpriority() failed");
slouken@5509
   190
    }
slouken@5509
   191
    return 0;
slouken@5509
   192
#else
slouken@5506
   193
    struct sched_param sched;
slouken@5506
   194
    int policy;
slouken@5509
   195
    pthread_t thread = pthread_self();
slouken@5506
   196
slouken@5509
   197
    if (pthread_getschedparam(thread, &policy, &sched) < 0) {
icculus@7037
   198
        return SDL_SetError("pthread_getschedparam() failed");
slouken@5506
   199
    }
slouken@5506
   200
    if (priority == SDL_THREAD_PRIORITY_LOW) {
slouken@5506
   201
        sched.sched_priority = sched_get_priority_min(policy);
slouken@5506
   202
    } else if (priority == SDL_THREAD_PRIORITY_HIGH) {
slouken@5506
   203
        sched.sched_priority = sched_get_priority_max(policy);
slouken@5506
   204
    } else {
slouken@5506
   205
        int min_priority = sched_get_priority_min(policy);
slouken@5506
   206
        int max_priority = sched_get_priority_max(policy);
slouken@5509
   207
        sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
slouken@5506
   208
    }
slouken@5509
   209
    if (pthread_setschedparam(thread, policy, &sched) < 0) {
icculus@7037
   210
        return SDL_SetError("pthread_setschedparam() failed");
slouken@5506
   211
    }
slouken@5506
   212
    return 0;
slouken@5509
   213
#endif /* linux */
slouken@5506
   214
}
slouken@5506
   215
slouken@1895
   216
void
slouken@1895
   217
SDL_SYS_WaitThread(SDL_Thread * thread)
slouken@1361
   218
{
slouken@1895
   219
    pthread_join(thread->handle, 0);
slouken@1361
   220
}
slouken@1361
   221
icculus@7978
   222
void
icculus@7978
   223
SDL_SYS_DetachThread(SDL_Thread * thread)
icculus@7978
   224
{
icculus@7978
   225
    pthread_detach(thread->handle);
icculus@7978
   226
}
icculus@7978
   227
slouken@1895
   228
/* vi: set ts=4 sw=4 expandtab: */