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@libsdl.org 21*/ 22#include "SDL_config.h" 23 24/* Win32 thread management routines for SDL */ 25 26#define WIN32_LEAN_AND_MEAN 1 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 44typedef unsigned long (__watcall *pfnSDL_CurrentBeginThread) (void *, unsigned, 45 unsigned (__stdcall *func)(void *), void *arg, 46 unsigned, unsigned *threadID); 47typedef void (__watcall *pfnSDL_CurrentEndThread)(unsigned code); 48#elif (defined(__MINGW32__) && (__GNUC__ < 4)) 49typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned, 50 unsigned (__stdcall *func)(void *), void *arg, 51 unsigned, unsigned *threadID); 52typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code); 53#else 54typedef uintptr_t (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned, 55 unsigned (__stdcall *func)(void *), void *arg, 56 unsigned, unsigned *threadID); 57typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code); 58#endif 59#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */ 60 61 62typedef struct ThreadStartParms 63{ 64 void *args; 65 pfnSDL_CurrentEndThread pfnCurrentEndThread; 66} tThreadStartParms, *pThreadStartParms; 67 68static 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 88static DWORD WINAPI RunThreadViaCreateThread(LPVOID data) 89{ 90 return RunThread(data); 91} 92 93static unsigned __stdcall RunThreadViaBeginThreadEx(void *data) 94{ 95 return (unsigned) RunThread(data); 96} 97 98#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD 99int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread) 100{ 101#else 102int 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 139void SDL_SYS_SetupThread(void) 140{ 141 return; 142} 143 144Uint32 SDL_ThreadID(void) 145{ 146 return((Uint32)GetCurrentThreadId()); 147} 148 149void 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 */ 159void SDL_SYS_KillThread(SDL_Thread *thread) 160{ 161 TerminateThread(thread->handle, FALSE); 162} 163