mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 20:03:12 +00:00
[UCRT] Import Microsoft.Windows.SDK.CRTSource version 10.0.22621.3
Imported from https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource/10.0.22621.3 License: MIT
This commit is contained in:
parent
f1b60c66f0
commit
04e0dc4a7a
568 changed files with 115483 additions and 0 deletions
345
sdk/lib/ucrt/internal/per_thread_data.cpp
Normal file
345
sdk/lib/ucrt/internal/per_thread_data.cpp
Normal file
|
@ -0,0 +1,345 @@
|
|||
//
|
||||
// per_thread_data.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Per-Thread Data (PTD) used by the AppCRT.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <corecrt_internal_ptd_propagation.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
|
||||
#ifdef _CRT_GLOBAL_STATE_ISOLATION
|
||||
extern "C" DWORD __crt_global_state_mode_flsindex = FLS_OUT_OF_INDEXES;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static void WINAPI destroy_fls(void*) throw();
|
||||
|
||||
|
||||
|
||||
static unsigned long __acrt_flsindex = FLS_OUT_OF_INDEXES;
|
||||
|
||||
|
||||
|
||||
extern "C" bool __cdecl __acrt_initialize_ptd()
|
||||
{
|
||||
__acrt_flsindex = __acrt_FlsAlloc(destroy_fls);
|
||||
if (__acrt_flsindex == FLS_OUT_OF_INDEXES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__acrt_getptd_noexit() == nullptr)
|
||||
{
|
||||
__acrt_uninitialize_ptd(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool __cdecl __acrt_uninitialize_ptd(bool)
|
||||
{
|
||||
if (__acrt_flsindex != FLS_OUT_OF_INDEXES)
|
||||
{
|
||||
__acrt_FlsFree(__acrt_flsindex);
|
||||
__acrt_flsindex = FLS_OUT_OF_INDEXES;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __cdecl replace_current_thread_locale_nolock(
|
||||
__acrt_ptd* const ptd,
|
||||
__crt_locale_data* const new_locale_info
|
||||
) throw()
|
||||
{
|
||||
if (ptd->_locale_info)
|
||||
{
|
||||
__acrt_release_locale_ref(ptd->_locale_info);
|
||||
if (ptd->_locale_info != __acrt_current_locale_data.value() &&
|
||||
ptd->_locale_info != &__acrt_initial_locale_data &&
|
||||
ptd->_locale_info->refcount == 0)
|
||||
{
|
||||
__acrt_free_locale(ptd->_locale_info);
|
||||
}
|
||||
}
|
||||
|
||||
ptd->_locale_info = new_locale_info;
|
||||
if (ptd->_locale_info)
|
||||
{
|
||||
__acrt_add_locale_ref(ptd->_locale_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Constructs a single PTD object, copying the given 'locale_data' if provided.
|
||||
static void __cdecl construct_ptd(
|
||||
__acrt_ptd* const ptd,
|
||||
__crt_locale_data** const locale_data
|
||||
) throw()
|
||||
{
|
||||
ptd->_rand_state = 1;
|
||||
ptd->_pxcptacttab = const_cast<__crt_signal_action_t*>(__acrt_exception_action_table);
|
||||
|
||||
// It is necessary to always have GLOBAL_LOCALE_BIT set in perthread data
|
||||
// because when doing bitwise or, we won't get __UPDATE_LOCALE to work when
|
||||
// global per thread locale is set.
|
||||
// See _configthreadlocale() and __acrt_should_sync_with_global_locale().
|
||||
ptd->_own_locale = _GLOBAL_LOCALE_BIT;
|
||||
|
||||
ptd->_multibyte_info = &__acrt_initial_multibyte_data;
|
||||
|
||||
// Initialize _setloc_data. These are the only valuse that need to be
|
||||
// initialized.
|
||||
ptd->_setloc_data._cachein[0] = L'C';
|
||||
ptd->_setloc_data._cacheout[0] = L'C';
|
||||
|
||||
// Downlevel data is not initially used
|
||||
ptd->_setloc_downlevel_data = nullptr;
|
||||
|
||||
__acrt_lock_and_call(__acrt_multibyte_cp_lock, [&]
|
||||
{
|
||||
_InterlockedIncrement(&ptd->_multibyte_info->refcount);
|
||||
});
|
||||
|
||||
// We need to make sure that ptd->ptlocinfo in never nullptr, this saves us
|
||||
// perf counts when UPDATING locale.
|
||||
__acrt_lock_and_call(__acrt_locale_lock, [&]
|
||||
{
|
||||
replace_current_thread_locale_nolock(ptd, *locale_data);
|
||||
});
|
||||
}
|
||||
|
||||
// Constructs each of the 'state_index_count' PTD objects in the array of PTD
|
||||
// objects pointed to by 'ptd'.
|
||||
static void __cdecl construct_ptd_array(__acrt_ptd* const ptd) throw()
|
||||
{
|
||||
for (size_t i = 0; i != __crt_state_management::state_index_count; ++i)
|
||||
{
|
||||
construct_ptd(&ptd[i], &__acrt_current_locale_data.dangerous_get_state_array()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleans up all resources used by a single PTD; does not free the PTD structure
|
||||
// itself.
|
||||
static void __cdecl destroy_ptd(__acrt_ptd* const ptd) throw()
|
||||
{
|
||||
if (ptd->_pxcptacttab != __acrt_exception_action_table)
|
||||
{
|
||||
_free_crt(ptd->_pxcptacttab);
|
||||
}
|
||||
|
||||
_free_crt(ptd->_cvtbuf);
|
||||
_free_crt(ptd->_asctime_buffer);
|
||||
_free_crt(ptd->_wasctime_buffer);
|
||||
_free_crt(ptd->_gmtime_buffer);
|
||||
_free_crt(ptd->_tmpnam_narrow_buffer);
|
||||
_free_crt(ptd->_tmpnam_wide_buffer);
|
||||
_free_crt(ptd->_strerror_buffer);
|
||||
_free_crt(ptd->_wcserror_buffer);
|
||||
_free_crt(ptd->_beginthread_context);
|
||||
|
||||
__acrt_lock_and_call(__acrt_multibyte_cp_lock, [&]
|
||||
{
|
||||
__crt_multibyte_data* const multibyte_data = ptd->_multibyte_info;
|
||||
if (!multibyte_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_InterlockedDecrement(&multibyte_data->refcount) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (multibyte_data == &__acrt_initial_multibyte_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_free_crt(multibyte_data);
|
||||
});
|
||||
|
||||
__acrt_lock_and_call(__acrt_locale_lock, [&]
|
||||
{
|
||||
replace_current_thread_locale_nolock(ptd, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
// Destroys each of the 'state_index_count' PTD objects in the array of PTD
|
||||
// objects pointed to by 'ptd'.
|
||||
static void __cdecl destroy_ptd_array(__acrt_ptd* const ptd) throw()
|
||||
{
|
||||
for (size_t i = 0; i != __crt_state_management::state_index_count; ++i)
|
||||
{
|
||||
destroy_ptd(&ptd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called by the operating system when a thread is being
|
||||
// destroyed, to allow us the opportunity to clean up.
|
||||
static void WINAPI destroy_fls(void* const pfd) throw()
|
||||
{
|
||||
if (!pfd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
destroy_ptd_array(static_cast<__acrt_ptd*>(pfd));
|
||||
_free_crt(pfd);
|
||||
}
|
||||
|
||||
static __forceinline __acrt_ptd* try_get_ptd_head() throw()
|
||||
{
|
||||
// If we haven't allocated per-thread data for this module, return failure:
|
||||
if (__acrt_flsindex == FLS_OUT_OF_INDEXES)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
__acrt_ptd* const ptd_head = static_cast<__acrt_ptd*>(__acrt_FlsGetValue(__acrt_flsindex));
|
||||
if (!ptd_head)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ptd_head;
|
||||
}
|
||||
|
||||
_Success_(return != nullptr)
|
||||
static __forceinline __acrt_ptd* internal_get_ptd_head() throw()
|
||||
{
|
||||
// We use the CRT heap to allocate the PTD. If the CRT heap fails to
|
||||
// allocate the requested memory, it will attempt to set errno to ENOMEM,
|
||||
// which will in turn attempt to acquire the PTD, resulting in infinite
|
||||
// recursion that causes a stack overflow.
|
||||
//
|
||||
// We set the PTD to this sentinel value for the duration of the allocation
|
||||
// in order to detect this case.
|
||||
static void* const reentrancy_sentinel = reinterpret_cast<void*>(SIZE_MAX);
|
||||
|
||||
__acrt_ptd* const existing_ptd_head = try_get_ptd_head();
|
||||
if (existing_ptd_head == reentrancy_sentinel)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else if (existing_ptd_head != nullptr)
|
||||
{
|
||||
return existing_ptd_head;
|
||||
}
|
||||
|
||||
if (!__acrt_FlsSetValue(__acrt_flsindex, reentrancy_sentinel))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
__crt_unique_heap_ptr<__acrt_ptd> new_ptd_head(_calloc_crt_t(__acrt_ptd, __crt_state_management::state_index_count));
|
||||
if (!new_ptd_head)
|
||||
{
|
||||
__acrt_FlsSetValue(__acrt_flsindex, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!__acrt_FlsSetValue(__acrt_flsindex, new_ptd_head.get()))
|
||||
{
|
||||
__acrt_FlsSetValue(__acrt_flsindex, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
construct_ptd_array(new_ptd_head.get());
|
||||
return new_ptd_head.detach();
|
||||
}
|
||||
|
||||
// This functionality has been split out of __acrt_getptd_noexit so that we can
|
||||
// force it to be inlined into both __acrt_getptd_noexit and __acrt_getptd. These
|
||||
// functions are performance critical and this change has substantially improved
|
||||
// __acrt_getptd performance.
|
||||
static __forceinline __acrt_ptd* __cdecl internal_getptd_noexit(
|
||||
__crt_scoped_get_last_error_reset const& last_error_reset,
|
||||
size_t const global_state_index
|
||||
) throw()
|
||||
{
|
||||
UNREFERENCED_PARAMETER(last_error_reset);
|
||||
__acrt_ptd* const ptd_head = internal_get_ptd_head();
|
||||
if (!ptd_head)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ptd_head + global_state_index;
|
||||
}
|
||||
|
||||
static __forceinline __acrt_ptd* __cdecl internal_getptd_noexit() throw()
|
||||
{
|
||||
__crt_scoped_get_last_error_reset const last_error_reset;
|
||||
return internal_getptd_noexit(last_error_reset, __crt_state_management::get_current_state_index(last_error_reset));
|
||||
}
|
||||
|
||||
__acrt_ptd* __cdecl __acrt_getptd_noexit_explicit(__crt_scoped_get_last_error_reset const& last_error_reset, size_t const global_state_index)
|
||||
{ // An extra function to grab the PTD while a GetLastError() reset guard is already in place
|
||||
// and the global state index is already known.
|
||||
|
||||
return internal_getptd_noexit(last_error_reset, global_state_index);
|
||||
}
|
||||
|
||||
extern "C" __acrt_ptd* __cdecl __acrt_getptd_noexit()
|
||||
{
|
||||
return internal_getptd_noexit();
|
||||
}
|
||||
|
||||
extern "C" __acrt_ptd* __cdecl __acrt_getptd()
|
||||
{
|
||||
__acrt_ptd* const ptd = internal_getptd_noexit();
|
||||
if (!ptd)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
return ptd;
|
||||
}
|
||||
|
||||
extern "C" __acrt_ptd* __cdecl __acrt_getptd_head()
|
||||
{
|
||||
__acrt_ptd* const ptd_head = internal_get_ptd_head();
|
||||
if (!ptd_head)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
return ptd_head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" void __cdecl __acrt_freeptd()
|
||||
{
|
||||
__acrt_ptd* const ptd_head = try_get_ptd_head();
|
||||
if (!ptd_head)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__acrt_FlsSetValue(__acrt_flsindex, nullptr);
|
||||
destroy_fls(ptd_head);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// These functions are simply wrappers around the Windows API functions.
|
||||
extern "C" unsigned long __cdecl __threadid()
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
extern "C" uintptr_t __cdecl __threadhandle()
|
||||
{
|
||||
return reinterpret_cast<uintptr_t>(GetCurrentThread());
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue