Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/thread/pthread/SDL_systhread.c
10279 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 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
#include "SDL_internal.h"
22
23
#include <pthread.h>
24
25
#ifdef HAVE_PTHREAD_NP_H
26
#include <pthread_np.h>
27
#endif
28
29
#ifdef HAVE_SIGNAL_H
30
#include <signal.h>
31
#endif
32
#include <errno.h>
33
34
#ifdef SDL_PLATFORM_LINUX
35
#include <sys/time.h>
36
#include <sys/resource.h>
37
#include <sys/syscall.h>
38
#include <unistd.h>
39
40
#include "../../core/linux/SDL_dbus.h"
41
#endif // SDL_PLATFORM_LINUX
42
43
#if (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)) && defined(HAVE_DLOPEN)
44
#include <dlfcn.h>
45
#ifndef RTLD_DEFAULT
46
#define RTLD_DEFAULT NULL
47
#endif
48
#endif
49
50
#include "../SDL_thread_c.h"
51
#include "../SDL_systhread.h"
52
#ifdef SDL_PLATFORM_ANDROID
53
#include "../../core/android/SDL_android.h"
54
#endif
55
56
#ifdef SDL_PLATFORM_HAIKU
57
#include <kernel/OS.h>
58
#endif
59
60
#ifdef HAVE_SIGNAL_H
61
// List of signals to mask in the subthreads
62
static const int sig_list[] = {
63
SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
64
SIGVTALRM, SIGPROF, 0
65
};
66
#endif
67
68
static void *RunThread(void *data)
69
{
70
#ifdef SDL_PLATFORM_ANDROID
71
Android_JNI_SetupThread();
72
#endif
73
SDL_RunThread((SDL_Thread *)data);
74
return NULL;
75
}
76
77
#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)) && defined(HAVE_DLOPEN)
78
static bool checked_setname = false;
79
static int (*ppthread_setname_np)(const char *) = NULL;
80
#elif (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)
81
static bool checked_setname = false;
82
static int (*ppthread_setname_np)(pthread_t, const char *) = NULL;
83
#endif
84
bool SDL_SYS_CreateThread(SDL_Thread *thread,
85
SDL_FunctionPointer pfnBeginThread,
86
SDL_FunctionPointer pfnEndThread)
87
{
88
pthread_attr_t type;
89
90
// do this here before any threads exist, so there's no race condition.
91
#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)
92
if (!checked_setname) {
93
void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np");
94
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)
95
ppthread_setname_np = (int (*)(const char *))fn;
96
#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)
97
ppthread_setname_np = (int (*)(pthread_t, const char *))fn;
98
#endif
99
checked_setname = true;
100
}
101
#endif
102
103
// Set the thread attributes
104
if (pthread_attr_init(&type) != 0) {
105
return SDL_SetError("Couldn't initialize pthread attributes");
106
}
107
pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
108
109
// Set caller-requested stack size. Otherwise: use the system default.
110
if (thread->stacksize) {
111
pthread_attr_setstacksize(&type, thread->stacksize);
112
}
113
114
// Create the thread and go!
115
if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {
116
return SDL_SetError("Not enough resources to create thread");
117
}
118
119
return true;
120
}
121
122
void SDL_SYS_SetupThread(const char *name)
123
{
124
#ifdef HAVE_SIGNAL_H
125
int i;
126
sigset_t mask;
127
#endif
128
129
if (name) {
130
#if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_DLOPEN)
131
SDL_assert(checked_setname);
132
if (ppthread_setname_np) {
133
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)
134
ppthread_setname_np(name);
135
#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)
136
if (ppthread_setname_np(pthread_self(), name) == ERANGE) {
137
char namebuf[16]; // Limited to 16 char
138
SDL_strlcpy(namebuf, name, sizeof(namebuf));
139
ppthread_setname_np(pthread_self(), namebuf);
140
}
141
#endif
142
}
143
#elif defined(HAVE_PTHREAD_SETNAME_NP)
144
#ifdef SDL_PLATFORM_NETBSD
145
pthread_setname_np(pthread_self(), "%s", name);
146
#else
147
if (pthread_setname_np(pthread_self(), name) == ERANGE) {
148
char namebuf[16]; // Limited to 16 char
149
SDL_strlcpy(namebuf, name, sizeof(namebuf));
150
pthread_setname_np(pthread_self(), namebuf);
151
}
152
#endif
153
#elif defined(HAVE_PTHREAD_SET_NAME_NP)
154
pthread_set_name_np(pthread_self(), name);
155
#elif defined(SDL_PLATFORM_HAIKU)
156
// The docs say the thread name can't be longer than B_OS_NAME_LENGTH.
157
char namebuf[B_OS_NAME_LENGTH];
158
SDL_strlcpy(namebuf, name, sizeof(namebuf));
159
rename_thread(find_thread(NULL), namebuf);
160
#endif
161
}
162
163
#ifdef HAVE_SIGNAL_H
164
// Mask asynchronous signals for this thread
165
sigemptyset(&mask);
166
for (i = 0; sig_list[i]; ++i) {
167
sigaddset(&mask, sig_list[i]);
168
}
169
pthread_sigmask(SIG_BLOCK, &mask, 0);
170
#endif
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
181
SDL_ThreadID SDL_GetCurrentThreadID(void)
182
{
183
return (SDL_ThreadID)pthread_self();
184
}
185
186
bool SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
187
{
188
#ifdef SDL_PLATFORM_RISCOS
189
// FIXME: Setting thread priority does not seem to be supported
190
return true;
191
#else
192
struct sched_param sched;
193
int policy;
194
int pri_policy;
195
pthread_t thread = pthread_self();
196
const char *policyhint = SDL_GetHint(SDL_HINT_THREAD_PRIORITY_POLICY);
197
const bool timecritical_realtime_hint = SDL_GetHintBoolean(SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL, false);
198
199
if (pthread_getschedparam(thread, &policy, &sched) != 0) {
200
return SDL_SetError("pthread_getschedparam() failed");
201
}
202
203
/* Higher priority levels may require changing the pthread scheduler policy
204
* for the thread. SDL will make such changes by default but there is
205
* also a hint allowing that behavior to be overridden. */
206
switch (priority) {
207
case SDL_THREAD_PRIORITY_LOW:
208
case SDL_THREAD_PRIORITY_NORMAL:
209
pri_policy = SCHED_OTHER;
210
break;
211
case SDL_THREAD_PRIORITY_HIGH:
212
case SDL_THREAD_PRIORITY_TIME_CRITICAL:
213
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
214
// Apple requires SCHED_RR for high priority threads
215
pri_policy = SCHED_RR;
216
break;
217
#else
218
pri_policy = SCHED_OTHER;
219
break;
220
#endif
221
default:
222
pri_policy = policy;
223
break;
224
}
225
226
if (timecritical_realtime_hint && priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
227
pri_policy = SCHED_RR;
228
}
229
230
if (policyhint) {
231
if (SDL_strcmp(policyhint, "current") == 0) {
232
// Leave current thread scheduler policy unchanged
233
} else if (SDL_strcmp(policyhint, "other") == 0) {
234
policy = SCHED_OTHER;
235
} else if (SDL_strcmp(policyhint, "rr") == 0) {
236
policy = SCHED_RR;
237
} else if (SDL_strcmp(policyhint, "fifo") == 0) {
238
policy = SCHED_FIFO;
239
} else {
240
policy = pri_policy;
241
}
242
} else {
243
policy = pri_policy;
244
}
245
246
#ifdef SDL_PLATFORM_LINUX
247
{
248
pid_t linuxTid = syscall(SYS_gettid);
249
return SDL_SetLinuxThreadPriorityAndPolicy(linuxTid, priority, policy);
250
}
251
#else
252
if (priority == SDL_THREAD_PRIORITY_LOW) {
253
sched.sched_priority = sched_get_priority_min(policy);
254
} else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
255
sched.sched_priority = sched_get_priority_max(policy);
256
} else {
257
int min_priority = sched_get_priority_min(policy);
258
int max_priority = sched_get_priority_max(policy);
259
260
#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
261
if (min_priority == 15 && max_priority == 47) {
262
// Apple has a specific set of thread priorities
263
if (priority == SDL_THREAD_PRIORITY_HIGH) {
264
sched.sched_priority = 45;
265
} else {
266
sched.sched_priority = 37;
267
}
268
} else
269
#endif // SDL_PLATFORM_MACOS || SDL_PLATFORM_IOS || SDL_PLATFORM_TVOS
270
{
271
sched.sched_priority = (min_priority + (max_priority - min_priority) / 2);
272
if (priority == SDL_THREAD_PRIORITY_HIGH) {
273
sched.sched_priority += ((max_priority - min_priority) / 4);
274
}
275
}
276
}
277
if (pthread_setschedparam(thread, policy, &sched) != 0) {
278
return SDL_SetError("pthread_setschedparam() failed");
279
}
280
return true;
281
#endif // linux
282
#endif // #if SDL_PLATFORM_RISCOS
283
}
284
285
void SDL_SYS_WaitThread(SDL_Thread *thread)
286
{
287
pthread_join(thread->handle, 0);
288
}
289
290
void SDL_SYS_DetachThread(SDL_Thread *thread)
291
{
292
pthread_detach(thread->handle);
293
}
294
295