Atlas - SDL_systhread.c
Home / ext / SDL2 / src / thread / pthread Lines: 1 | Size: 9505 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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#include <errno.h> 38 39#include "../../core/linux/SDL_dbus.h" 40#endif /* __LINUX__ */ 41 42#if defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__) 43#include <dlfcn.h> 44#ifndef RTLD_DEFAULT 45#define RTLD_DEFAULT NULL 46#endif 47#endif 48 49#include "SDL_log.h" 50#include "SDL_platform.h" 51#include "SDL_thread.h" 52#include "../SDL_thread_c.h" 53#include "../SDL_systhread.h" 54#ifdef __ANDROID__ 55#include "../../core/android/SDL_android.h" 56#endif 57 58#ifdef __HAIKU__ 59#include <kernel/OS.h> 60#endif 61 62#include "SDL_assert.h" 63 64#ifndef __NACL__ 65/* List of signals to mask in the subthreads */ 66static const int sig_list[] = { 67 SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH, 68 SIGVTALRM, SIGPROF, 0 69}; 70#endif 71 72static void * 73RunThread(void *data) 74{ 75#ifdef __ANDROID__ 76 Android_JNI_SetupThread(); 77#endif 78 SDL_RunThread(data); 79 return NULL; 80} 81 82#if defined(__MACOSX__) || defined(__IPHONEOS__) 83static SDL_bool checked_setname = SDL_FALSE; 84static int (*ppthread_setname_np)(const char*) = NULL; 85#elif defined(__LINUX__) 86static SDL_bool checked_setname = SDL_FALSE; 87static int (*ppthread_setname_np)(pthread_t, const char*) = NULL; 88#endif 89int 90SDL_SYS_CreateThread(SDL_Thread * thread, void *args) 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, (size_t) thread->stacksize); 116 } 117 118 /* Create the thread and go! */ 119 if (pthread_create(&thread->handle, &type, RunThread, args) != 0) { 120 return SDL_SetError("Not enough resources to create thread"); 121 } 122 123 return 0; 124} 125 126void 127SDL_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 181SDL_threadID 182SDL_ThreadID(void) 183{ 184 return ((SDL_threadID) pthread_self()); 185} 186 187#if __LINUX__ 188/* d-bus queries to org.freedesktop.RealtimeKit1. */ 189#if SDL_USE_LIBDBUS 190 191#define RTKIT_DBUS_NODE "org.freedesktop.RealtimeKit1" 192#define RTKIT_DBUS_PATH "/org/freedesktop/RealtimeKit1" 193#define RTKIT_DBUS_INTERFACE "org.freedesktop.RealtimeKit1" 194 195static pthread_once_t rtkit_initialize_once = PTHREAD_ONCE_INIT; 196static Sint32 rtkit_min_nice_level = -20; 197 198static void 199rtkit_initialize() 200{ 201 SDL_DBusContext *dbus = SDL_DBus_GetContext(); 202 203 /* Try getting minimum nice level: this is often greater than PRIO_MIN (-20). */ 204 if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MinNiceLevel", 205 DBUS_TYPE_INT32, &rtkit_min_nice_level)) { 206 rtkit_min_nice_level = -20; 207 } 208} 209 210static SDL_bool 211rtkit_setpriority(pid_t thread, int nice_level) 212{ 213 Uint64 ui64 = (Uint64)thread; 214 Sint32 si32 = (Sint32)nice_level; 215 SDL_DBusContext *dbus = SDL_DBus_GetContext(); 216 217 pthread_once(&rtkit_initialize_once, rtkit_initialize); 218 219 if (si32 < rtkit_min_nice_level) 220 si32 = rtkit_min_nice_level; 221 222 if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn, 223 RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadHighPriority", 224 DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_INT32, &si32, DBUS_TYPE_INVALID, 225 DBUS_TYPE_INVALID)) { 226 return SDL_FALSE; 227 } 228 return SDL_TRUE; 229} 230 231#else 232 233static SDL_bool 234rtkit_setpriority(pid_t thread, int nice_level) 235{ 236 return SDL_FALSE; 237} 238 239#endif /* !SDL_USE_LIBDBUS */ 240 241int 242SDL_LinuxSetThreadPriority(Sint64 threadID, int priority) 243{ 244 if (setpriority(PRIO_PROCESS, (id_t)threadID, priority) < 0) { 245 /* Note that this fails if you're trying to set high priority 246 and you don't have root permission. BUT DON'T RUN AS ROOT! 247 248 You can grant the ability to increase thread priority by 249 running the following command on your application binary: 250 sudo setcap 'cap_sys_nice=eip' <application> 251 252 Let's try setting priority with RealtimeKit... 253 254 README and sample code at: 255 http://git.0pointer.net/rtkit.git 256 */ 257 if (rtkit_setpriority((pid_t)threadID, priority) == SDL_FALSE) { 258 return SDL_SetError("setpriority() failed"); 259 } 260 } 261 return 0; 262} 263#endif /* __LINUX__ */ 264 265int 266SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) 267{ 268#if __NACL__ 269 /* FIXME: Setting thread priority does not seem to be supported in NACL */ 270 return 0; 271#elif __LINUX__ 272 int value; 273 pid_t thread = syscall(SYS_gettid); 274 275 if (priority == SDL_THREAD_PRIORITY_LOW) { 276 value = 19; 277 } else if (priority == SDL_THREAD_PRIORITY_HIGH) { 278 value = -10; 279 } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) { 280 value = -20; 281 } else { 282 value = 0; 283 } 284 return SDL_LinuxSetThreadPriority(thread, value); 285#else 286 struct sched_param sched; 287 int policy; 288 pthread_t thread = pthread_self(); 289 290 if (pthread_getschedparam(thread, &policy, &sched) != 0) { 291 return SDL_SetError("pthread_getschedparam() failed"); 292 } 293 if (priority == SDL_THREAD_PRIORITY_LOW) { 294 sched.sched_priority = sched_get_priority_min(policy); 295 } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) { 296 sched.sched_priority = sched_get_priority_max(policy); 297 } else { 298 int min_priority = sched_get_priority_min(policy); 299 int max_priority = sched_get_priority_max(policy); 300 sched.sched_priority = (min_priority + (max_priority - min_priority) / 2); 301 if (priority == SDL_THREAD_PRIORITY_HIGH) { 302 sched.sched_priority += ((max_priority - min_priority) / 4); 303 } 304 } 305 if (pthread_setschedparam(thread, policy, &sched) != 0) { 306 return SDL_SetError("pthread_setschedparam() failed"); 307 } 308 return 0; 309#endif /* linux */ 310} 311 312void 313SDL_SYS_WaitThread(SDL_Thread * thread) 314{ 315 pthread_join(thread->handle, 0); 316} 317 318void 319SDL_SYS_DetachThread(SDL_Thread * thread) 320{ 321 pthread_detach(thread->handle); 322} 323 324/* vi: set ts=4 sw=4 expandtab: */ 325[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.