https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2a5bf9689144d2ec78f4114d4d0f43758399f427

commit 2a5bf9689144d2ec78f4114d4d0f43758399f427
Author:     Timo Kreuzer <[email protected]>
AuthorDate: Mon Feb 4 00:06:35 2019 +0100
Commit:     Timo Kreuzer <[email protected]>
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 ([email protected])
+ */
+
+#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);
+}

Reply via email to