mirror of
https://github.com/reactos/reactos.git
synced 2025-05-30 14:39:46 +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/iswblank.c
|
||||||
misc/ofmt_stub.c)
|
misc/ofmt_stub.c)
|
||||||
|
|
||||||
if(NOT MSVC)
|
if(MSVC)
|
||||||
|
list(APPEND MSVCRTEX_SOURCE
|
||||||
|
startup/threadSafeInit.c)
|
||||||
|
else()
|
||||||
list(APPEND MSVCRTEX_SOURCE
|
list(APPEND MSVCRTEX_SOURCE
|
||||||
startup/pseudo-reloc.c
|
startup/pseudo-reloc.c
|
||||||
startup/pseudo-reloc-list.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