SDL  2.0
SDL_systhread.c
Go to the documentation of this file.
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 #include "../../SDL_internal.h"
22 
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 
64 #ifndef __NACL__
65 /* List of signals to mask in the subthreads */
66 static const int sig_list[] = {
67  SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
68  SIGVTALRM, SIGPROF, 0
69 };
70 #endif
71 
72 static void *
74 {
75 #ifdef __ANDROID__
77 #endif
79  return NULL;
80 }
81 
82 #if defined(__MACOSX__) || defined(__IPHONEOS__)
83 static SDL_bool checked_setname = SDL_FALSE;
84 static int (*ppthread_setname_np)(const char*) = NULL;
85 #elif defined(__LINUX__)
86 static SDL_bool checked_setname = SDL_FALSE;
87 static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
88 #endif
89 int
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, thread->stacksize);
116  }
117 
118  /* Create the thread and go! */
119  if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {
120  return SDL_SetError("Not enough resources to create thread");
121  }
122 
123  return 0;
124 }
125 
126 void
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 
183 {
184  return ((SDL_threadID) pthread_self());
185 }
186 
187 #if __LINUX__
188 /**
189  \brief Sets the SDL priority (not nice level) for a thread, using setpriority() if appropriate, and RealtimeKit if available.
190  Differs from SDL_LinuxSetThreadPriority in also taking the desired scheduler policy,
191  such as SCHED_OTHER or SCHED_RR.
192 
193  \return 0 on success, or -1 on error.
194  */
195 extern DECLSPEC int SDLCALL SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy);
196 #endif
197 
198 int
200 {
201 #if __NACL__ || __RISCOS__
202  /* FIXME: Setting thread priority does not seem to be supported in NACL */
203  return 0;
204 #else
205  struct sched_param sched;
206  int policy;
207  int pri_policy;
208  pthread_t thread = pthread_self();
209  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) {
222  pri_policy = SCHED_OTHER;
223  break;
226 #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
227  /* Apple requires SCHED_RR for high priority threads */
228  pri_policy = SCHED_RR;
229  break;
230 #else
231  pri_policy = SCHED_OTHER;
232  break;
233 #endif
234  default:
235  pri_policy = policy;
236  break;
237  }
238 
239  if (timecritical_realtime_hint && priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
240  pri_policy = SCHED_RR;
241  }
242 
243  if (policyhint) {
244  if (SDL_strcmp(policyhint, "current") == 0) {
245  /* Leave current thread scheduler policy unchanged */
246  } else if (SDL_strcmp(policyhint, "other") == 0) {
247  policy = SCHED_OTHER;
248  } else if (SDL_strcmp(policyhint, "rr") == 0) {
249  policy = SCHED_RR;
250  } else if (SDL_strcmp(policyhint, "fifo") == 0) {
251  policy = SCHED_FIFO;
252  } else {
253  policy = pri_policy;
254  }
255  } else {
256  policy = pri_policy;
257  }
258 
259 #if __LINUX__
260  {
261  pid_t linuxTid = syscall(SYS_gettid);
262  return SDL_LinuxSetThreadPriorityAndPolicy(linuxTid, priority, policy);
263  }
264 #else
265  if (priority == SDL_THREAD_PRIORITY_LOW) {
266  sched.sched_priority = sched_get_priority_min(policy);
267  } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
268  sched.sched_priority = sched_get_priority_max(policy);
269  } else {
270  int min_priority = sched_get_priority_min(policy);
271  int max_priority = sched_get_priority_max(policy);
272 
273 #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
274  if (min_priority == 15 && max_priority == 47) {
275  /* Apple has a specific set of thread priorities */
276  if (priority == SDL_THREAD_PRIORITY_HIGH) {
277  sched.sched_priority = 45;
278  } else {
279  sched.sched_priority = 37;
280  }
281  } else
282 #endif /* __MACOSX__ || __IPHONEOS__ || __TVOS__ */
283  {
284  sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
285  if (priority == SDL_THREAD_PRIORITY_HIGH) {
286  sched.sched_priority += ((max_priority - min_priority) / 4);
287  }
288  }
289  }
290  if (pthread_setschedparam(thread, policy, &sched) != 0) {
291  return SDL_SetError("pthread_setschedparam() failed");
292  }
293  return 0;
294 #endif /* linux */
295 #endif /* #if __NACL__ || __RISCOS__ */
296 }
297 
298 void
300 {
301  pthread_join(thread->handle, 0);
302 }
303 
304 void
306 {
307  pthread_detach(thread->handle);
308 }
309 
310 /* vi: set ts=4 sw=4 expandtab: */
int Android_JNI_SetupThread(void)
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#define SDL_SetError
#define SDL_strcmp
#define SDL_GetHintBoolean
#define SDL_snprintf
#define SDL_GetHint
#define SDL_HINT_THREAD_PRIORITY_POLICY
A string specifying additional information to use with SDL_SetThreadPriority.
Definition: SDL_hints.h:815
#define SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL
Specifies whether SDL_THREAD_PRIORITY_TIME_CRITICAL should be treated as realtime.
Definition: SDL_hints.h:834
#define SDLCALL
Definition: SDL_internal.h:49
#define DECLSPEC
Definition: SDL_internal.h:48
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLuint const GLchar * name
GLenum GLint GLuint mask
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
int64_t Sint64
Definition: SDL_stdinc.h:216
void SDL_RunThread(SDL_Thread *thread)
Definition: SDL_thread.c:261
unsigned long SDL_threadID
Definition: SDL_thread.h:49
SDL_ThreadPriority
Definition: SDL_thread.h:64
@ SDL_THREAD_PRIORITY_TIME_CRITICAL
Definition: SDL_thread.h:68
@ SDL_THREAD_PRIORITY_LOW
Definition: SDL_thread.h:65
@ SDL_THREAD_PRIORITY_HIGH
Definition: SDL_thread.h:67
@ SDL_THREAD_PRIORITY_NORMAL
Definition: SDL_thread.h:66
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
EGLint policy
Definition: eglext.h:593
void SDL_SYS_SetupThread(const char *name)
Definition: SDL_systhread.c:42
int SDL_SYS_CreateThread(SDL_Thread *thread)
Definition: SDL_systhread.c:35
void SDL_SYS_DetachThread(SDL_Thread *thread)
Definition: SDL_systhread.c:66
int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
Definition: SDL_systhread.c:54
void SDL_SYS_WaitThread(SDL_Thread *thread)
Definition: SDL_systhread.c:60
SDL_threadID SDL_ThreadID(void)
Definition: SDL_systhread.c:48
static const int sig_list[]
Definition: SDL_systhread.c:66
static void * RunThread(void *data)
Definition: SDL_systhread.c:73
SYS_ThreadHandle handle
Definition: SDL_thread_c.h:59
size_t stacksize
Definition: SDL_thread_c.h:64
typedef int(__stdcall *FARPROC)()