https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2a5bf9689144d2ec78f41…
commit 2a5bf9689144d2ec78f4114d4d0f43758399f427
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Mon Feb 4 00:06:35 2019 +0100
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Tue Feb 12 19:31:33 2019 +0100
[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.
---
sdk/lib/crt/msvcrtex.cmake | 5 ++-
sdk/lib/crt/startup/threadSafeInit.c | 60 ++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/sdk/lib/crt/msvcrtex.cmake b/sdk/lib/crt/msvcrtex.cmake
index cd058cf089..c46751007a 100644
--- a/sdk/lib/crt/msvcrtex.cmake
+++ b/sdk/lib/crt/msvcrtex.cmake
@@ -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)
diff --git a/sdk/lib/crt/startup/threadSafeInit.c b/sdk/lib/crt/startup/threadSafeInit.c
new file mode 100644
index 0000000000..4ceb5ded6d
--- /dev/null
+++ b/sdk/lib/crt/startup/threadSafeInit.c
@@ -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(a)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);
+}