Atlas - SDL_systimer.c
Home / ext / SDL / src / timer / windows Lines: 1 | Size: 5468 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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#ifdef SDL_TIMER_WINDOWS 24 25#include "../../core/windows/SDL_windows.h" 26 27Uint64 SDL_GetPerformanceCounter(void) 28{ 29 LARGE_INTEGER counter; 30 const BOOL rc = QueryPerformanceCounter(&counter); 31 SDL_assert(rc != 0); // this should _never_ fail if you're on XP or later. 32 return (Uint64)counter.QuadPart; 33} 34 35Uint64 SDL_GetPerformanceFrequency(void) 36{ 37 LARGE_INTEGER frequency; 38 const BOOL rc = QueryPerformanceFrequency(&frequency); 39 SDL_assert(rc != 0); // this should _never_ fail if you're on XP or later. 40 return (Uint64)frequency.QuadPart; 41} 42 43static void SDL_CleanupWaitableHandle(void *handle) 44{ 45 CloseHandle(handle); 46} 47 48static HANDLE SDL_GetWaitableEvent(void) 49{ 50 static SDL_TLSID TLS_event_handle; 51 HANDLE event; 52 53 event = SDL_GetTLS(&TLS_event_handle); 54 if (!event) { 55 event = CreateEvent(NULL, FALSE, FALSE, NULL); 56 if (event) { 57 SDL_SetTLS(&TLS_event_handle, event, SDL_CleanupWaitableHandle); 58 } 59 } 60 return event; 61} 62 63/* CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag was added in Windows 10 version 1803. */ 64#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 65#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x2 66#endif 67 68typedef HANDLE (WINAPI *pfnCreateWaitableTimerExW)(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess); 69static pfnCreateWaitableTimerExW pCreateWaitableTimerExW; 70 71#if WINVER < _WIN32_WINNT_WIN7 72typedef struct _REASON_CONTEXT REASON_CONTEXT; 73typedef REASON_CONTEXT * PREASON_CONTEXT; 74#endif 75typedef BOOL (WINAPI *pfnSetWaitableTimerEx)(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay); 76static pfnSetWaitableTimerEx pSetWaitableTimerEx; 77 78typedef HANDLE (WINAPI *pfnCreateWaitableTimerW)(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName); 79static pfnCreateWaitableTimerW pCreateWaitableTimerW; 80 81typedef BOOL (WINAPI *pfnSetWaitableTimer)(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume); 82static pfnSetWaitableTimer pSetWaitableTimer; 83 84static HANDLE SDL_GetWaitableTimer(void) 85{ 86 static SDL_TLSID TLS_timer_handle; 87 HANDLE timer; 88 static bool initialized; 89 90 if (!initialized) { 91 HMODULE module = GetModuleHandle(TEXT("kernel32.dll")); 92 if (module) { 93 pCreateWaitableTimerExW = (pfnCreateWaitableTimerExW)GetProcAddress(module, "CreateWaitableTimerExW"); // Windows 7 and up 94 if (!pCreateWaitableTimerExW) { 95 pCreateWaitableTimerW = (pfnCreateWaitableTimerW)GetProcAddress(module, "CreateWaitableTimerW"); 96 } 97 pSetWaitableTimerEx = (pfnSetWaitableTimerEx)GetProcAddress(module, "SetWaitableTimerEx"); // Windows Vista and up 98 if (!pSetWaitableTimerEx) { 99 pSetWaitableTimer = (pfnSetWaitableTimer)GetProcAddress(module, "SetWaitableTimer"); 100 } 101 initialized = 102 (pCreateWaitableTimerExW || pCreateWaitableTimerW) && 103 (pSetWaitableTimerEx || pSetWaitableTimer); 104 } 105 if (!initialized) { 106 return NULL; 107 } 108 } 109 110 timer = SDL_GetTLS(&TLS_timer_handle); 111 if (!timer) { 112 if (pCreateWaitableTimerExW) { 113 timer = pCreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); 114 } else { 115 timer = pCreateWaitableTimerW(NULL, TRUE, NULL); 116 } 117 if (timer) { 118 SDL_SetTLS(&TLS_timer_handle, timer, SDL_CleanupWaitableHandle); 119 } 120 } 121 return timer; 122} 123 124void SDL_SYS_DelayNS(Uint64 ns) 125{ 126 HANDLE timer = SDL_GetWaitableTimer(); 127 if (timer) { 128 LARGE_INTEGER due_time; 129 due_time.QuadPart = -((LONGLONG)ns / 100); 130 if ((pSetWaitableTimerEx && pSetWaitableTimerEx(timer, &due_time, 0, NULL, NULL, NULL, 0)) || pSetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) { 131 WaitForSingleObject(timer, INFINITE); 132 } 133 return; 134 } 135 136 const Uint64 max_delay = 0xffffffffLL * SDL_NS_PER_MS; 137 if (ns > max_delay) { 138 ns = max_delay; 139 } 140 const DWORD delay = (DWORD)SDL_NS_TO_MS(ns); 141 142 HANDLE event = SDL_GetWaitableEvent(); 143 if (event) { 144 WaitForSingleObjectEx(event, delay, FALSE); 145 return; 146 } 147 148 Sleep(delay); 149} 150 151#endif // SDL_TIMER_WINDOWS 152[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.