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 static DWORD
78 RunThread(void *data)
79 {
80  SDL_Thread *thread = (SDL_Thread *) data;
82  SDL_RunThread(thread);
83  if (pfnEndThread != NULL) {
84  pfnEndThread(0);
85  }
86  return 0;
87 }
88 
89 static DWORD WINAPI
90 RunThreadViaCreateThread(LPVOID data)
91 {
92  return RunThread(data);
93 }
94 
95 static unsigned __stdcall
96 RunThreadViaBeginThreadEx(void *data)
97 {
98  return (unsigned) RunThread(data);
99 }
100 
101 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
102 int
104  pfnSDL_CurrentBeginThread pfnBeginThread,
105  pfnSDL_CurrentEndThread pfnEndThread)
106 {
107 #elif defined(__CYGWIN__) || defined(__WINRT__)
108 int
110 {
111  pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
112  pfnSDL_CurrentEndThread pfnEndThread = NULL;
113 #else
114 int
116 {
117  pfnSDL_CurrentBeginThread pfnBeginThread = (pfnSDL_CurrentBeginThread)_beginthreadex;
118  pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)_endthreadex;
119 #endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
120  const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0;
121 
122  /* Save the function which we will have to call to clear the RTL of calling app! */
123  thread->endfunc = pfnEndThread;
124 
125  /* thread->stacksize == 0 means "system default", same as win32 expects */
126  if (pfnBeginThread) {
127  unsigned threadid = 0;
128  thread->handle = (SYS_ThreadHandle)
129  ((size_t) pfnBeginThread(NULL, (unsigned int) thread->stacksize,
130  RunThreadViaBeginThreadEx,
131  thread, flags, &threadid));
132  } else {
133  DWORD threadid = 0;
134  thread->handle = CreateThread(NULL, thread->stacksize,
135  RunThreadViaCreateThread,
136  thread, flags, &threadid);
137  }
138  if (thread->handle == NULL) {
139  return SDL_SetError("Not enough resources to create thread");
140  }
141  return 0;
142 }
143 
144 #pragma pack(push,8)
145 typedef struct tagTHREADNAME_INFO
146 {
147  DWORD dwType; /* must be 0x1000 */
148  LPCSTR szName; /* pointer to name (in user addr space) */
149  DWORD dwThreadID; /* thread ID (-1=caller thread) */
150  DWORD dwFlags; /* reserved for future use, must be zero */
151 } THREADNAME_INFO;
152 #pragma pack(pop)
153 
154 
155 typedef HRESULT (WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR);
156 
157 void
158 SDL_SYS_SetupThread(const char *name)
159 {
160  if (name != NULL) {
161  #ifndef __WINRT__ /* !!! FIXME: There's no LoadLibrary() in WinRT; don't know if SetThreadDescription is available there at all at the moment. */
162  static pfnSetThreadDescription pSetThreadDescription = NULL;
163  static HMODULE kernel32 = 0;
164 
165  if (!kernel32) {
166  kernel32 = LoadLibraryW(L"kernel32.dll");
167  if (kernel32) {
168  pSetThreadDescription = (pfnSetThreadDescription) GetProcAddress(kernel32, "SetThreadDescription");
169  }
170  }
171 
172  if (pSetThreadDescription != NULL) {
173  WCHAR *strw = WIN_UTF8ToString(name);
174  if (strw) {
175  pSetThreadDescription(GetCurrentThread(), strw);
176  SDL_free(strw);
177  }
178  }
179  #endif
180 
181  /* Presumably some version of Visual Studio will understand SetThreadDescription(),
182  but we still need to deal with older OSes and debuggers. Set it with the arcane
183  exception magic, too. */
184 
185  if (IsDebuggerPresent()) {
186  THREADNAME_INFO inf;
187 
188  /* C# and friends will try to catch this Exception, let's avoid it. */
190  return;
191  }
192 
193  /* This magic tells the debugger to name a thread if it's listening. */
194  SDL_zero(inf);
195  inf.dwType = 0x1000;
196  inf.szName = name;
197  inf.dwThreadID = (DWORD) -1;
198  inf.dwFlags = 0;
199 
200  /* The debugger catches this, renames the thread, continues on. */
201  RaiseException(0x406D1388, 0, sizeof(inf) / sizeof(ULONG), (const ULONG_PTR*) &inf);
202  }
203  }
204 }
205 
207 SDL_ThreadID(void)
208 {
209  return ((SDL_threadID) GetCurrentThreadId());
210 }
211 
212 int
214 {
215  int value;
216 
217  if (priority == SDL_THREAD_PRIORITY_LOW) {
218  value = THREAD_PRIORITY_LOWEST;
219  } else if (priority == SDL_THREAD_PRIORITY_HIGH) {
220  value = THREAD_PRIORITY_HIGHEST;
221  } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
222  value = THREAD_PRIORITY_TIME_CRITICAL;
223  } else {
224  value = THREAD_PRIORITY_NORMAL;
225  }
226  if (!SetThreadPriority(GetCurrentThread(), value)) {
227  return WIN_SetError("SetThreadPriority()");
228  }
229  return 0;
230 }
231 
232 void
234 {
235  WaitForSingleObjectEx(thread->handle, INFINITE, FALSE);
236  CloseHandle(thread->handle);
237 }
238 
239 void
241 {
242  CloseHandle(thread->handle);
243 }
244 
245 #endif /* SDL_THREAD_WINDOWS */
246 
247 /* vi: set ts=4 sw=4 expandtab: */
unsigned int uintptr_t
#define SDL_SetError
#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_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:1182
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:426
@ SDL_TRUE
Definition: SDL_stdinc.h:170
void SDL_RunThread(SDL_Thread *thread)
Definition: SDL_thread.c:261
void(__cdecl * pfnSDL_CurrentEndThread)(unsigned code)
Definition: SDL_thread.h:104
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
uintptr_t(__cdecl * pfnSDL_CurrentBeginThread)(void *, unsigned, unsigned(__stdcall *func)(void *), void *, unsigned, unsigned *)
Definition: SDL_thread.h:102
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
int WIN_SetError(const char *prefix)
#define NULL
Definition: begin_code.h:163
#define FALSE
Definition: edid-parse.c:34
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
int SYS_ThreadHandle
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
void * endfunc
Definition: SDL_thread_c.h:68
static HMODULE kernel32
Definition: SDL_syslocale.c:32