diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 5bd82bd3373..dfb026bd299 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -244,6 +244,7 @@ set(IMPLIB_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/sharedmutex.cpp ${CMAKE_CURRENT_LIST_DIR}/src/syserror_import_lib.cpp ${CMAKE_CURRENT_LIST_DIR}/src/vector_algorithms.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/xonce2.cpp ) # The following files are linked in msvcp140[d][_clr].dll. @@ -397,13 +398,18 @@ set(STATIC_SOURCES ${SOURCES_SATELLITE_CODECVT_IDS} ) +add_library(std_init_once_begin_initialize OBJECT IMPORTED) +add_library(std_init_once_complete OBJECT IMPORTED) +set_target_properties(std_init_once_begin_initialize PROPERTIES IMPORTED_OBJECTS "${CMAKE_CURRENT_LIST_DIR}/aliases/${VCLIBS_I386_OR_AMD64}/std_init_once_begin_initialize.obj") +set_target_properties(std_init_once_complete PROPERTIES IMPORTED_OBJECTS "${CMAKE_CURRENT_LIST_DIR}/aliases/${VCLIBS_I386_OR_AMD64}/std_init_once_complete.obj") + add_compile_definitions(_CRTBLD _VCRT_ALLOW_INTERNALS _HAS_OLD_IOSTREAMS_MEMBERS=1 _STL_CONCRT_SUPPORT) include_directories(BEFORE "${CMAKE_CURRENT_LIST_DIR}/inc" "${TOOLSET_ROOT_DIR}/crt/src/concrt" "${TOOLSET_ROOT_DIR}/crt/src/vcruntime" - ) +) function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIONS GL_FLAG THIS_CONFIG_LINK_OPTIONS) # msvcp140.dll @@ -446,7 +452,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_link_libraries(msvcp_2${D_SUFFIX}_objects PRIVATE Boost::headers Boost::disable_autolinking) add_library(msvcp_2${D_SUFFIX} SHARED) - target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_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") + target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_implib_objects std_init_once_begin_initialize std_init_once_complete "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -466,7 +472,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO # import library add_library(msvcp${D_SUFFIX}_implib STATIC ${HEADERS}) - target_link_libraries(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX}_implib_objects) + target_link_libraries(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX}_implib_objects std_init_once_begin_initialize std_init_once_complete) add_dependencies(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX} msvcp_1${D_SUFFIX} msvcp_2${D_SUFFIX} msvcp${D_SUFFIX}_codecvt_ids) set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$") set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES ARCHIVE_OUTPUT_NAME "msvcprt${D_SUFFIX}") @@ -483,7 +489,7 @@ function(add_stl_statics FLAVOR_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPI add_library(libcpmt${FLAVOR_SUFFIX} STATIC ${HEADERS} ${IMPLIB_SOURCES} ${SOURCES} ${STATIC_SOURCES}) target_compile_definitions(libcpmt${FLAVOR_SUFFIX} PRIVATE "${THIS_CONFIG_DEFINITIONS}") target_compile_options(libcpmt${FLAVOR_SUFFIX} PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};/EHsc") - target_link_libraries(libcpmt${FLAVOR_SUFFIX} PRIVATE Boost::headers Boost::disable_autolinking libcpmt${FLAVOR_SUFFIX}_eha) + target_link_libraries(libcpmt${FLAVOR_SUFFIX} PRIVATE Boost::headers Boost::disable_autolinking libcpmt${FLAVOR_SUFFIX}_eha std_init_once_begin_initialize std_init_once_complete) endfunction() add_stl_statics("" "_ITERATOR_DEBUG_LEVEL=0" "${VCLIBS_RELEASE_OPTIONS}") diff --git a/stl/aliases/amd64/std_init_once_begin_initialize.obj b/stl/aliases/amd64/std_init_once_begin_initialize.obj new file mode 100644 index 00000000000..452313ab3f7 Binary files /dev/null and b/stl/aliases/amd64/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/amd64/std_init_once_complete.obj b/stl/aliases/amd64/std_init_once_complete.obj new file mode 100644 index 00000000000..1bb2f105747 Binary files /dev/null and b/stl/aliases/amd64/std_init_once_complete.obj differ diff --git a/stl/aliases/arm/std_init_once_begin_initialize.obj b/stl/aliases/arm/std_init_once_begin_initialize.obj new file mode 100644 index 00000000000..452313ab3f7 Binary files /dev/null and b/stl/aliases/arm/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/arm/std_init_once_complete.obj b/stl/aliases/arm/std_init_once_complete.obj new file mode 100644 index 00000000000..1bb2f105747 Binary files /dev/null and b/stl/aliases/arm/std_init_once_complete.obj differ diff --git a/stl/aliases/arm64/std_init_once_begin_initialize.obj b/stl/aliases/arm64/std_init_once_begin_initialize.obj new file mode 100644 index 00000000000..452313ab3f7 Binary files /dev/null and b/stl/aliases/arm64/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/arm64/std_init_once_complete.obj b/stl/aliases/arm64/std_init_once_complete.obj new file mode 100644 index 00000000000..1bb2f105747 Binary files /dev/null and b/stl/aliases/arm64/std_init_once_complete.obj differ diff --git a/stl/aliases/chpe/std_init_once_begin_initialize.obj b/stl/aliases/chpe/std_init_once_begin_initialize.obj new file mode 100644 index 00000000000..b82e6958524 Binary files /dev/null and b/stl/aliases/chpe/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/chpe/std_init_once_complete.obj b/stl/aliases/chpe/std_init_once_complete.obj new file mode 100644 index 00000000000..82b42bedef0 Binary files /dev/null and b/stl/aliases/chpe/std_init_once_complete.obj differ diff --git a/stl/aliases/generate.cmd b/stl/aliases/generate.cmd new file mode 100644 index 00000000000..6a6ceb50b4d --- /dev/null +++ b/stl/aliases/generate.cmd @@ -0,0 +1,57 @@ +:: Copyright (c) Microsoft Corporation. +:: SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +:: +:: Generates aliases for Windows API functions called by headers. +:: TRANSITION, VSO-1116868 "'aliasobj.exe' should be available with Visual Studio" + +cd %~dp0 + +rmdir /s /q i386 +rmdir /s /q amd64 +rmdir /s /q arm +rmdir /s /q arm64 +rmdir /s /q chpe + +mkdir i386 +mkdir amd64 +mkdir arm +mkdir arm64 +mkdir chpe + +:: __std_init_once_begin_initialize +..\..\..\..\..\tools\x86\aliasobj.exe ^ + __imp____std_init_once_begin_initialize@16 ^ + __imp__InitOnceBeginInitialize@16 ^ + i386\std_init_once_begin_initialize.obj +..\..\..\..\..\tools\amd64\aliasobj.exe ^ + __imp___std_init_once_begin_initialize ^ + __imp_InitOnceBeginInitialize ^ + amd64\std_init_once_begin_initialize.obj +..\..\..\..\..\tools\x86\aliasobj.exe ^ + __imp___std_init_once_begin_initialize ^ + __imp_InitOnceBeginInitialize ^ + arm\std_init_once_begin_initialize.obj +copy amd64\std_init_once_begin_initialize.obj arm64\std_init_once_begin_initialize.obj +..\..\..\..\..\tools\x86\aliasobj.exe ^ + __imp_#__std_init_once_begin_initialize@16 ^ + __imp_#InitOnceBeginInitialize@16 ^ + chpe\std_init_once_begin_initialize.obj + +:: __std_init_once_complete +..\..\..\..\..\tools\x86\aliasobj.exe ^ + __imp____std_init_once_complete@12 ^ + __imp__InitOnceComplete@12 ^ + i386\std_init_once_complete.obj +..\..\..\..\..\tools\amd64\aliasobj.exe ^ + __imp___std_init_once_complete ^ + __imp_InitOnceComplete ^ + amd64\std_init_once_complete.obj +..\..\..\..\..\tools\x86\aliasobj.exe ^ + __imp___std_init_once_complete ^ + __imp_InitOnceComplete ^ + arm\std_init_once_complete.obj +copy amd64\std_init_once_complete.obj arm64\std_init_once_complete.obj +..\..\..\..\..\tools\x86\aliasobj.exe ^ + __imp_#__std_init_once_complete@12 ^ + __imp_#InitOnceComplete@12 ^ + chpe\std_init_once_complete.obj diff --git a/stl/aliases/i386/std_init_once_begin_initialize.obj b/stl/aliases/i386/std_init_once_begin_initialize.obj new file mode 100644 index 00000000000..46243a4db69 Binary files /dev/null and b/stl/aliases/i386/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/i386/std_init_once_complete.obj b/stl/aliases/i386/std_init_once_complete.obj new file mode 100644 index 00000000000..59a56df8052 Binary files /dev/null and b/stl/aliases/i386/std_init_once_complete.obj differ diff --git a/stl/inc/future b/stl/inc/future index f56bd6e1c1f..99c0f93032b 100644 --- a/stl/inc/future +++ b/stl/inc/future @@ -1429,6 +1429,20 @@ void swap(packaged_task<_Ty>& _Left, packaged_task<_Ty>& _Right) noexcept { _Left.swap(_Right); } +// FUNCTION TEMPLATE _Invoke_stored_explicit +template +auto _Invoke_stored_explicit(tuple<_Types...>&& _Tuple, index_sequence<_Indices...>) -> decltype( + _STD invoke(_STD get<_Indices>(_STD move(_Tuple))...)) { // invoke() a tuple with explicit parameter ordering + return _STD invoke(_STD get<_Indices>(_STD move(_Tuple))...); +} + +// FUNCTION TEMPLATE _Invoke_stored +template +auto _Invoke_stored(tuple<_Types...>&& _Tuple) + -> decltype(_Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{})) { // invoke() a tuple + return _Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{}); +} + // FUNCTION TEMPLATE async template class _Fake_no_copy_callable_adapter { diff --git a/stl/inc/mutex b/stl/inc/mutex index 30fd607f64a..ae6cd9d1ed8 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -14,9 +14,9 @@ #endif // _M_CEE_PURE #include +#include #include #include -#include #include #include @@ -508,61 +508,72 @@ public: }; #endif // _HAS_CXX17 -// FUNCTION TEMPLATE _Invoke_stored_explicit -template -auto _Invoke_stored_explicit(tuple<_Types...>&& _Tuple, index_sequence<_Indices...>) -> decltype( - _STD invoke(_STD get<_Indices>(_STD move(_Tuple))...)) { // invoke() a tuple with explicit parameter ordering - return _STD invoke(_STD get<_Indices>(_STD move(_Tuple))...); -} - -// FUNCTION TEMPLATE _Invoke_stored -template -auto _Invoke_stored(tuple<_Types...>&& _Tuple) - -> decltype(_Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{})) { // invoke() a tuple - return _Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{}); -} - // FUNCTION TEMPLATE call_once -[[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _XGetLastError(); - -template -int __stdcall _Callback_once(void*, void* _Pv, void**) { // adapt call_once() to callback API - _Tuple* _Ptup = static_cast<_Tuple*>(_Pv); - - _TRY_BEGIN - // Note explicit _Seq{} selects every element from *_Ptup except the last, - // which contains call_once's exception_ptr. - _Invoke_stored_explicit(_STD move(*_Ptup), _Seq{}); - _CATCH_ALL - auto& _Ref = _STD get<_Idx>(*_Ptup); - _Ref = _STD current_exception(); - return 0; - _CATCH_END +#ifdef _M_CEE +#define _WINDOWS_API __stdcall +#define _RENAME_WINDOWS_API(_Api) _Api##_clr +#else // ^^^ _M_CEE // !_M_CEE vvv +#define _WINDOWS_API __declspec(dllimport) __stdcall +#define _RENAME_WINDOWS_API(_Api) _Api +#endif // _M_CEE - return 1; -} +// WINBASEAPI +// BOOL +// WINAPI +// InitOnceBeginInitialize( +// _Inout_ LPINIT_ONCE lpInitOnce, +// _In_ DWORD dwFlags, +// _Out_ PBOOL fPending, +// _Outptr_opt_result_maybenull_ LPVOID* lpContext +// ); +extern "C" _NODISCARD int _WINDOWS_API _RENAME_WINDOWS_API(__std_init_once_begin_initialize)( + void** _LpInitOnce, unsigned long _DwFlags, int* _FPending, void** _LpContext) noexcept; + +// WINBASEAPI +// BOOL +// WINAPI +// InitOnceComplete( +// _Inout_ LPINIT_ONCE lpInitOnce, +// _In_ DWORD dwFlags, +// _In_opt_ LPVOID lpContext +// ); +extern "C" _NODISCARD int _WINDOWS_API _RENAME_WINDOWS_API(__std_init_once_complete)( + void** _LpInitOnce, unsigned long _DwFlags, void* _LpContext) noexcept; + +// #define RTL_RUN_ONCE_INIT_FAILED 0x00000004UL +// #define INIT_ONCE_INIT_FAILED RTL_RUN_ONCE_INIT_FAILED +_INLINE_VAR constexpr unsigned long _Init_once_init_failed = 0x4UL; + +struct _Init_once_completer { + once_flag& _Once; + unsigned long _DwFlags; + ~_Init_once_completer() { + if (_RENAME_WINDOWS_API(__std_init_once_complete)(&_Once._Opaque, _DwFlags, nullptr) == 0) { + _CSTD abort(); + } + } +}; template -void(call_once)(once_flag& _Flag, _Fn&& _Fx, _Args&&... _Ax) { // call _Fx(_Ax...) once - using _Tuple = tuple<_Fn&&, _Args&&..., exception_ptr&>; - using _Seq = make_index_sequence<1 + sizeof...(_Args)>; - - exception_ptr _Exc; - _Tuple _Tup(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)..., _Exc); - - _Execute_once_fp_t _Fp = &_Callback_once<_Tuple, _Seq, 1 + sizeof...(_Args)>; - - if (_Execute_once(_Flag, _Fp, _STD addressof(_Tup)) != 0) { - return; +void(call_once)(once_flag& _Once, _Fn&& _Fx, _Args&&... _Ax) noexcept( + noexcept(_STD invoke(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...))) /* strengthened */ { + // call _Fx(_Ax...) once + // parentheses against common "#define call_once(flag,func) pthread_once(flag,func)" + int _Pending; + if (_RENAME_WINDOWS_API(__std_init_once_begin_initialize)(&_Once._Opaque, 0, &_Pending, nullptr) == 0) { + _CSTD abort(); } - if (_Exc) { - _STD rethrow_exception(_Exc); + if (_Pending != 0) { + _Init_once_completer _Op{_Once, _Init_once_init_failed}; + _STD invoke(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...); + _Op._DwFlags = 0; } - - _XGetLastError(); } +#undef _WINDOWS_API +#undef _RENAME_WINDOWS_API + // condition_variable, timed_mutex, and recursive_timed_mutex are not supported under /clr #ifndef _M_CEE enum class cv_status { // names for wait returns diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index c4126d80a13..4c371170a5f 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -174,6 +174,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception $(CrtRoot)\github\stl\src\sharedmutex.cpp; $(CrtRoot)\github\stl\src\syserror_import_lib.cpp; $(CrtRoot)\github\stl\src\vector_algorithms.cpp; + $(CrtRoot)\github\stl\src\xonce2.cpp; "> nativecpp false @@ -191,6 +192,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + + + + diff --git a/stl/msbuild/stl_post/msvcp_post.settings.targets b/stl/msbuild/stl_post/msvcp_post.settings.targets index 6325ec4f978..6d09f6244f5 100644 --- a/stl/msbuild/stl_post/msvcp_post.settings.targets +++ b/stl/msbuild/stl_post/msvcp_post.settings.targets @@ -54,6 +54,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp index d09ea267903..95a5a011dbe 100644 --- a/stl/src/ppltasks.cpp +++ b/stl/src/ppltasks.cpp @@ -114,15 +114,23 @@ namespace Concurrency { } bool isCausalitySupported() { - std::call_once(m_stateFlag, [this] { - ComPtr causalityAPIs; - if (SUCCEEDED(GetActivationFactory( - HStringReference(RuntimeClass_Windows_Foundation_Diagnostics_AsyncCausalityTracer).Get(), - &causalityAPIs))) { - m_causalityAPIs = causalityAPIs.Detach(); - m_isSupported = true; - } - }); + // TRANSITION, ABI + _Execute_once( + m_stateFlag, + [](void*, void* _This_raw, void**) -> int { + const auto _This = static_cast(_This_raw); + ComPtr causalityAPIs; + if (SUCCEEDED(GetActivationFactory( + HStringReference(RuntimeClass_Windows_Foundation_Diagnostics_AsyncCausalityTracer) + .Get(), + &causalityAPIs))) { + _This->m_causalityAPIs = causalityAPIs.Detach(); + _This->m_isSupported = true; + } + + return 1; + }, + this); return m_isSupported; } } asyncCausalityTracer; diff --git a/stl/src/xonce.cpp b/stl/src/xonce.cpp index f6310f02f62..a7cbfd974c2 100644 --- a/stl/src/xonce.cpp +++ b/stl/src/xonce.cpp @@ -7,6 +7,7 @@ #include _STD_BEGIN +// TRANSITION, ABI _CRTIMP2_PURE int __CLRCALL_PURE_OR_CDECL _Execute_once( once_flag& _Flag, _Execute_once_fp_t _Callback, void* _Pv) noexcept { // wrap Win32 InitOnceExecuteOnce() static_assert(sizeof(_Flag._Opaque) == sizeof(INIT_ONCE), "invalid size"); diff --git a/stl/src/xonce2.cpp b/stl/src/xonce2.cpp new file mode 100644 index 00000000000..77013f2316e --- /dev/null +++ b/stl/src/xonce2.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include + +// This must be as small as possible, because its contents are +// injected into the msvcprt.lib and msvcprtd.lib import libraries. +// Do not include or define anything else here. +// In particular, basic_string must not be included here. + +// Provides forwarders for InitOnceBeginInitialize and InitOnceComplete for +// environments that can't use aliasobj, like /clr. + +_EXTERN_C + +int __stdcall __std_init_once_begin_initialize_clr( + void** _LpInitOnce, unsigned long _DwFlags, int* _FPending, void** _LpContext) noexcept { + return InitOnceBeginInitialize(reinterpret_cast(_LpInitOnce), _DwFlags, _FPending, _LpContext); +} + +int __stdcall __std_init_once_complete_clr(void** _LpInitOnce, unsigned long _DwFlags, void* _LpContext) noexcept { + return InitOnceComplete(reinterpret_cast(_LpInitOnce), _DwFlags, _LpContext); +} + +_END_EXTERN_C