Some WinAPI functions were introduced in recent versions of Windows. It's not possible to detect if they're available at compile time, so they're dynamically detected.
The issue is that _WIN32_WINNT defaults to Win10 these days, so a default build of a toolchain won't work for older targets, which is why it was agreed to do the change to try to load this function at runtime. https://sourceforge.net/p/mingw-w64/mailman/message/47371359/, https://sourceforge.net/p/mingw-w64/mailman/message/49958237/ and https://sourceforge.net/p/mingw-w64/mailman/message/48131379/. Multiple workarounds are needed for MSVC to make this detection portable. 1. Missing constructor attribute in MSVC > The `constructor` attribute causes the function to be called before > entering `main()`. https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-constructor-function-attribute https://clang.llvm.org/docs/AttributeReference.html#constructor This feature is not supported by the MSVC compiler, and can be worked around by putting a function pointer to the constructor in the .CRT$XC? section of the executable. https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170#linker-features-for-initialization We chose the .CRT$XCT section, however the documentation warns: > The names .CRT$XCT and .CRT$XCV aren't used by either the compiler > or the CRT library right now, but there's no guarantee that they'll > remain unused in the future. And, your variables could still be > optimized away by the compiler. Consider the potential engineering, > maintenance, and portability issues before adopting this technique. 2. Missing typeof extension in MSVC As MSVC doesn't support the GCC __typeof__ extension, we explicit the type of the function pointer. Casting the result of GetProcAddress (a function pointer) to a (void *) (a data pointer) is allowed as an extension, mimics the POSIX dlsym function, and prevents compiler warnings. 3. Missing __atomic functions in MSVC MSVC doesn't support GCC __atomic functions. Finding whether GetSystemTimePreciseAsFileTime is present on the system can be done using a function tagged with the constructor attribute, avoiding the need of atomics to prevent races. 4. Gather the initialization bits into a single function Considering the amount of boilerplate code needed to instruct the linker on MSVC, gather the discovery of the WinAPI functions in a single winpthreads_init function. The WinAPI functions can be accessed through internal global function pointers. Signed-off-by: Antonin Décimo <anto...@tarides.com> --- mingw-w64-libraries/winpthreads/src/clock.c | 31 ++--------------- mingw-w64-libraries/winpthreads/src/misc.c | 38 ++++++++++++++++++--- mingw-w64-libraries/winpthreads/src/misc.h | 2 ++ 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/src/clock.c b/mingw-w64-libraries/winpthreads/src/clock.c index db8b34ea5..49db0f667 100644 --- a/mingw-w64-libraries/winpthreads/src/clock.c +++ b/mingw-w64-libraries/winpthreads/src/clock.c @@ -13,6 +13,7 @@ #endif #include "pthread.h" #include "pthread_time.h" +#include "misc.h" #define POW10_7 10000000 #define POW10_9 1000000000 @@ -31,32 +32,6 @@ static WINPTHREADS_INLINE int lc_set_errno(int result) return 0; } -typedef void (WINAPI * GetSystemTimeAsFileTime_t)(LPFILETIME); -static GetSystemTimeAsFileTime_t GetSystemTimeAsFileTime_p /* = 0 */; - -static GetSystemTimeAsFileTime_t try_load_GetSystemPreciseTimeAsFileTime(void) -{ - /* Use GetSystemTimePreciseAsFileTime() if available (Windows 8 or later) */ - HMODULE mod = GetModuleHandle("kernel32.dll"); - GetSystemTimeAsFileTime_t get_time = NULL; - if (mod) - get_time = (GetSystemTimeAsFileTime_t)(intptr_t)GetProcAddress(mod, - "GetSystemTimePreciseAsFileTime"); /* <1us precision on Windows 10 */ - if (get_time == NULL) - get_time = GetSystemTimeAsFileTime; /* >15ms precision on Windows 10 */ - __atomic_store_n(&GetSystemTimeAsFileTime_p, get_time, __ATOMIC_RELAXED); - return get_time; -} - -static WINPTHREADS_INLINE GetSystemTimeAsFileTime_t load_GetSystemTimeBestAsFileTime(void) -{ - GetSystemTimeAsFileTime_t get_time = - __atomic_load_n(&GetSystemTimeAsFileTime_p, __ATOMIC_RELAXED); - if (get_time == NULL) - get_time = try_load_GetSystemPreciseTimeAsFileTime(); - return get_time; -} - /** * Get the resolution of the specified clock clock_id and * stores it in the struct timespec pointed to by res. @@ -80,7 +55,7 @@ int clock_getres(clockid_t clock_id, struct timespec *res) { clockid_t id = clock_id; - if (id == CLOCK_REALTIME && load_GetSystemTimeBestAsFileTime() == GetSystemTimeAsFileTime) + if (id == CLOCK_REALTIME && GetSystemTimeBestAsFileTimeFuncPtr == GetSystemTimeAsFileTime) id = CLOCK_REALTIME_COARSE; /* GetSystemTimePreciseAsFileTime() not available */ switch(id) { @@ -150,7 +125,7 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp) switch(clock_id) { case CLOCK_REALTIME: { - load_GetSystemTimeBestAsFileTime()(&ct.ft); + GetSystemTimeBestAsFileTimeFuncPtr(&ct.ft); t = ct.u64 - DELTA_EPOCH_IN_100NS; tp->tv_sec = t / POW10_7; tp->tv_nsec = ((int) (t % POW10_7)) * 100; diff --git a/mingw-w64-libraries/winpthreads/src/misc.c b/mingw-w64-libraries/winpthreads/src/misc.c index 83caf262f..0aaeba913 100644 --- a/mingw-w64-libraries/winpthreads/src/misc.c +++ b/mingw-w64-libraries/winpthreads/src/misc.c @@ -24,15 +24,43 @@ #include "pthread.h" #include "misc.h" -static ULONGLONG (*GetTickCount64FuncPtr) (VOID); +void (WINAPI *GetSystemTimeBestAsFileTimeFuncPtr) (LPFILETIME) = NULL; +static ULONGLONG (WINAPI *GetTickCount64FuncPtr) (VOID); -static void __attribute__((constructor)) ctor (void) +#if defined(__GNUC__) || defined(__clang__) +__attribute__((constructor)) +#endif +static void winpthreads_init(void) { - HMODULE mod = GetModuleHandle("kernel32.dll"); - if (mod) - GetTickCount64FuncPtr = (__typeof__(GetTickCount64FuncPtr)) GetProcAddress(mod, "GetTickCount64"); + HMODULE mod = GetModuleHandle("kernel32.dll"); + if (!mod) return; + + GetTickCount64FuncPtr = (ULONGLONG (WINAPI *)(VOID))(void*) GetProcAddress(mod, + "GetTickCount64"); + + GetSystemTimeBestAsFileTimeFuncPtr = (void (WINAPI *)(LPFILETIME))(void*) GetProcAddress(mod, + "GetSystemTimePreciseAsFileTime"); /* <1us precision on Windows 10 */ + if (!GetSystemTimeBestAsFileTimeFuncPtr) + GetSystemTimeBestAsFileTimeFuncPtr = GetSystemTimeAsFileTime; /* >15ms precision on Windows 10 */ } +#if defined(_MSC_VER) && !defined(__clang__) +/* Force a reference to __xc_t to prevent whole program optimization + * from discarding the variable. */ + +/* On x86, symbols are prefixed with an underscore. */ +# if defined(_M_IX86) +# pragma comment(linker, "/include:___xc_t") +# else +# pragma comment(linker, "/include:__xc_t") +# endif + +#pragma section(".CRT$XCT", long, read) +__declspec(allocate(".CRT$XCT")) +extern const _PVFV __xc_t; +const _PVFV __xc_t = winpthreads_init; +#endif + unsigned long long _pthread_time_in_ms(void) { FILETIME ft; diff --git a/mingw-w64-libraries/winpthreads/src/misc.h b/mingw-w64-libraries/winpthreads/src/misc.h index eb0f7f2b6..e5c56519c 100644 --- a/mingw-w64-libraries/winpthreads/src/misc.h +++ b/mingw-w64-libraries/winpthreads/src/misc.h @@ -107,6 +107,8 @@ unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts); unsigned long _pthread_wait_for_single_object (void *handle, unsigned long timeout); unsigned long _pthread_wait_for_multiple_objects (unsigned long count, void **handles, unsigned int all, unsigned long timeout); +extern void (WINAPI *GetSystemTimeBestAsFileTimeFuncPtr) (LPFILETIME); + #if defined(__GNUC__) || defined(__clang__) #define likely(cond) __builtin_expect((cond) != 0, 1) #define unlikely(cond) __builtin_expect((cond) != 0, 0) -- 2.43.0 _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public