From 7ecd37a2f67f7c973b2da9a171cef09bd8354773 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 23 Jul 2024 14:58:07 -0700 Subject: [PATCH 1/6] Revert "Drop support for Win7 / Server 2008 R2 (#4742)" This reverts commit 0be52578708f2b6400b980b30b9ccad8aa609526. Conflict resolutions: * yvals_core.h + GH 4742 dropped `_STL_WIN32_WINNT_WIN7`, then GH 4751 dropped `_STL_WIN32_WINNT_WINBLUE`. * atomic_wait.cpp + GH 4742 dropped `_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE` machinery, then GH 4751 dropped `__std_atomic_compare_exchange_128_fallback`. --- stl/CMakeLists.txt | 2 +- stl/inc/__msvc_chrono.hpp | 2 +- stl/inc/xatomic_wait.h | 16 +- stl/inc/yvals_core.h | 10 +- .../msvcp_atomic_wait.settings.targets | 1 - stl/src/atomic_wait.cpp | 166 +++++++- stl/src/awint.hpp | 11 + stl/src/ppltasks.cpp | 6 + stl/src/winapisupp.cpp | 141 ++++++- stl/src/xtime.cpp | 2 +- tests/std/include/test_atomic_wait.hpp | 366 ++++++++++++++++++ tests/std/test.lst | 1 + tests/std/tests/P1135R6_atomic_wait/test.cpp | 364 +---------------- .../tests/P1135R6_atomic_wait_vista/env.lst | 4 + .../tests/P1135R6_atomic_wait_vista/test.cpp | 11 + 15 files changed, 718 insertions(+), 385 deletions(-) create mode 100644 tests/std/include/test_atomic_wait.hpp create mode 100644 tests/std/tests/P1135R6_atomic_wait_vista/env.lst create mode 100644 tests/std/tests/P1135R6_atomic_wait_vista/test.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 1532ef4da0..376f4ef9cd 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -556,7 +556,7 @@ function(add_stl_dlls D_SUFFIX REL_OR_DBG) generate_satellite_def("atomic_wait" "${D_SUFFIX}") add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${CMAKE_BINARY_DIR}/msvcp_atomic_wait${D_SUFFIX}.def") - target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "synchronization.lib") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_atomic_wait${VCLIBS_SUFFIX}") diff --git a/stl/inc/__msvc_chrono.hpp b/stl/inc/__msvc_chrono.hpp index 08268b83b8..cad459cf81 100644 --- a/stl/inc/__msvc_chrono.hpp +++ b/stl/inc/__msvc_chrono.hpp @@ -640,7 +640,7 @@ namespace chrono { return time_point<_Clock, _To>(_CHRONO round<_To>(_Time.time_since_epoch())); } - _EXPORT_STD struct system_clock { // wraps GetSystemTimePreciseAsFileTime + _EXPORT_STD struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime using rep = long long; using period = ratio<1, 10'000'000>; // 100 nanoseconds using duration = _CHRONO duration; diff --git a/stl/inc/xatomic_wait.h b/stl/inc/xatomic_wait.h index 5058335d97..178f91fa9e 100644 --- a/stl/inc/xatomic_wait.h +++ b/stl/inc/xatomic_wait.h @@ -21,9 +21,23 @@ _STL_DISABLE_CLANG_WARNINGS extern "C" { inline constexpr unsigned long __std_atomic_wait_no_timeout = 0xFFFF'FFFF; // Pass as partial timeout +enum class __std_atomic_api_level : unsigned long { + __not_set, + __detecting, + __has_srwlock, + __has_wait_on_address, +}; + +// This function allows testing the atomic wait support while always using the APIs for a platform with fewer +// capabilities; it attempts to lock the APIs used to the level `_Requested_api_level`, and returns the actual API level +// in use. Once the API level has been set by calling this function (or detected by a call to one of the atomic wait +// functions), it can no longer be changed. +__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept; + // Support for atomic waits. // The "direct" functions are used when the underlying infrastructure can use WaitOnAddress directly; that is, _Size is -// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK. +// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK. If WaitOnAddress is not +// available on the current platform, falls back to a similar solution based on SRWLOCK and CONDITION_VARIABLE. int __stdcall __std_atomic_wait_direct( const void* _Storage, void* _Comparand, size_t _Size, unsigned long _Remaining_timeout) noexcept; void __stdcall __std_atomic_notify_one_direct(const void* _Storage) noexcept; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 207a859a74..4522aa5868 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1939,6 +1939,7 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #endif // defined(MRTDLL) && !defined(_M_CEE_PURE) #define _STL_WIN32_WINNT_VISTA 0x0600 // _WIN32_WINNT_VISTA from sdkddkver.h +#define _STL_WIN32_WINNT_WIN7 0x0601 // _WIN32_WINNT_WIN7 from sdkddkver.h #define _STL_WIN32_WINNT_WIN8 0x0602 // _WIN32_WINNT_WIN8 from sdkddkver.h #define _STL_WIN32_WINNT_WIN10 0x0A00 // _WIN32_WINNT_WIN10 from sdkddkver.h @@ -1947,10 +1948,13 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #if defined(_M_ARM64) // The first ARM64 Windows was Windows 10 #define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN10 -#else // ^^^ defined(_M_ARM64) / !defined(_M_ARM64) vvv -// The earliest Windows supported by this implementation is Windows 8 +#elif defined(_M_ARM) || defined(_ONECORE) || defined(_CRT_APP) +// The first ARM or OneCore or App Windows was Windows 8 #define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN8 -#endif // ^^^ !defined(_M_ARM64) ^^^ +#else // ^^^ default to Win8 / default to Win7 vvv +// The earliest Windows supported by this implementation is Windows 7 +#define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN7 +#endif // ^^^ !defined(_M_ARM) && !defined(_M_ARM64) && !defined(_ONECORE) && !defined(_CRT_APP) ^^^ #endif // !defined(_STL_WIN32_WINNT) #ifdef __cpp_noexcept_function_type diff --git a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets index 0f29c99587..869f8a1ecd 100644 --- a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets +++ b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets @@ -70,7 +70,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/atomic_wait.cpp b/stl/src/atomic_wait.cpp index 4bafb1a86b..2ac108c998 100644 --- a/stl/src/atomic_wait.cpp +++ b/stl/src/atomic_wait.cpp @@ -11,8 +11,6 @@ #include -#pragma comment(lib, "synchronization") - namespace { constexpr unsigned long long _Atomic_wait_no_deadline = 0xFFFF'FFFF'FFFF'FFFF; @@ -91,13 +89,134 @@ namespace { } #endif // defined(_DEBUG) } + +#ifndef _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE +#if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 +#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 1 +#else // ^^^ _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 vvv +#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 0 +#endif // ^^^ _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 ^^^ +#endif // !defined(_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE) + +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE + +#pragma comment(lib, "synchronization") + +#define __crtWaitOnAddress WaitOnAddress +#define __crtWakeByAddressSingle WakeByAddressSingle +#define __crtWakeByAddressAll WakeByAddressAll + +#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv + + struct _Wait_functions_table { + _STD atomic _Pfn_WaitOnAddress{nullptr}; + _STD atomic _Pfn_WakeByAddressSingle{nullptr}; + _STD atomic _Pfn_WakeByAddressAll{nullptr}; + _STD atomic<__std_atomic_api_level> _Api_level{__std_atomic_api_level::__not_set}; + }; + + _Wait_functions_table _Wait_functions; + + void _Force_wait_functions_srwlock_only() noexcept { + auto _Local = _Wait_functions._Api_level.load(_STD memory_order_acquire); + if (_Local <= __std_atomic_api_level::__detecting) { + while (!_Wait_functions._Api_level.compare_exchange_weak( + _Local, __std_atomic_api_level::__has_srwlock, _STD memory_order_acq_rel)) { + if (_Local > __std_atomic_api_level::__detecting) { + return; + } + } + } + } + + [[nodiscard]] __std_atomic_api_level _Init_wait_functions(__std_atomic_api_level _Level) { + while (!_Wait_functions._Api_level.compare_exchange_weak( + _Level, __std_atomic_api_level::__detecting, _STD memory_order_acq_rel)) { + if (_Level > __std_atomic_api_level::__detecting) { + return _Level; + } + } + + _Level = __std_atomic_api_level::__has_srwlock; + + const HMODULE _Sync_module = GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"); + if (_Sync_module != nullptr) { + const auto _Wait_on_address = + reinterpret_cast(GetProcAddress(_Sync_module, "WaitOnAddress")); + const auto _Wake_by_address_single = + reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressSingle")); + const auto _Wake_by_address_all = + reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressAll")); + + if (_Wait_on_address != nullptr && _Wake_by_address_single != nullptr && _Wake_by_address_all != nullptr) { + _Wait_functions._Pfn_WaitOnAddress.store(_Wait_on_address, _STD memory_order_relaxed); + _Wait_functions._Pfn_WakeByAddressSingle.store(_Wake_by_address_single, _STD memory_order_relaxed); + _Wait_functions._Pfn_WakeByAddressAll.store(_Wake_by_address_all, _STD memory_order_relaxed); + _Level = __std_atomic_api_level::__has_wait_on_address; + } + } + + // for __has_srwlock, relaxed would have been enough, not distinguishing for consistency + _Wait_functions._Api_level.store(_Level, _STD memory_order_release); + return _Level; + } + + [[nodiscard]] __std_atomic_api_level _Acquire_wait_functions() noexcept { + auto _Level = _Wait_functions._Api_level.load(_STD memory_order_acquire); + if (_Level <= __std_atomic_api_level::__detecting) { + _Level = _Init_wait_functions(_Level); + } + + return _Level; + } + + [[nodiscard]] BOOL __crtWaitOnAddress( + volatile VOID* Address, PVOID CompareAddress, SIZE_T AddressSize, DWORD dwMilliseconds) { + const auto _Wait_on_address = _Wait_functions._Pfn_WaitOnAddress.load(_STD memory_order_relaxed); + return _Wait_on_address(Address, CompareAddress, AddressSize, dwMilliseconds); + } + + VOID __crtWakeByAddressSingle(PVOID Address) { + const auto _Wake_by_address_single = _Wait_functions._Pfn_WakeByAddressSingle.load(_STD memory_order_relaxed); + _Wake_by_address_single(Address); + } + + VOID __crtWakeByAddressAll(PVOID Address) { + const auto _Wake_by_address_all = _Wait_functions._Pfn_WakeByAddressAll.load(_STD memory_order_relaxed); + _Wake_by_address_all(Address); + } + + bool __stdcall _Atomic_wait_are_equal_direct_fallback( + const void* _Storage, void* _Comparand, size_t _Size, void*) noexcept { + switch (_Size) { + case 1: + return __iso_volatile_load8(static_cast(_Storage)) == *static_cast(_Comparand); + case 2: + return __iso_volatile_load16(static_cast(_Storage)) == *static_cast(_Comparand); + case 4: + return __iso_volatile_load32(static_cast(_Storage)) == *static_cast(_Comparand); + case 8: + return __iso_volatile_load64(static_cast(_Storage)) + == *static_cast(_Comparand); + default: + _CSTD abort(); + } + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE } // unnamed namespace extern "C" { int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _Comparand, const size_t _Size, const unsigned long _Remaining_timeout) noexcept { - const auto _Result = - WaitOnAddress(const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout); +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { + return __std_atomic_wait_indirect( + _Storage, _Comparand, _Size, nullptr, &_Atomic_wait_are_equal_direct_fallback, _Remaining_timeout); + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + + const auto _Result = __crtWaitOnAddress( + const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout); if (!_Result) { _Assume_timeout(); @@ -106,11 +225,25 @@ int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _ } void __stdcall __std_atomic_notify_one_direct(const void* const _Storage) noexcept { - WakeByAddressSingle(const_cast(_Storage)); +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { + __std_atomic_notify_one_indirect(_Storage); + return; + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE = 0 + + __crtWakeByAddressSingle(const_cast(_Storage)); } void __stdcall __std_atomic_notify_all_direct(const void* const _Storage) noexcept { - WakeByAddressAll(const_cast(_Storage)); +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { + __std_atomic_notify_all_indirect(_Storage); + return; + } +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 + + __crtWakeByAddressAll(const_cast(_Storage)); } void __stdcall __std_atomic_notify_one_indirect(const void* const _Storage) noexcept { @@ -206,10 +339,25 @@ unsigned long __stdcall __std_atomic_wait_get_remaining_timeout(unsigned long lo return static_cast(_Remaining); } -// TRANSITION, ABI: preserved for binary compatibility -enum class __std_atomic_api_level : unsigned long { __not_set, __detecting, __has_srwlock, __has_wait_on_address }; -__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level) noexcept { +__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept { +#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE + (void) _Requested_api_level; return __std_atomic_api_level::__has_wait_on_address; +#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv + switch (_Requested_api_level) { + case __std_atomic_api_level::__not_set: + case __std_atomic_api_level::__detecting: + _CSTD abort(); + case __std_atomic_api_level::__has_srwlock: + _Force_wait_functions_srwlock_only(); + break; + case __std_atomic_api_level::__has_wait_on_address: + default: // future compat: new header using an old DLL will get the highest requested level supported + break; + } + + return _Acquire_wait_functions(); +#endif // !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE } #pragma warning(push) diff --git a/stl/src/awint.hpp b/stl/src/awint.hpp index 797801b7a9..da1e26e470 100644 --- a/stl/src/awint.hpp +++ b/stl/src/awint.hpp @@ -14,6 +14,17 @@ _CRT_BEGIN_C_HEADER +#if _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 + +#define __crtGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime) \ + GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime) + +#else // ^^^ _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 vvv + +_CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept; + +#endif // ^^^ _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 ^^^ + _CRTIMP2 int __cdecl __crtCompareStringA(_In_z_ LPCWSTR _LocaleName, _In_ DWORD _DwCmpFlags, _In_reads_(_CchCount1) LPCSTR _LpString1, _In_ int _CchCount1, _In_reads_(_CchCount2) LPCSTR _LpString2, _In_ int _CchCount2, _In_ int _CodePage) noexcept; diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp index 62cf885e54..ef1048cad1 100644 --- a/stl/src/ppltasks.cpp +++ b/stl/src/ppltasks.cpp @@ -26,6 +26,12 @@ namespace Concurrency { namespace details { [[noreturn]] _CRTIMP2 void __cdecl _ReportUnobservedException() { +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_CRT_APP) && _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + if (!IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) { + std::abort(); + } +#endif // ^^^ __fastfail conditionally available ^^^ + __fastfail(FAST_FAIL_INVALID_ARG); } diff --git a/stl/src/winapisupp.cpp b/stl/src/winapisupp.cpp index de6f6ae4d2..94dc7a55b1 100644 --- a/stl/src/winapisupp.cpp +++ b/stl/src/winapisupp.cpp @@ -1,12 +1,19 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include - -#include +// clang-format off +// Prevent clang-format from reordering before +#include +#include // for APPMODEL_ERROR_NO_PACKAGE #include +#include +#include +// clang-format on -#include +#pragma warning(push) +#pragma warning(disable : 4265) // non-virtual destructor in base class +#include +#pragma warning(pop) #if !defined(_ONECORE) namespace { @@ -14,6 +21,14 @@ namespace { // Use this macro for defining the following function pointers #define DEFINEFUNCTIONPOINTER(fn_name) decltype(&fn_name) __KERNEL32Function_##fn_name = nullptr +#if !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) + DEFINEFUNCTIONPOINTER(GetCurrentPackageId); +#endif // !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) + +#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + DEFINEFUNCTIONPOINTER(GetSystemTimePreciseAsFileTime); +#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + DEFINEFUNCTIONPOINTER(GetTempPath2W); // Use this macro for caching a function pointer from a DLL @@ -28,9 +43,107 @@ namespace { #if !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) +#if !defined(_CRT_APP) +#if defined(_ONECORE) + +namespace { + struct HMODULETraits { + using Type = HMODULE; + + static bool Close(Type const h) noexcept { + return ::FreeLibrary(h) != FALSE; + } + + static Type GetInvalidValue() noexcept { + return nullptr; + } + }; + + using HMODULEHandle = Microsoft::WRL::Wrappers::HandleT; +} // unnamed namespace + +extern "C" int __crt_IsPackagedAppHelper() noexcept { + static wchar_t const* const possible_apisets[] = { + L"api-ms-win-appmodel-runtime-l1-1-1.dll", // Windows 8.1+ APISet + L"ext-ms-win-kernel32-package-current-l1-1-0.dll", // Legacy APISet + L"appmodel.dll" // LNM implementation DLL + }; + + for (auto& dll : possible_apisets) { + HMODULEHandle const apiset(LoadLibraryExW(dll, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)); + if (!apiset.IsValid()) { + continue; + } + + auto const get_current_package_id = + reinterpret_cast(GetProcAddress(apiset.Get(), "GetCurrentPackageId")); + + if (!get_current_package_id) { + continue; + } + + UINT32 buffer_length = 0; + if (get_current_package_id(&buffer_length, nullptr) == ERROR_INSUFFICIENT_BUFFER) { + return 1; + } else { + return 0; + } + } + + // Either the app is not packaged or we cannot determine if the app is packaged: + return 0; +} + +#else // ^^^ defined(_ONECORE) / !defined(_ONECORE) vvv + +extern "C" int __crt_IsPackagedAppHelper() noexcept { + LONG retValue = APPMODEL_ERROR_NO_PACKAGE; + UINT32 bufferLength = 0; + + IFDYNAMICGETCACHEDFUNCTION(GetCurrentPackageId) { + retValue = pfGetCurrentPackageId(&bufferLength, nullptr); + } + + if (retValue == ERROR_INSUFFICIENT_BUFFER) { + return 1; + } + + // If GetCurrentPackageId was not found, or it returned a different error, + // then this is NOT a Packaged app + return 0; +} + +#endif // ^^^ !defined(_ONECORE) ^^^ +#endif // ^^^ !defined(_CRT_APP) ^^^ + +// __crtIsPackagedApp() - Check if the current app is a Packaged app +// +// Purpose: +// Check if the current application was started through a package. +// This determines if the app is a Packaged app or not. +// +// This function uses a new Windows 8 API, GetCurrentPackageId, to detect +// if the application is deployed via a package. +// +// Entry: +// None +// +// Exit: +// TRUE if Packaged app, FALSE if not. // TRANSITION, ABI: preserved for binary compatibility extern "C" _CRTIMP2 BOOL __cdecl __crtIsPackagedApp() noexcept { - return FALSE; +#ifdef _CRT_APP + return TRUE; +#else // ^^^ defined(_CRT_APP) / !defined(_CRT_APP) vvv + static int isPackaged = -1; // Initialize to undefined state + + // If we've already made this check, just return the prev result + if (isPackaged < 0) { + isPackaged = __crt_IsPackagedAppHelper(); + } + + return (isPackaged > 0) ? TRUE : FALSE; +#endif // ^^^ !defined(_CRT_APP) ^^^ } #endif // !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) @@ -154,9 +267,15 @@ extern "C" _CRTIMP2 BOOL __cdecl __crtSetFileInformationByHandle(_In_ HANDLE con #if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 -// TRANSITION, ABI: preserved for binary compatibility extern "C" _CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept { - GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime); + // use GetSystemTimePreciseAsFileTime if it is available (only on Windows 8+)... + IFDYNAMICGETCACHEDFUNCTION(GetSystemTimePreciseAsFileTime) { + pfGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime); + return; + } + + // ...otherwise use GetSystemTimeAsFileTime. + GetSystemTimeAsFileTime(lpSystemTimeAsFileTime); } #endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 @@ -186,6 +305,14 @@ static int __cdecl initialize_pointers() noexcept { HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll"); _Analysis_assume_(hKernel32); +#if !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) + STOREFUNCTIONPOINTER(hKernel32, GetCurrentPackageId); +#endif // !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) + +#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + STOREFUNCTIONPOINTER(hKernel32, GetSystemTimePreciseAsFileTime); +#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 + // Note that GetTempPath2W is defined as of Windows 10 Build 20348 (a server release) or Windows 11, // but there is no "_WIN32_WINNT_WIN11" constant, so we will always dynamically load it STOREFUNCTIONPOINTER(hKernel32, GetTempPath2W); diff --git a/stl/src/xtime.cpp b/stl/src/xtime.cpp index 7499f42e19..c59d0fc73a 100644 --- a/stl/src/xtime.cpp +++ b/stl/src/xtime.cpp @@ -51,7 +51,7 @@ _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks() noexcept { constexpr long long _Epoch = 0x19DB1DED53E8000LL; FILETIME ft; - GetSystemTimePreciseAsFileTime(&ft); + __crtGetSystemTimePreciseAsFileTime(&ft); return ((static_cast(ft.dwHighDateTime)) << 32) + static_cast(ft.dwLowDateTime) - _Epoch; } diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp new file mode 100644 index 0000000000..28f4be97fb --- /dev/null +++ b/tests/std/include/test_atomic_wait.hpp @@ -0,0 +1,366 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include + +template