SDL 2.0
SDL_systhread.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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#if SDL_THREAD_WINDOWS
24
25/* Win32 thread management routines for SDL */
26
27#include "SDL_hints.h"
28#include "SDL_thread.h"
29#include "../SDL_thread_c.h"
30#include "../SDL_systhread.h"
31#include "SDL_systhread_c.h"
32
33#ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD
34/* We'll use the C library from this DLL */
35#include <process.h>
36
37#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
38#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
39#endif
40
41/* Cygwin gcc-3 ... MingW64 (even with a i386 host) does this like MSVC. */
42#if (defined(__MINGW32__) && (__GNUC__ < 4))
43typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned,
44 unsigned (__stdcall *func)(void *), void *arg,
45 unsigned, unsigned *threadID);
46typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code);
47
48#elif defined(__WATCOMC__)
49/* This is for Watcom targets except OS2 */
50#if __WATCOMC__ < 1240
51#define __watcall
52#endif
53typedef unsigned long (__watcall * pfnSDL_CurrentBeginThread) (void *,
54 unsigned,
55 unsigned
56 (__stdcall *
57 func) (void
58 *),
59 void *arg,
60 unsigned,
61 unsigned
62 *threadID);
63typedef void (__watcall * pfnSDL_CurrentEndThread) (unsigned code);
64
65#else
66typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
67 unsigned (__stdcall *
68 func) (void
69 *),
70 void *arg, unsigned,
71 unsigned *threadID);
72typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
73#endif
74#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */
75
76
77typedef struct ThreadStartParms
78{
79 void *args;
80 pfnSDL_CurrentEndThread pfnCurrentEndThread;
81} tThreadStartParms, *pThreadStartParms;
82
83static DWORD
84RunThread(void *data)
85{
86 pThreadStartParms pThreadParms = (pThreadStartParms) data;
87 pfnSDL_CurrentEndThread pfnEndThread = pThreadParms->pfnCurrentEndThread;
88 void *args = pThreadParms->args;
89 SDL_free(pThreadParms);
90 SDL_RunThread(args);
91 if (pfnEndThread != NULL)
92 pfnEndThread(0);
93 return (0);
94}
95
96static DWORD WINAPI
97RunThreadViaCreateThread(LPVOID data)
98{
99 return RunThread(data);
100}
101
102static unsigned __stdcall
103RunThreadViaBeginThreadEx(void *data)
104{
105 return (unsigned) RunThread(data);
106}
107
108#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
109int
110SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
111 pfnSDL_CurrentBeginThread pfnBeginThread,
112 pfnSDL_CurrentEndThread pfnEndThread)
113{
114#elif defined(__CYGWIN__) || defined(__WINRT__)
115int
116SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
117{
118 pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
119 pfnSDL_CurrentEndThread pfnEndThread = NULL;
120#else
121int
122SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
123{
124 pfnSDL_CurrentBeginThread pfnBeginThread = (pfnSDL_CurrentBeginThread)_beginthreadex;
125 pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)_endthreadex;
126#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
127 pThreadStartParms pThreadParms =
128 (pThreadStartParms) SDL_malloc(sizeof(tThreadStartParms));
129 const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0;
130 if (!pThreadParms) {
131 return SDL_OutOfMemory();
132 }
133 /* Save the function which we will have to call to clear the RTL of calling app! */
134 pThreadParms->pfnCurrentEndThread = pfnEndThread;
135 /* Also save the real parameters we have to pass to thread function */
136 pThreadParms->args = args;
137
138 /* thread->stacksize == 0 means "system default", same as win32 expects */
139 if (pfnBeginThread) {
140 unsigned threadid = 0;
141 thread->handle = (SYS_ThreadHandle)
142 ((size_t) pfnBeginThread(NULL, (unsigned int) thread->stacksize,
143 RunThreadViaBeginThreadEx,
144 pThreadParms, flags, &threadid));
145 } else {
146 DWORD threadid = 0;
147 thread->handle = CreateThread(NULL, thread->stacksize,
148 RunThreadViaCreateThread,
149 pThreadParms, flags, &threadid);
150 }
151 if (thread->handle == NULL) {
152 return SDL_SetError("Not enough resources to create thread");
153 }
154 return 0;
155}
156
157#pragma pack(push,8)
158typedef struct tagTHREADNAME_INFO
159{
160 DWORD dwType; /* must be 0x1000 */
161 LPCSTR szName; /* pointer to name (in user addr space) */
162 DWORD dwThreadID; /* thread ID (-1=caller thread) */
163 DWORD dwFlags; /* reserved for future use, must be zero */
164} THREADNAME_INFO;
165#pragma pack(pop)
166
167
168typedef HRESULT (WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR);
169
170void
171SDL_SYS_SetupThread(const char *name)
172{
173 if (name != NULL) {
174 #ifndef __WINRT__ /* !!! FIXME: There's no LoadLibrary() in WinRT; don't know if SetThreadDescription is available there at all at the moment. */
175 static pfnSetThreadDescription pSetThreadDescription = NULL;
176 static HMODULE kernel32 = 0;
177
178 if (!kernel32) {
179 kernel32 = LoadLibraryW(L"kernel32.dll");
180 if (kernel32) {
181 pSetThreadDescription = (pfnSetThreadDescription) GetProcAddress(kernel32, "SetThreadDescription");
182 }
183 }
184
185 if (pSetThreadDescription != NULL) {
186 WCHAR *strw = WIN_UTF8ToString(name);
187 if (strw) {
188 pSetThreadDescription(GetCurrentThread(), strw);
189 SDL_free(strw);
190 }
191 }
192 #endif
193
194 /* Presumably some version of Visual Studio will understand SetThreadDescription(),
195 but we still need to deal with older OSes and debuggers. Set it with the arcane
196 exception magic, too. */
197
198 if (IsDebuggerPresent()) {
199 THREADNAME_INFO inf;
200
201 /* C# and friends will try to catch this Exception, let's avoid it. */
203 return;
204 }
205
206 /* This magic tells the debugger to name a thread if it's listening. */
207 SDL_zero(inf);
208 inf.dwType = 0x1000;
209 inf.szName = name;
210 inf.dwThreadID = (DWORD) -1;
211 inf.dwFlags = 0;
212
213 /* The debugger catches this, renames the thread, continues on. */
214 RaiseException(0x406D1388, 0, sizeof(inf) / sizeof(ULONG), (const ULONG_PTR*) &inf);
215 }
216 }
217}
218
220SDL_ThreadID(void)
221{
222 return ((SDL_threadID) GetCurrentThreadId());
223}
224
225int
227{
228 int value;
229
230 if (priority == SDL_THREAD_PRIORITY_LOW) {
231 value = THREAD_PRIORITY_LOWEST;
232 } else if (priority == SDL_THREAD_PRIORITY_HIGH) {
233 value = THREAD_PRIORITY_HIGHEST;
234 } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
235 value = THREAD_PRIORITY_TIME_CRITICAL;
236 } else {
237 value = THREAD_PRIORITY_NORMAL;
238 }
239 if (!SetThreadPriority(GetCurrentThread(), value)) {
240 return WIN_SetError("SetThreadPriority()");
241 }
242 return 0;
243}
244
245void
247{
248 WaitForSingleObjectEx(thread->handle, INFINITE, FALSE);
249 CloseHandle(thread->handle);
250}
251
252void
254{
255 CloseHandle(thread->handle);
256}
257
258#endif /* SDL_THREAD_WINDOWS */
259
260/* vi: set ts=4 sw=4 expandtab: */
unsigned int uintptr_t
#define SDL_SetError
#define SDL_malloc
#define SDL_free
#define SDL_GetHintBoolean
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING
Tell SDL not to name threads on Windows with the 0x406D1388 Exception. The 0x406D1388 Exception is a ...
Definition: SDL_hints.h:967
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLenum func
GLuint const GLchar * name
GLbitfield flags
GLsizei const GLfloat * value
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
@ SDL_TRUE
Definition: SDL_stdinc.h:164
void SDL_RunThread(void *data)
Definition: SDL_thread.c:265
unsigned long SDL_threadID
Definition: SDL_thread.h:49
SDL_ThreadPriority
Definition: SDL_thread.h:59
@ SDL_THREAD_PRIORITY_TIME_CRITICAL
Definition: SDL_thread.h:63
@ SDL_THREAD_PRIORITY_LOW
Definition: SDL_thread.h:60
@ SDL_THREAD_PRIORITY_HIGH
Definition: SDL_thread.h:62
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
int WIN_SetError(const char *prefix)
#define NULL
Definition: begin_code.h:167
#define FALSE
Definition: edid-parse.c:34
void SDL_SYS_SetupThread(const char *name)
Definition: SDL_systhread.c:42
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
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
Definition: SDL_systhread.c:35
int SYS_ThreadHandle
static void * RunThread(void *data)
Definition: SDL_systhread.c:74
SYS_ThreadHandle handle
Definition: SDL_thread_c.h:57
size_t stacksize
Definition: SDL_thread_c.h:62