ReactOS 0.4.16-dev-927-g467dec4
per_thread_data.cpp
Go to the documentation of this file.
1//
2// per_thread_data.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Per-Thread Data (PTD) used by the AppCRT.
7//
8#include <corecrt_internal.h>
10#include <stddef.h>
11
12
13
14#ifdef _CRT_GLOBAL_STATE_ISOLATION
15 extern "C" DWORD __crt_global_state_mode_flsindex = FLS_OUT_OF_INDEXES;
16#endif
17
18
19
20static void WINAPI destroy_fls(void*) throw();
21
22
23
24static unsigned long __acrt_flsindex = FLS_OUT_OF_INDEXES;
25
26
27
29{
32 {
33 return false;
34 }
35
36 if (__acrt_getptd_noexit() == nullptr)
37 {
39 return false;
40 }
41
42 return true;
43}
44
45extern "C" bool __cdecl __acrt_uninitialize_ptd(bool)
46{
48 {
51 }
52
53 return true;
54}
55
56
57
59 __acrt_ptd* const ptd,
60 __crt_locale_data* const new_locale_info
61 ) throw()
62{
63 if (ptd->_locale_info)
64 {
65 __acrt_release_locale_ref(ptd->_locale_info);
66 if (ptd->_locale_info != __acrt_current_locale_data.value() &&
67 ptd->_locale_info != &__acrt_initial_locale_data &&
68 ptd->_locale_info->refcount == 0)
69 {
70 __acrt_free_locale(ptd->_locale_info);
71 }
72 }
73
74 ptd->_locale_info = new_locale_info;
75 if (ptd->_locale_info)
76 {
77 __acrt_add_locale_ref(ptd->_locale_info);
78 }
79}
80
81
82
83// Constructs a single PTD object, copying the given 'locale_data' if provided.
85 __acrt_ptd* const ptd,
86 __crt_locale_data** const locale_data
87 ) throw()
88{
89 ptd->_rand_state = 1;
90 ptd->_pxcptacttab = const_cast<__crt_signal_action_t*>(__acrt_exception_action_table);
91
92 // It is necessary to always have GLOBAL_LOCALE_BIT set in perthread data
93 // because when doing bitwise or, we won't get __UPDATE_LOCALE to work when
94 // global per thread locale is set.
95 // See _configthreadlocale() and __acrt_should_sync_with_global_locale().
96 ptd->_own_locale = _GLOBAL_LOCALE_BIT;
97
98 ptd->_multibyte_info = &__acrt_initial_multibyte_data;
99
100 // Initialize _setloc_data. These are the only valuse that need to be
101 // initialized.
102 ptd->_setloc_data._cachein[0] = L'C';
103 ptd->_setloc_data._cacheout[0] = L'C';
104
105 // Downlevel data is not initially used
106 ptd->_setloc_downlevel_data = nullptr;
107
108 __acrt_lock_and_call(__acrt_multibyte_cp_lock, [&]
109 {
110 _InterlockedIncrement(&ptd->_multibyte_info->refcount);
111 });
112
113 // We need to make sure that ptd->ptlocinfo in never nullptr, this saves us
114 // perf counts when UPDATING locale.
115 __acrt_lock_and_call(__acrt_locale_lock, [&]
116 {
118 });
119}
120
121// Constructs each of the 'state_index_count' PTD objects in the array of PTD
122// objects pointed to by 'ptd'.
123static void __cdecl construct_ptd_array(__acrt_ptd* const ptd) throw()
124{
125 for (size_t i = 0; i != __crt_state_management::state_index_count; ++i)
126 {
127 construct_ptd(&ptd[i], &__acrt_current_locale_data.dangerous_get_state_array()[i]);
128 }
129}
130
131// Cleans up all resources used by a single PTD; does not free the PTD structure
132// itself.
133static void __cdecl destroy_ptd(__acrt_ptd* const ptd) throw()
134{
135 if (ptd->_pxcptacttab != __acrt_exception_action_table)
136 {
137 _free_crt(ptd->_pxcptacttab);
138 }
139
140 _free_crt(ptd->_cvtbuf);
141 _free_crt(ptd->_asctime_buffer);
142 _free_crt(ptd->_wasctime_buffer);
143 _free_crt(ptd->_gmtime_buffer);
144 _free_crt(ptd->_tmpnam_narrow_buffer);
145 _free_crt(ptd->_tmpnam_wide_buffer);
146 _free_crt(ptd->_strerror_buffer);
147 _free_crt(ptd->_wcserror_buffer);
148 _free_crt(ptd->_beginthread_context);
149
150 __acrt_lock_and_call(__acrt_multibyte_cp_lock, [&]
151 {
152 __crt_multibyte_data* const multibyte_data = ptd->_multibyte_info;
153 if (!multibyte_data)
154 {
155 return;
156 }
157
158 if (_InterlockedDecrement(&multibyte_data->refcount) != 0)
159 {
160 return;
161 }
162
163 if (multibyte_data == &__acrt_initial_multibyte_data)
164 {
165 return;
166 }
167
168 _free_crt(multibyte_data);
169 });
170
171 __acrt_lock_and_call(__acrt_locale_lock, [&]
172 {
174 });
175}
176
177// Destroys each of the 'state_index_count' PTD objects in the array of PTD
178// objects pointed to by 'ptd'.
179static void __cdecl destroy_ptd_array(__acrt_ptd* const ptd) throw()
180{
181 for (size_t i = 0; i != __crt_state_management::state_index_count; ++i)
182 {
183 destroy_ptd(&ptd[i]);
184 }
185}
186
187// This function is called by the operating system when a thread is being
188// destroyed, to allow us the opportunity to clean up.
189static void WINAPI destroy_fls(void* const pfd) throw()
190{
191 if (!pfd)
192 {
193 return;
194 }
195
196 destroy_ptd_array(static_cast<__acrt_ptd*>(pfd));
197 _free_crt(pfd);
198}
199
200static __forceinline __acrt_ptd* try_get_ptd_head() throw()
201{
202 // If we haven't allocated per-thread data for this module, return failure:
204 {
205 return nullptr;
206 }
207
208 __acrt_ptd* const ptd_head = static_cast<__acrt_ptd*>(__acrt_FlsGetValue(__acrt_flsindex));
209 if (!ptd_head)
210 {
211 return nullptr;
212 }
213
214 return ptd_head;
215}
216
217_Success_(return != nullptr)
218static __forceinline __acrt_ptd* internal_get_ptd_head() throw()
219{
220 // We use the CRT heap to allocate the PTD. If the CRT heap fails to
221 // allocate the requested memory, it will attempt to set errno to ENOMEM,
222 // which will in turn attempt to acquire the PTD, resulting in infinite
223 // recursion that causes a stack overflow.
224 //
225 // We set the PTD to this sentinel value for the duration of the allocation
226 // in order to detect this case.
227 static void* const reentrancy_sentinel = reinterpret_cast<void*>(SIZE_MAX);
228
229 __acrt_ptd* const existing_ptd_head = try_get_ptd_head();
230 if (existing_ptd_head == reentrancy_sentinel)
231 {
232 return nullptr;
233 }
234 else if (existing_ptd_head != nullptr)
235 {
236 return existing_ptd_head;
237 }
238
239 if (!__acrt_FlsSetValue(__acrt_flsindex, reentrancy_sentinel))
240 {
241 return nullptr;
242 }
243
244 __crt_unique_heap_ptr<__acrt_ptd> new_ptd_head(_calloc_crt_t(__acrt_ptd, __crt_state_management::state_index_count));
245 if (!new_ptd_head)
246 {
248 return nullptr;
249 }
250
251 if (!__acrt_FlsSetValue(__acrt_flsindex, new_ptd_head.get()))
252 {
254 return nullptr;
255 }
256
257 construct_ptd_array(new_ptd_head.get());
258 return new_ptd_head.detach();
259}
260
261// This functionality has been split out of __acrt_getptd_noexit so that we can
262// force it to be inlined into both __acrt_getptd_noexit and __acrt_getptd. These
263// functions are performance critical and this change has substantially improved
264// __acrt_getptd performance.
266 __crt_scoped_get_last_error_reset const& last_error_reset,
267 size_t const global_state_index
268 ) throw()
269{
270 UNREFERENCED_PARAMETER(last_error_reset);
271 __acrt_ptd* const ptd_head = internal_get_ptd_head();
272 if (!ptd_head)
273 {
274 return nullptr;
275 }
276
277 return ptd_head + global_state_index;
278}
279
281{
282 __crt_scoped_get_last_error_reset const last_error_reset;
283 return internal_getptd_noexit(last_error_reset, __crt_state_management::get_current_state_index(last_error_reset));
284}
285
286__acrt_ptd* __cdecl __acrt_getptd_noexit_explicit(__crt_scoped_get_last_error_reset const& last_error_reset, size_t const global_state_index)
287{ // An extra function to grab the PTD while a GetLastError() reset guard is already in place
288 // and the global state index is already known.
289
290 return internal_getptd_noexit(last_error_reset, global_state_index);
291}
292
294{
295 return internal_getptd_noexit();
296}
297
299{
301 if (!ptd)
302 {
303 abort();
304 }
305
306 return ptd;
307}
308
310{
311 __acrt_ptd* const ptd_head = internal_get_ptd_head();
312 if (!ptd_head)
313 {
314 abort();
315 }
316
317 return ptd_head;
318}
319
320
321
322extern "C" void __cdecl __acrt_freeptd()
323{
324 __acrt_ptd* const ptd_head = try_get_ptd_head();
325 if (!ptd_head)
326 {
327 return;
328 }
329
331 destroy_fls(ptd_head);
332}
333
334
335
336// These functions are simply wrappers around the Windows API functions.
337extern "C" unsigned long __cdecl __threadid()
338{
339 return GetCurrentThreadId();
340}
341
343{
344 return reinterpret_cast<uintptr_t>(GetCurrentThread());
345}
#define __cdecl
Definition: accygwin.h:79
void __cdecl __acrt_release_locale_ref(__crt_locale_data *)
BOOL WINAPI __acrt_FlsFree(_In_ DWORD dwFlsIndex)
@ __acrt_locale_lock
@ __acrt_multibyte_cp_lock
void __cdecl __acrt_free_locale(__crt_locale_data *)
BOOL WINAPI __acrt_FlsSetValue(_In_ DWORD dwFlsIndex, _In_opt_ PVOID lpFlsData)
__crt_locale_data __acrt_initial_locale_data
Definition: nlsdata.cpp:92
struct __crt_signal_action_t const __acrt_exception_action_table[]
void __cdecl __acrt_add_locale_ref(__crt_locale_data *)
__crt_multibyte_data __acrt_initial_multibyte_data
Definition: mbctype.cpp:42
#define _GLOBAL_LOCALE_BIT
PVOID WINAPI __acrt_FlsGetValue(_In_ DWORD dwFlsIndex)
DWORD WINAPI __acrt_FlsAlloc(_In_opt_ PFLS_CALLBACK_FUNCTION lpCallback)
result_buffer_count char *const _In_ int const _In_ bool const _In_ unsigned const _In_ STRFLT const _In_ bool const _Inout_ __crt_cached_ptd_host &ptd throw()
Definition: cvt.cpp:119
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
unsigned long DWORD
Definition: ntddk_ex.h:95
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define abort()
Definition: i386-dis.c:34
#define _free_crt
long __cdecl _InterlockedIncrement(_Interlocked_operand_ long volatile *_Addend)
long __cdecl _InterlockedDecrement(_Interlocked_operand_ long volatile *_Addend)
if(dx< 0)
Definition: linetemp.h:194
unsigned int uintptr_t
Definition: intrin.h:47
__crt_state_management::dual_state_global< __crt_locale_data * > __acrt_current_locale_data
Definition: nlsdata.cpp:132
#define _Success_(c)
Definition: no_sal2.h:84
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
#define L(x)
Definition: ntvdm.h:50
static void __cdecl destroy_ptd_array(__acrt_ptd *const ptd)
static void __cdecl construct_ptd(__acrt_ptd *const ptd, __crt_locale_data **const locale_data)
__acrt_ptd *__cdecl __acrt_getptd_noexit()
static void __cdecl replace_current_thread_locale_nolock(__acrt_ptd *const ptd, __crt_locale_data *const new_locale_info)
uintptr_t __cdecl __threadhandle()
static void WINAPI destroy_fls(void *)
__acrt_ptd *__cdecl __acrt_getptd_head()
static void __cdecl construct_ptd_array(__acrt_ptd *const ptd)
static __forceinline __acrt_ptd *__cdecl internal_getptd_noexit()
__acrt_ptd *__cdecl __acrt_getptd()
static unsigned long __acrt_flsindex
unsigned long __cdecl __threadid()
bool __cdecl __acrt_uninitialize_ptd(bool)
static void __cdecl destroy_ptd(__acrt_ptd *const ptd)
void __cdecl __acrt_freeptd()
static __forceinline __acrt_ptd * try_get_ptd_head()
bool __cdecl __acrt_initialize_ptd()
__acrt_ptd *__cdecl __acrt_getptd_noexit_explicit(__crt_scoped_get_last_error_reset const &last_error_reset, size_t const global_state_index)
#define SIZE_MAX
Definition: compat.h:66
static PIXELFORMATDESCRIPTOR pfd
Definition: ssstars.c:67
HANDLE WINAPI GetCurrentThread(void)
Definition: proc.c:1148
#define FLS_OUT_OF_INDEXES
Definition: winbase.h:602
DWORD WINAPI GetCurrentThreadId(void)
Definition: thread.c:459
#define WINAPI
Definition: msvc.h:6