SDL  2.0
SDL_systhread.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 {
235  value = THREAD_PRIORITY_NORMAL;
236  }
237  if (!SetThreadPriority(GetCurrentThread(), value)) {
238  return WIN_SetError("SetThreadPriority()");
239  }
240  return 0;
241 }
242 
243 void
245 {
246  WaitForSingleObjectEx(thread->handle, INFINITE, FALSE);
247  CloseHandle(thread->handle);
248 }
249 
250 void
252 {
253  CloseHandle(thread->handle);
254 }
255 
256 #endif /* SDL_THREAD_WINDOWS */
257 
258 /* vi: set ts=4 sw=4 expandtab: */
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
#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:835
static void * RunThread(void *data)
Definition: SDL_systhread.c:69
int SYS_ThreadHandle
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint const GLchar * name
#define SDL_GetHintBoolean
SDL_threadID SDL_ThreadID(void)
Definition: SDL_systhread.c:48
void SDL_SYS_WaitThread(SDL_Thread *thread)
Definition: SDL_systhread.c:60
#define SDL_free
int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
Definition: SDL_systhread.c:54
GLsizei const GLfloat * value
void SDL_SYS_DetachThread(SDL_Thread *thread)
Definition: SDL_systhread.c:66
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
unsigned int uintptr_t
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
int WIN_SetError(const char *prefix)
SYS_ThreadHandle handle
Definition: SDL_thread_c.h:57
#define SDL_SetError
GLbitfield flags
GLenum func
SDL_ThreadPriority
Definition: SDL_thread.h:59
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
void SDL_RunThread(void *data)
Definition: SDL_thread.c:265
void SDL_SYS_SetupThread(const char *name)
Definition: SDL_systhread.c:42
#define SDL_malloc
#define FALSE
Definition: edid-parse.c:34
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
Definition: SDL_systhread.c:35
size_t stacksize
Definition: SDL_thread_c.h:62
unsigned long SDL_threadID
Definition: SDL_thread.h:49