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 #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))
43 typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned,
44  unsigned (__stdcall *func)(void *), void *arg,
45  unsigned, unsigned *threadID);
46 typedef 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
53 typedef 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);
63 typedef void (__watcall * pfnSDL_CurrentEndThread) (unsigned code);
64 
65 #else
66 typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
67  unsigned (__stdcall *
68  func) (void
69  *),
70  void *arg, unsigned,
71  unsigned *threadID);
72 typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
73 #endif
74 #endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */
75 
76 
77 typedef struct ThreadStartParms
78 {
79  void *args;
80  pfnSDL_CurrentEndThread pfnCurrentEndThread;
81 } tThreadStartParms, *pThreadStartParms;
82 
83 static DWORD
84 RunThread(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 
96 static DWORD WINAPI
97 RunThreadViaCreateThread(LPVOID data)
98 {
99  return RunThread(data);
100 }
101 
102 static unsigned __stdcall
103 RunThreadViaBeginThreadEx(void *data)
104 {
105  return (unsigned) RunThread(data);
106 }
107 
108 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
109 int
110 SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
111  pfnSDL_CurrentBeginThread pfnBeginThread,
112  pfnSDL_CurrentEndThread pfnEndThread)
113 {
114 #elif defined(__CYGWIN__) || defined(__WINRT__)
115 int
116 SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
117 {
118  pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
119  pfnSDL_CurrentEndThread pfnEndThread = NULL;
120 #else
121 int
122 SDL_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)
158 typedef 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 
168 typedef HRESULT (WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR);
169 
170 void
171 SDL_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 
220 SDL_ThreadID(void)
221 {
222  return ((SDL_threadID) GetCurrentThreadId());
223 }
224 
225 int
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 
245 void
247 {
248  WaitForSingleObjectEx(thread->handle, INFINITE, FALSE);
249  CloseHandle(thread->handle);
250 }
251 
252 void
254 {
255  CloseHandle(thread->handle);
256 }
257 
258 #endif /* SDL_THREAD_WINDOWS */
259 
260 /* vi: set ts=4 sw=4 expandtab: */
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:418
pfnSDL_CurrentEndThread
void(__cdecl * pfnSDL_CurrentEndThread)(unsigned code)
Definition: SDL_thread.h:99
WIN_UTF8ToString
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
SDL_Thread::stacksize
size_t stacksize
Definition: SDL_thread_c.h:62
NULL
#define NULL
Definition: begin_code.h:167
SDL_RunThread
void SDL_RunThread(void *data)
Definition: SDL_thread.c:271
SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING
#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:1051
pfnSDL_CurrentBeginThread
uintptr_t(__cdecl * pfnSDL_CurrentBeginThread)(void *, unsigned, unsigned(__stdcall *func)(void *), void *, unsigned, unsigned *)
Definition: SDL_thread.h:97
SDL_THREAD_PRIORITY_TIME_CRITICAL
@ SDL_THREAD_PRIORITY_TIME_CRITICAL
Definition: SDL_thread.h:63
SDL_ThreadID
SDL_threadID SDL_ThreadID(void)
Definition: SDL_systhread.c:48
SDL_THREAD_PRIORITY_HIGH
@ SDL_THREAD_PRIORITY_HIGH
Definition: SDL_thread.h:62
SDL_SYS_SetupThread
void SDL_SYS_SetupThread(const char *name)
Definition: SDL_systhread.c:42
SDL_SYS_WaitThread
void SDL_SYS_WaitThread(SDL_Thread *thread)
Definition: SDL_systhread.c:60
SDL_Thread
Definition: SDL_thread_c.h:55
SDL_THREAD_PRIORITY_LOW
@ SDL_THREAD_PRIORITY_LOW
Definition: SDL_thread.h:60
SDL_SYS_CreateThread
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
Definition: SDL_systhread.c:35
func
GLenum func
Definition: SDL_opengl_glext.h:660
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
RunThread
static void * RunThread(void *data)
Definition: SDL_systhread.c:74
SDL_GetHintBoolean
#define SDL_GetHintBoolean
Definition: SDL_dynapi_overrides.h:608
SDL_thread.h
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
SDL_SYS_DetachThread
void SDL_SYS_DetachThread(SDL_Thread *thread)
Definition: SDL_systhread.c:66
SDL_SYS_SetThreadPriority
int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
Definition: SDL_systhread.c:54
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_threadID
unsigned long SDL_threadID
Definition: SDL_thread.h:49
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:701
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
WIN_SetError
int WIN_SetError(const char *prefix)
SDL_hints.h
SDL_Thread::handle
SYS_ThreadHandle handle
Definition: SDL_thread_c.h:57
SYS_ThreadHandle
int SYS_ThreadHandle
Definition: SDL_systhread_c.h:24
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
void
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
Definition: SDL_dynapi_procs.h:89
flags
GLbitfield flags
Definition: SDL_opengl_glext.h:1483
SDL_ThreadPriority
SDL_ThreadPriority
Definition: SDL_thread.h:59
FALSE
#define FALSE
Definition: edid-parse.c:34
uintptr_t
unsigned int uintptr_t
Definition: SDL_config_windows.h:70