1 /***
2 *_vcclrit.h
3 *
4 *           Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 *           This file defined the functions and variables used by users
8 *           to initialize the CRT and the dll in IJW scenarios. It is no longer
9 *           necessary to use this file and the functions it contains because
10 *           CRT initialization no longer causes managed code to execute
11 *           under the loader lock. It is now possible to use the CRT in
12 *           the standard way without problems. This header is shipped for
13 *           compatibility with the previous version only.
14 *
15 ****/
16
17 #pragma once
18
19 #ifndef __midl
20 #ifndef _MSC_EXTENSIONS
21 #error ERROR: This initialisation code cannot be used with /Za
22 #endif
23
24 #ifdef _M_CEE_PURE
25 #error ERROR: This code is not useful for /clr:pure mode. Remove the include.
26 #endif
27
28 #include <crtwrn.h>
29 #include <windows.h>
30
31 #if !defined(_CRT_VCCLRIT_NO_DEPRECATE)
32       #define _CRT_VCCLRIT_DEPRECATE _CRT_DEPRECATE_TEXT("These manual initialisation functions (plus link /noentry) are no longer appropriate for managed code DLLs. Instead, use a normal DLL entrypoint. See online help for more information.")
33       #pragma _CRT_WARNING( _VCCLRIT_DEPRECATED )
34 #else
35       #define _CRT_VCCLRIT_DEPRECATE 
36 #endif
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41
42 extern IMAGE_DOS_HEADER __ImageBase;
43
44 BOOL WINAPI _DllMainCRTStartup(
45              HANDLE  _HDllHandle,
46              DWORD     _DwReason,
47              LPVOID  _Lpreserved
48              );
49
50 typedef enum {
51       __uninitialized,
52       __initializing,
53       __NSinitialized /* Renamed */
54 } __enative_startup_state;
55
56 extern __enative_startup_state __native_startup_state;
57 extern void *__native_startup_lock;
58 extern volatile unsigned int __native_vcclrit_reason;
59 #define __NO_REASON      0xffffffff      /* maximum unsigned int value */
60 #ifdef __cplusplus
61 }
62 #endif
63
64 #ifdef __cplusplus
65 #define __USE_GLOBAL_NAMESPACE(X)     (::X)
66 #define __THROW throw()
67 #define __REINTERPRET_CAST(T) reinterpret_cast<T>
68 #define __STATIC_CAST(T) static_cast<T>
69 #define __INLINE inline
70 #else
71 /* deliberately no parens here so we don't suppress macro expansion */
72 #define __USE_GLOBAL_NAMESPACE(X)     X
73 #define __THROW 
74 #define __REINTERPRET_CAST(T)     (T)
75 #define __STATIC_CAST(T)             (T)
76 #define __INLINE __inline
77 #endif
78
79 #ifdef _M_IX86
80 /* System version has problems especially for /Wp64 */
81 __INLINE void* WINAPI _CrtInterlockedExchangePointer(void** pp, void* pNew) __THROW
82 {
83              return( __REINTERPRET_CAST(void*)(__STATIC_CAST(LONG_PTR)(__USE_GLOBAL_NAMESPACE(InterlockedExchange)(__REINTERPRET_CAST(LONG*)(pp), __STATIC_CAST(LONG)(__REINTERPRET_CAST(LONG_PTR)(pNew))))) );
84 }
85 #else
86 #define _CrtInterlockedExchangePointer(p, n) InterlockedExchangePointer(p, n)
87 #endif
88
89 /*
90 Used to lock 
91 */
92 _CRT_VCCLRIT_DEPRECATE
93 __declspec( selectany ) LONG  volatile __lock_handle = 0;
94
95 /*
96 Init called
97 */
98 _CRT_VCCLRIT_DEPRECATE
99 __declspec(selectany) BOOL volatile __initialized = FALSE;
100
101 /*
102 Term called
103 */
104 _CRT_VCCLRIT_DEPRECATE
105 __declspec( selectany ) BOOL volatile __terminated = FALSE;
106
107 _CRT_VCCLRIT_DEPRECATE
108 __inline BOOL WINAPI __crt_dll_initialize()
109 {
110       /*
111       Try to make the variable names unique, so that the variables don't even clash with macros.
112       */
113       static BOOL volatile (__retval) = FALSE;
114       static void * volatile (__lockFiberId) = 0;
115       void * volatile (__currentFiberId) = ((PNT_TIB)__USE_GLOBAL_NAMESPACE(NtCurrentTeb)())->StackBase;
116       int (__int_var)=0;
117       int __nested=FALSE;
118       
119       /*
120       Take Lock, This is needed for multithreaded scenario. Moreover the threads
121       need to wait here to make sure that the dll is initialized when they get
122       past this function.
123       */
124       while ( __USE_GLOBAL_NAMESPACE(InterlockedExchange)( &(__lock_handle), 1) == 1 )
125              {
126              ++(__int_var);
127              if ((__lockFiberId) == (__currentFiberId)) 
128              {
129                     return TRUE;
130              }
131                           __USE_GLOBAL_NAMESPACE(Sleep)( (__int_var)>1000?100:0 );
132
133              /*
134              If you hang in this loop, this implies that your dllMainCRTStartup is hung on another
135              thread. The most likely cause of this is a hang in one of your static constructors or
136              destructors.
137              */
138              }
139       /*
140       Note that we don't really need any interlocked stuff here as the writes are always
141       in the lock. Only reads are outside the lock.
142       */
143       (__lockFiberId) = (__currentFiberId);
144       __try {
145       
146              void * __lock_free=0;
147              while((__lock_free=InterlockedCompareExchangePointer(&__native_startup_lock, __currentFiberId, 0))!=0)
148              {
149                     if(__lock_free==__currentFiberId)
150                     {
151                           __nested=TRUE;
152                           break;
153                     }
154
155                     /* some other thread is running native startup/shutdown during a cctor/domain unload. 
156                     Should only happen if this DLL was built using the Everett-compat loader lock fix in vcclrit.h
157                     */
158                     /* wait for the other thread to complete init before we return */
159                     Sleep(1000);
160              }
161
162              if ( (__terminated) == TRUE )
163              {
164                     (__retval) = FALSE;
165              }
166              else if ( (__initialized) == FALSE )
167              {
168                     /* cctor may have initialized native code already */
169                     if (__native_startup_state == __uninitialized)
Lines 170 ... 179 are skipped.
180                           (__initialized) = TRUE;
181                     }
182              }
183
184       } __finally {
185              /* revert the __lockFiberId */
186              (__lockFiberId) = 0;
187              /* Release Lock */
188              __USE_GLOBAL_NAMESPACE(InterlockedExchange)( &(__lock_handle), 0 );
189              if(!__nested)
190              {
191                     _CrtInterlockedExchangePointer( &(__native_startup_lock), 0 );
192              }
193       }
194       return (__retval);
195 }
196
197 _CRT_VCCLRIT_DEPRECATE
198 __inline BOOL WINAPI __crt_dll_terminate()
199 {
200       static BOOL volatile (__retval) = TRUE;
201       static void * volatile (__lockFiberId) = 0;
202       void * volatile (__currentFiberId) = ((PNT_TIB)__USE_GLOBAL_NAMESPACE(NtCurrentTeb)())->StackBase;
203       int (__int_var)=0;
204       int __nested=FALSE;
205       
206       /* Take Lock, this lock is needed to keep Terminate in sync with Initialize. */
207       while ( __USE_GLOBAL_NAMESPACE(InterlockedExchange)( &(__lock_handle), 1) == 1 )
208              {
209              ++(__int_var);
210              if ((__lockFiberId) == (__currentFiberId)) 
211              {
212                     return TRUE;
213              }
214                           __USE_GLOBAL_NAMESPACE(Sleep)( (__int_var)>1000?100:0 );
215
216              /*
217              If you hang in this loop, this implies that your dllMainCRTStartup is hung on another
218              thread. The most likely cause of this is a hang in one of your static constructors or
219              destructors.
220              */
221       }
222       /*
223       Note that we don't really need any interlocked stuff here as the writes are always
224       in the lock. Only reads are outside the lock.
225       */
226       (__lockFiberId) = (__currentFiberId);
227       __try {
228
229              void *__lock_free=0;
230              while((__lock_free=__USE_GLOBAL_NAMESPACE(InterlockedCompareExchangePointer)(&__native_startup_lock, __REINTERPRET_CAST(void *)(__STATIC_CAST(INT_PTR)(1)), 0))!=0)
231              {
232                     /* some other thread is running native startup/shutdown during a cctor/domain unload. 
233                     Should only happen if this DLL was built using the Everett-compat loader lock fix in vcclrit.h
234                     */
235                     /* wait for the other thread to complete init before we return */
236                     Sleep(1000);
237              }
238              if ( (__initialized) == FALSE )
239              {
240                     (__retval) = FALSE;
241              }
242              else if ( (__terminated) == FALSE )
243              {
244                     __try
245                     {
246                           __native_vcclrit_reason = DLL_PROCESS_DETACH;
247                           (__retval) = _DllMainCRTStartup( ( HINSTANCE )( &(__ImageBase) ), DLL_PROCESS_DETACH, 0 );
248                     }
249                     __finally
250                     {
251                           __native_vcclrit_reason = __NO_REASON;
252                     }
253                     (__terminated) = TRUE;
254              }
255
256       } __finally {
257              /* revert the __lockFiberId */
258              (__lockFiberId) = 0;
259              /* Release Lock */
260              __USE_GLOBAL_NAMESPACE(InterlockedExchange)( &(__lock_handle), 0 );
261              if(!__nested)
262              {
263                     _CrtInterlockedExchangePointer( &(__native_startup_lock), 0 );
264              }
265       }
266       return (__retval);
267 }
268
269 #endif
270