src/thread/windows/SDL_systhread.c
author Manuel Alfayate Corchete
Thu, 22 Oct 2020 19:51:57 +0200
changeset 14191 7bb6793cd70f
parent 13677 498a7f27758e
permissions -rw-r--r--
kmsdrm: Add comment about KMSDRM_VideoQuit() changes.
     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: */