Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for Win7 / Server 2008 R2 #4742

Merged
merged 12 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion stl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
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")
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}")
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/__msvc_chrono.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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/GetSystemTimeAsFileTime
_EXPORT_STD struct system_clock { // wraps GetSystemTimePreciseAsFileTime
using rep = long long;
using period = ratio<1, 10'000'000>; // 100 nanoseconds
using duration = _CHRONO duration<rep, period>;
Expand Down
16 changes: 1 addition & 15 deletions stl/inc/xatomic_wait.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,9 @@ _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. If WaitOnAddress is not
// available on the current platform, falls back to a similar solution based on SRWLOCK and CONDITION_VARIABLE.
// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK.
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;
Expand Down
10 changes: 3 additions & 7 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1927,7 +1927,6 @@ 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this also unused or is it used as a "baseline"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still test it here:

#if _STL_WIN32_WINNT < _STL_WIN32_WINNT_VISTA

In theory, this could be collapsed away, since we're either building the STL as a user, or building the separately compiled STL. I'll look into this for a followup - we can't change the DLL's export surface, but when building the static LIB we can unconditionally assume Win8+, and I don't think we're doing that right now.

#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_WINBLUE 0x0603 // _WIN32_WINNT_WINBLUE from sdkddkver.h
#define _STL_WIN32_WINNT_WIN10 0x0A00 // _WIN32_WINNT_WIN10 from sdkddkver.h
Expand All @@ -1937,13 +1936,10 @@ 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
#elif defined(_M_ARM) || defined(_ONECORE) || defined(_CRT_APP)
// The first ARM or OneCore or App Windows was Windows 8
#else // ^^^ defined(_M_ARM64) / !defined(_M_ARM64) vvv
// The earliest Windows supported by this implementation is Windows 8
#define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN8
#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(_M_ARM64) ^^^
#endif // !defined(_STL_WIN32_WINNT)

#ifdef __cpp_noexcept_function_type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
<TargetLib Include="$(CrtLibPath)\vcruntime$(BuildSuffix)$(ClrLibSuffix).lib"/>
<TargetLib Include="$(UniversalCRTLib)"/>
<TargetLib Condition="'$(MsvcpFlavor)' == 'kernel32' or '$(MsvcpFlavor)' == 'netfx'" Include="$(SdkLibPath)\advapi32.lib"/>
<TargetLib Condition="'$(MsvcpFlavor)' == 'kernel32' or '$(MsvcpFlavor)' == 'netfx'" Include="$(SdkLibPath)\synchronization.lib"/>
</ItemGroup>

<!-- Copy the output dll and pdb to various destinations -->
Expand Down
166 changes: 9 additions & 157 deletions stl/src/atomic_wait.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include <Windows.h>

#pragma comment(lib, "synchronization")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we even need the pragma comment if we're linking everything manually?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This activates when users link the STL statically (/MT, /MTd) and drag in libcpmt[d].lib, which contains atomic_wait.obj. The #pragma comment(lib, "synchronization") then tells the linker to automatically drag in synchronization.lib.


namespace {
constexpr unsigned long long _Atomic_wait_no_deadline = 0xFFFF'FFFF'FFFF'FFFF;

Expand Down Expand Up @@ -89,120 +91,6 @@ 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<decltype(&::WaitOnAddress)> _Pfn_WaitOnAddress{nullptr};
_STD atomic<decltype(&::WakeByAddressSingle)> _Pfn_WakeByAddressSingle{nullptr};
_STD atomic<decltype(&::WakeByAddressAll)> _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<decltype(&::WaitOnAddress)>(GetProcAddress(_Sync_module, "WaitOnAddress"));
const auto _Wake_by_address_single =
reinterpret_cast<decltype(&::WakeByAddressSingle)>(GetProcAddress(_Sync_module, "WakeByAddressSingle"));
const auto _Wake_by_address_all =
reinterpret_cast<decltype(&::WakeByAddressAll)>(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<const char*>(_Storage)) == *static_cast<const char*>(_Comparand);
case 2:
return __iso_volatile_load16(static_cast<const short*>(_Storage)) == *static_cast<const short*>(_Comparand);
case 4:
return __iso_volatile_load32(static_cast<const int*>(_Storage)) == *static_cast<const int*>(_Comparand);
case 8:
return __iso_volatile_load64(static_cast<const long long*>(_Storage))
== *static_cast<const long long*>(_Comparand);
default:
_CSTD abort();
}
}
#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE

[[nodiscard]] unsigned char __std_atomic_compare_exchange_128_fallback(
_Inout_bytecount_(16) long long* _Destination, _In_ long long _ExchangeHigh, _In_ long long _ExchangeLow,
_Inout_bytecount_(16) long long* _ComparandResult) noexcept {
Expand All @@ -225,15 +113,8 @@ 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 {
#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<volatile void*>(_Storage), const_cast<void*>(_Comparand), _Size, _Remaining_timeout);
const auto _Result =
WaitOnAddress(const_cast<volatile void*>(_Storage), const_cast<void*>(_Comparand), _Size, _Remaining_timeout);

if (!_Result) {
_Assume_timeout();
Expand All @@ -242,25 +123,11 @@ int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _
}

void __stdcall __std_atomic_notify_one_direct(const void* const _Storage) noexcept {
#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<void*>(_Storage));
WakeByAddressSingle(const_cast<void*>(_Storage));
}

void __stdcall __std_atomic_notify_all_direct(const void* const _Storage) noexcept {
#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<void*>(_Storage));
WakeByAddressAll(const_cast<void*>(_Storage));
}

void __stdcall __std_atomic_notify_one_indirect(const void* const _Storage) noexcept {
Expand Down Expand Up @@ -356,25 +223,10 @@ unsigned long __stdcall __std_atomic_wait_get_remaining_timeout(unsigned long lo
return static_cast<unsigned long>(_Remaining);
}

__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;
// 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 {
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)
Expand Down
11 changes: 0 additions & 11 deletions stl/src/awint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,6 @@

_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;
Expand Down
6 changes: 0 additions & 6 deletions stl/src/ppltasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ 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);
}

Expand Down
Loading