mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[CRT] Implement thread/fiber safe support for MSVC and Clang-CL
This is the most trivial (but also most efficient) implementation possible. Should be good enough for now.
This commit is contained in:
parent
dc77e7d379
commit
2a5bf96891
2 changed files with 64 additions and 1 deletions
|
@ -41,7 +41,10 @@ list(APPEND MSVCRTEX_SOURCE
|
|||
misc/iswblank.c
|
||||
misc/ofmt_stub.c)
|
||||
|
||||
if(NOT MSVC)
|
||||
if(MSVC)
|
||||
list(APPEND MSVCRTEX_SOURCE
|
||||
startup/threadSafeInit.c)
|
||||
else()
|
||||
list(APPEND MSVCRTEX_SOURCE
|
||||
startup/pseudo-reloc.c
|
||||
startup/pseudo-reloc-list.c)
|
||||
|
|
60
sdk/lib/crt/startup/threadSafeInit.c
Normal file
60
sdk/lib/crt/startup/threadSafeInit.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* PROJECT: ReactOS CRT library
|
||||
* LICENSE: CC0-1.0 (https://spdx.org/licenses/CC0-1.0)
|
||||
* PURPOSE: Thread safe initialization support routines for MSVC and Clang-CL
|
||||
* COPYRIGHT: Copyright 2019 Timo Kreuzer (timo.kreuzer@reactos.org)
|
||||
*/
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
int _stdcall SwitchToThread(void);
|
||||
|
||||
unsigned int _tls_array;
|
||||
unsigned int _tls_index;
|
||||
long _Init_global_epoch;
|
||||
long _Init_thread_epoch;
|
||||
|
||||
/*
|
||||
This function tries to acquire a lock on the initialization for the static
|
||||
variable by changing the value saved in *ptss to -1. If *ptss is 0, the
|
||||
variable was not initialized yet and the function tries to set it to -1.
|
||||
If that succeeds, the function will return. If the value is already -1,
|
||||
another thread is in the process of doing the initialization and we
|
||||
wait for it. If it is any other value the initialization is complete.
|
||||
After returning the compiler generated code will check the value:
|
||||
if it is -1 it will continue with the initialization, otherwise the
|
||||
initialization must be complete and will be skipped.
|
||||
*/
|
||||
void
|
||||
_Init_thread_header(volatile int* ptss)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
/* Try to acquire the first initialization lock */
|
||||
int oldTss = _InterlockedCompareExchange((long*)ptss, -1, 0);
|
||||
if (oldTss == -1)
|
||||
{
|
||||
/* Busy, wait for the other thread to do the initialization */
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Either we acquired the lock and the caller will do the initializaion
|
||||
or the initialization is complete and the caller will skip it */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_Init_thread_footer(volatile int* ptss)
|
||||
{
|
||||
/* Initialization is complete */
|
||||
*ptss = _InterlockedIncrement(&_Init_global_epoch);
|
||||
}
|
||||
|
||||
void
|
||||
_Init_thread_abort(volatile int* ptss)
|
||||
{
|
||||
/* Abort the initialization */
|
||||
_InterlockedAnd((volatile long*)ptss, 0);
|
||||
}
|
Loading…
Reference in a new issue