Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/thread/windows/SDL_systhread.c
9905 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
#ifdef SDL_THREAD_WINDOWS
24
25
// Win32 thread management routines for SDL
26
27
#include "../SDL_thread_c.h"
28
#include "../SDL_systhread.h"
29
#include "SDL_systhread_c.h"
30
31
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
32
#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
33
#endif
34
35
#define SDL_DEBUGGER_NAME_EXCEPTION_CODE 0x406D1388
36
37
typedef void (__cdecl * SDL_EndThreadExCallback) (unsigned retval);
38
typedef uintptr_t (__cdecl * SDL_BeginThreadExCallback)
39
(void *security, unsigned stacksize, unsigned (__stdcall *startaddr)(void *),
40
void * arglist, unsigned initflag, unsigned *threadaddr);
41
42
static DWORD RunThread(void *data)
43
{
44
SDL_Thread *thread = (SDL_Thread *)data;
45
SDL_EndThreadExCallback pfnEndThread = (SDL_EndThreadExCallback)thread->endfunc;
46
SDL_RunThread(thread);
47
if (pfnEndThread) {
48
pfnEndThread(0);
49
}
50
return 0;
51
}
52
53
static DWORD WINAPI MINGW32_FORCEALIGN RunThreadViaCreateThread(LPVOID data)
54
{
55
return RunThread(data);
56
}
57
58
static unsigned __stdcall MINGW32_FORCEALIGN RunThreadViaBeginThreadEx(void *data)
59
{
60
return (unsigned)RunThread(data);
61
}
62
63
bool SDL_SYS_CreateThread(SDL_Thread *thread,
64
SDL_FunctionPointer vpfnBeginThread,
65
SDL_FunctionPointer vpfnEndThread)
66
{
67
SDL_BeginThreadExCallback pfnBeginThread = (SDL_BeginThreadExCallback) vpfnBeginThread;
68
69
const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0;
70
71
// Save the function which we will have to call to clear the RTL of calling app!
72
thread->endfunc = vpfnEndThread;
73
74
// thread->stacksize == 0 means "system default", same as win32 expects
75
if (pfnBeginThread) {
76
unsigned threadid = 0;
77
thread->handle = (SYS_ThreadHandle)((size_t)pfnBeginThread(NULL, (unsigned int)thread->stacksize,
78
RunThreadViaBeginThreadEx,
79
thread, flags, &threadid));
80
} else {
81
DWORD threadid = 0;
82
thread->handle = CreateThread(NULL, thread->stacksize,
83
RunThreadViaCreateThread,
84
thread, flags, &threadid);
85
}
86
if (!thread->handle) {
87
return SDL_SetError("Not enough resources to create thread");
88
}
89
return true;
90
}
91
92
#pragma pack(push, 8)
93
typedef struct tagTHREADNAME_INFO
94
{
95
DWORD dwType; // must be 0x1000
96
LPCSTR szName; // pointer to name (in user addr space)
97
DWORD dwThreadID; // thread ID (-1=caller thread)
98
DWORD dwFlags; // reserved for future use, must be zero
99
} THREADNAME_INFO;
100
#pragma pack(pop)
101
102
static LONG NTAPI EmptyVectoredExceptionHandler(EXCEPTION_POINTERS *info)
103
{
104
if (info != NULL && info->ExceptionRecord != NULL && info->ExceptionRecord->ExceptionCode == SDL_DEBUGGER_NAME_EXCEPTION_CODE) {
105
return EXCEPTION_CONTINUE_EXECUTION;
106
} else {
107
return EXCEPTION_CONTINUE_SEARCH;
108
}
109
}
110
111
typedef HRESULT(WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR);
112
113
void SDL_SYS_SetupThread(const char *name)
114
{
115
if (name) {
116
PVOID exceptionHandlerHandle;
117
static pfnSetThreadDescription pSetThreadDescription = NULL;
118
static HMODULE kernel32 = NULL;
119
120
if (!kernel32) {
121
kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
122
if (kernel32) {
123
pSetThreadDescription = (pfnSetThreadDescription)GetProcAddress(kernel32, "SetThreadDescription");
124
}
125
if (!kernel32 || !pSetThreadDescription) {
126
HMODULE kernelBase = GetModuleHandle(TEXT("KernelBase.dll"));
127
if (kernelBase) {
128
pSetThreadDescription = (pfnSetThreadDescription)GetProcAddress(kernelBase, "SetThreadDescription");
129
}
130
}
131
}
132
133
if (pSetThreadDescription) {
134
WCHAR *strw = WIN_UTF8ToStringW(name);
135
if (strw) {
136
pSetThreadDescription(GetCurrentThread(), strw);
137
SDL_free(strw);
138
}
139
}
140
141
/* Presumably some version of Visual Studio will understand SetThreadDescription(),
142
but we still need to deal with older OSes and debuggers. Set it with the arcane
143
exception magic, too. */
144
145
exceptionHandlerHandle = AddVectoredExceptionHandler(1, EmptyVectoredExceptionHandler);
146
if (exceptionHandlerHandle) {
147
THREADNAME_INFO inf;
148
// This magic tells the debugger to name a thread if it's listening.
149
SDL_zero(inf);
150
inf.dwType = 0x1000;
151
inf.szName = name;
152
inf.dwThreadID = (DWORD)-1;
153
inf.dwFlags = 0;
154
155
// The debugger catches this, renames the thread, continues on.
156
RaiseException(SDL_DEBUGGER_NAME_EXCEPTION_CODE, 0, sizeof(inf) / sizeof(ULONG_PTR), (const ULONG_PTR *)&inf);
157
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
158
}
159
}
160
}
161
162
SDL_ThreadID SDL_GetCurrentThreadID(void)
163
{
164
return (SDL_ThreadID)GetCurrentThreadId();
165
}
166
167
bool SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
168
{
169
int value;
170
171
if (priority == SDL_THREAD_PRIORITY_LOW) {
172
value = THREAD_PRIORITY_LOWEST;
173
} else if (priority == SDL_THREAD_PRIORITY_HIGH) {
174
value = THREAD_PRIORITY_HIGHEST;
175
} else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
176
value = THREAD_PRIORITY_TIME_CRITICAL;
177
} else {
178
value = THREAD_PRIORITY_NORMAL;
179
}
180
if (!SetThreadPriority(GetCurrentThread(), value)) {
181
return WIN_SetError("SetThreadPriority()");
182
}
183
return true;
184
}
185
186
void SDL_SYS_WaitThread(SDL_Thread *thread)
187
{
188
WaitForSingleObjectEx(thread->handle, INFINITE, FALSE);
189
CloseHandle(thread->handle);
190
}
191
192
void SDL_SYS_DetachThread(SDL_Thread *thread)
193
{
194
CloseHandle(thread->handle);
195
}
196
197
#endif // SDL_THREAD_WINDOWS
198
199