1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* Win32 thread management routines for SDL */ 25 26 #define WIN32_LEAN_AND_MEAN 27 #include <windows.h> 28 29 #include "SDL_thread.h" 30 #include "../SDL_thread_c.h" 31 #include "../SDL_systhread.h" 32 33 #ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD 34 #ifndef _WIN32_WCE 35 /* We'll use the C library from this DLL */ 36 #include <process.h> 37 #endif 38 39 #if defined(__WATCOMC__) 40 /* This is for Watcom targets except OS2 */ 41 #if __WATCOMC__ < 1240 42 #define __watcall 43 #endif 44 typedef unsigned long (__watcall *pfnSDL_CurrentBeginThread) (void *, unsigned, 45 unsigned (__stdcall *func)(void *), void *arg, 46 unsigned, unsigned *threadID); 47 typedef void (__watcall *pfnSDL_CurrentEndThread)(unsigned code); 48 #elif (defined(__MINGW32__) && (__GNUC__ < 4)) 49 typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned, 50 unsigned (__stdcall *func)(void *), void *arg, 51 unsigned, unsigned *threadID); 52 typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code); 53 #else 54 typedef uintptr_t (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned, 55 unsigned (__stdcall *func)(void *), void *arg, 56 unsigned, unsigned *threadID); 57 typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code); 58 #endif 59 #endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */ 60 61 62 typedef struct ThreadStartParms 63 { 64 void *args; 65 pfnSDL_CurrentEndThread pfnCurrentEndThread; 66 } tThreadStartParms, *pThreadStartParms; 67 68 static DWORD RunThread(void *data) 69 { 70 pThreadStartParms pThreadParms = (pThreadStartParms)data; 71 pfnSDL_CurrentEndThread pfnCurrentEndThread = NULL; 72 73 // Call the thread function! 74 SDL_RunThread(pThreadParms->args); 75 76 // Get the current endthread we have to use! 77 if (pThreadParms) 78 { 79 pfnCurrentEndThread = pThreadParms->pfnCurrentEndThread; 80 SDL_free(pThreadParms); 81 } 82 // Call endthread! 83 if (pfnCurrentEndThread) 84 (*pfnCurrentEndThread)(0); 85 return(0); 86 } 87 88 static DWORD WINAPI RunThreadViaCreateThread(LPVOID data) 89 { 90 return RunThread(data); 91 } 92 93 static unsigned __stdcall RunThreadViaBeginThreadEx(void *data) 94 { 95 return (unsigned) RunThread(data); 96 } 97 98 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD 99 int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread) 100 { 101 #else 102 int SDL_SYS_CreateThread(SDL_Thread *thread, void *args) 103 { 104 #ifdef _WIN32_WCE 105 pfnSDL_CurrentBeginThread pfnBeginThread = NULL; 106 pfnSDL_CurrentEndThread pfnEndThread = NULL; 107 #else 108 pfnSDL_CurrentBeginThread pfnBeginThread = _beginthreadex; 109 pfnSDL_CurrentEndThread pfnEndThread = _endthreadex; 110 #endif 111 #endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */ 112 pThreadStartParms pThreadParms = (pThreadStartParms)SDL_malloc(sizeof(tThreadStartParms)); 113 if (!pThreadParms) { 114 SDL_OutOfMemory(); 115 return(-1); 116 } 117 118 // Save the function which we will have to call to clear the RTL of calling app! 119 pThreadParms->pfnCurrentEndThread = pfnEndThread; 120 // Also save the real parameters we have to pass to thread function 121 pThreadParms->args = args; 122 123 if (pfnBeginThread) { 124 unsigned threadid = 0; 125 thread->handle = (SYS_ThreadHandle) 126 ((size_t) pfnBeginThread(NULL, 0, RunThreadViaBeginThreadEx, 127 pThreadParms, 0, &threadid)); 128 } else { 129 DWORD threadid = 0; 130 thread->handle = CreateThread(NULL, 0, RunThreadViaCreateThread, pThreadParms, 0, &threadid); 131 } 132 if (thread->handle == NULL) { 133 SDL_SetError("Not enough resources to create thread"); 134 return(-1); 135 } 136 return(0); 137 } 138 139 void SDL_SYS_SetupThread(void) 140 { 141 return; 142 } 143 144 Uint32 SDL_ThreadID(void) 145 { 146 return((Uint32)GetCurrentThreadId()); 147 } 148 149 void SDL_SYS_WaitThread(SDL_Thread *thread) 150 { 151 WaitForSingleObject(thread->handle, INFINITE); 152 CloseHandle(thread->handle); 153 } 154 155 /* WARNING: This function is really a last resort. 156 * Threads should be signaled and then exit by themselves. 157 * TerminateThread() doesn't perform stack and DLL cleanup. 158 */ 159 void SDL_SYS_KillThread(SDL_Thread *thread) 160 { 161 TerminateThread(thread->handle, FALSE); 162 } 163