SDL_systhread.c (8480B)
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; 81 pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread) thread->endfunc; 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 103 SDL_SYS_CreateThread(SDL_Thread * thread, 104 pfnSDL_CurrentBeginThread pfnBeginThread, 105 pfnSDL_CurrentEndThread pfnEndThread) 106 { 107 #elif defined(__CYGWIN__) || defined(__WINRT__) 108 int 109 SDL_SYS_CreateThread(SDL_Thread * thread) 110 { 111 pfnSDL_CurrentBeginThread pfnBeginThread = NULL; 112 pfnSDL_CurrentEndThread pfnEndThread = NULL; 113 #else 114 int 115 SDL_SYS_CreateThread(SDL_Thread * thread) 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. */ 189 if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, SDL_TRUE)) { 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 206 SDL_threadID 207 SDL_ThreadID(void) 208 { 209 return ((SDL_threadID) GetCurrentThreadId()); 210 } 211 212 int 213 SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) 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 233 SDL_SYS_WaitThread(SDL_Thread * thread) 234 { 235 WaitForSingleObjectEx(thread->handle, INFINITE, FALSE); 236 CloseHandle(thread->handle); 237 } 238 239 void 240 SDL_SYS_DetachThread(SDL_Thread * thread) 241 { 242 CloseHandle(thread->handle); 243 } 244 245 #endif /* SDL_THREAD_WINDOWS */ 246 247 /* vi: set ts=4 sw=4 expandtab: */