Remove always defined FEATURE_CORECLR
[platform/upstream/coreclr.git] / src / utilcode / clrhost.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5
6 //
7
8 #include "stdafx.h"
9
10 #include "unsafe.h"
11 #include "clrhost.h"
12 #include "utilcode.h"
13 #include "ex.h"
14 #include "hostimpl.h"
15 #include "clrnt.h"
16 #include "contract.h"
17 #include "tls.h"
18
19 CoreClrCallbacks g_CoreClrCallbacks;
20
21
22 // In some cirumstance (e.g, the thread suspecd another thread), allocation on heap
23 // could cause dead lock. We use a counter in TLS to indicate the current thread is not allowed
24 // to do heap allocation.
25 //In cases where CLRTlsInfo doesn't exist and we still want to track CantAlloc info (this is important to 
26 //stress log), We use a global counter. This introduces the problem where one thread could disable allocation 
27 //for another thread, but the cases should be rare (we limit the use to stress log for now) and the period 
28 //should (MUST) be short
29 //only stress log check this counter
30
31 struct CantAllocThread
32 {
33     PVOID m_fiberId;
34     LONG  m_CantCount;
35 };
36
37 #define MaxCantAllocThreadNum 100
38 static CantAllocThread g_CantAllocThreads[MaxCantAllocThreadNum] = {};
39 static Volatile<LONG> g_CantAllocStressLogCount = 0;
40
41 void IncCantAllocCount()
42 {
43     size_t count = 0;
44     if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
45     {
46         _ASSERTE (count >= 0);
47         ClrFlsSetValue(TlsIdx_CantAllocCount,  (LPVOID)(count+1));
48         return;
49     }
50     PVOID fiberId = ClrTeb::GetFiberPtrId();
51     for (int i = 0; i < MaxCantAllocThreadNum; i ++)
52     {
53         if (g_CantAllocThreads[i].m_fiberId == fiberId)
54         {
55             g_CantAllocThreads[i].m_CantCount ++;
56             return;
57         }
58     }
59     for (int i = 0; i < MaxCantAllocThreadNum; i ++)
60     {
61         if (g_CantAllocThreads[i].m_fiberId == NULL)
62         {
63             if (InterlockedCompareExchangeT(&g_CantAllocThreads[i].m_fiberId, fiberId, NULL) == NULL)
64             {
65                 _ASSERTE(g_CantAllocThreads[i].m_CantCount == 0);
66                 g_CantAllocThreads[i].m_CantCount = 1;
67                 return;
68             }
69         }
70     }
71     count = InterlockedIncrement (&g_CantAllocStressLogCount);
72     _ASSERTE (count >= 1);
73     return;
74 }
75
76 void DecCantAllocCount()
77 {
78     size_t count = 0;
79     if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
80     {
81         if (count > 0)
82         {
83             ClrFlsSetValue(TlsIdx_CantAllocCount,  (LPVOID)(count-1));
84             return;
85         }
86     }
87     PVOID fiberId = ClrTeb::GetFiberPtrId();
88     for (int i = 0; i < MaxCantAllocThreadNum; i ++)
89     {
90         if (g_CantAllocThreads[i].m_fiberId == fiberId)
91         {
92             _ASSERTE (g_CantAllocThreads[i].m_CantCount > 0);
93             g_CantAllocThreads[i].m_CantCount --;
94             if (g_CantAllocThreads[i].m_CantCount == 0)
95             {
96                 g_CantAllocThreads[i].m_fiberId = NULL;
97             }
98             return;
99         }
100     }
101     _ASSERTE (g_CantAllocStressLogCount > 0);
102     InterlockedDecrement (&g_CantAllocStressLogCount);
103     return;
104
105 }
106
107 // for stress log the rule is more restrict, we have to check the global counter too
108 BOOL IsInCantAllocStressLogRegion()
109 {
110     size_t count = 0;
111     if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
112     {
113         if (count > 0)
114         {
115             return true;
116         }
117     }
118     PVOID fiberId = ClrTeb::GetFiberPtrId();
119     for (int i = 0; i < MaxCantAllocThreadNum; i ++)
120     {
121         if (g_CantAllocThreads[i].m_fiberId == fiberId)
122         {
123             _ASSERTE (g_CantAllocThreads[i].m_CantCount > 0);
124             return true;
125         }
126     }
127
128     return g_CantAllocStressLogCount > 0;
129
130 }
131
132
133 #ifdef FAILPOINTS_ENABLED
134 typedef int (*FHashStack) ();
135
136 static FHashStack fHashStack = 0;
137 static _TEB *HashStackSetupThread = NULL;
138 static _TEB *RFSCustomDataSetupThread = NULL;
139
140 static void SetupHashStack ()
141 {
142     CANNOT_HAVE_CONTRACT;
143
144     FHashStack oldValue = InterlockedCompareExchangeT(&fHashStack, 
145         reinterpret_cast<FHashStack>(1), reinterpret_cast<FHashStack>(0));
146     if ((size_t) oldValue >= 2) {
147         return;
148     }
149     else if ((size_t) oldValue == 0) {
150         // We are the first thread to initialize
151         HashStackSetupThread = NtCurrentTeb();
152
153         if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HashStack) == 0) {
154             fHashStack = (FHashStack) 2;
155             return;
156         }
157
158         PAL_TRY(void *, unused, NULL) {
159             FHashStack func;
160             HMODULE hmod = LoadLibraryExA ("mscorrfs.dll", NULL, 0);
161             if (hmod) {
162                 func = (FHashStack)GetProcAddress (hmod, "HashStack");
163                 if (func == 0) {
164                     func = (FHashStack)2;
165                 }
166             }
167             else
168                 func = (FHashStack)2;
169             fHashStack = func;
170         }
171         PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
172         {
173             fHashStack = (FHashStack) 2;
174         }
175         PAL_ENDTRY;
176     }
177     else if (NtCurrentTeb() == HashStackSetupThread) {
178         // We get here while initializing
179         return;
180     }
181     else {
182         // All other threads will wait
183         while (fHashStack == (FHashStack) 1) {
184             ClrSleepEx (100, FALSE);
185         }
186     }
187 }
188
189 int RFS_HashStack ()
190 {
191     CANNOT_HAVE_CONTRACT;
192
193     if ((size_t)fHashStack < 2) {
194         SetupHashStack ();
195     }
196
197     if ((size_t)fHashStack <= 2) {
198         return 0;
199     }
200     else
201         return fHashStack ();
202 }
203
204 #endif // FAILPOINTS_ENABLED
205
206
207
208 //-----------------------------------------------------------------------------------
209 // This is the approved way to get a module handle to mscorwks.dll (or coreclr.dll).
210 // Never call GetModuleHandle(mscorwks) yourself as this will break side-by-side inproc.
211 //
212 // This function is safe to call before or during CRT initialization. It can not
213 // legally return NULL (it only does so in the case of a broken build invariant.)
214 // 
215 // TODO puCLR SxS utilcode work: Since this is never supposed to return NULL, it should
216 // not be present in SELF_NO_HOST builds of utilcode where there isn't necessarily a
217 // CLR in the process.  We should also ASSERT that GetModuleHandleA isn't returning
218 // NULL below - we've probably been getting away with this in SELF_NO_HOST cases like
219 // mscordbi.dll.
220 //-----------------------------------------------------------------------------------
221 HMODULE GetCLRModule ()
222 {
223     //! WARNING: At the time this function is invoked, the C Runtime has NOT been fully initialized, let alone the CLR.
224     //! So don't put in a runtime contract and don't invoke other functions in the CLR (not even _ASSERTE!) 
225
226     STATIC_CONTRACT_NOTHROW;
227     STATIC_CONTRACT_SO_TOLERANT;
228     STATIC_CONTRACT_SUPPORTS_DAC; // DAC can call in here since we initialize the SxS callbacks in ClrDataAccess::Initialize.
229
230 #ifdef DACCESS_COMPILE
231     // For DAC, "g_CoreClrCallbacks" is populated in InitUtilCode when the latter is invoked
232     // from ClrDataAccess::Initialize alongwith a reference to a structure allocated in the 
233     // host-process address space.
234     //
235     // This function will be invoked in the host when DAC uses SEHException::GetHr that calls into
236     // IsComplusException, which calls into WasThrownByUs that calls GetCLRModule when EH SxS is enabled.
237     // However, this function can also be executed within the target space as well.
238     //
239     // Since DACCop gives the warning to DACize this global that, actually, would be used only
240     // in the respective address spaces and does not require marshalling, we need to ignore this
241     // warning.
242     DACCOP_IGNORE(UndacizedGlobalVariable, "g_CoreClrCallbacks has the dual mode DAC issue.");
243 #endif // DACCESS_COMPILE
244     VALIDATECORECLRCALLBACKS();
245
246     // This is the normal coreclr case - we return the module handle that was captured in our DllMain.
247 #ifdef DACCESS_COMPILE
248     // For DAC, "g_CoreClrCallbacks" is populated in InitUtilCode when the latter is invoked
249     // from ClrDataAccess::Initialize alongwith a reference to a structure allocated in the 
250     // host-process address space.
251     //
252     // This function will be invoked in the host when DAC uses SEHException::GetHr that calls into
253     // IsComplusException, which calls into WasThrownByUs that calls GetCLRModule when EH SxS is enabled.
254     // However, this function can also be executed within the target space as well.
255     //
256     // Since DACCop gives the warning to DACize this global that, actually, would be used only
257     // in the respective address spaces and does not require marshalling, we need to ignore this
258     // warning.
259     DACCOP_IGNORE(UndacizedGlobalVariable, "g_CoreClrCallbacks has the dual mode DAC issue.");
260 #endif // DACCESS_COMPILE
261     return g_CoreClrCallbacks.m_hmodCoreCLR;
262 }
263
264
265
266 #if defined(SELF_NO_HOST)
267
268 HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName)
269 {
270     WRAPPER_NO_CONTRACT;
271     return CLRLoadLibraryEx(lpLibFileName, NULL, 0);
272 }
273
274 HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
275 {
276     WRAPPER_NO_CONTRACT;
277     return WszLoadLibraryEx(lpLibFileName, hFile, dwFlags);
278 }
279
280 BOOL CLRFreeLibrary(HMODULE hModule)
281 {
282     WRAPPER_NO_CONTRACT;
283     return FreeLibrary(hModule);
284 }
285
286 #endif // defined(SELF_NO_HOST)
287
288
289 #if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
290
291 //-----------------------------------------------------------------------------------------------
292 // Imposes a new typeload level limit for the scope of the holder. Any attempt to load a type
293 // past that limit generates a contract violation assert.
294 //
295 // Do not invoke this directly. Invoke it through TRIGGERS_TYPE_LOAD or OVERRIDE_TYPE_LOAD_LEVEL_LIMIT.
296 //
297 // Arguments:
298 //     fConditional   - if FALSE, this holder is a nop - supports the MAYBE_* macros.
299 //     newLevel       - a value from classloadlevel.h - specifies the new max limit.
300 //     fEnforceLevelChangeDirection
301 //                    - if true,  implements TRIGGERS_TYPE_LOAD (level cap only allowed to decrease.)
302 //                      if false, implements OVERRIDE (level allowed to increase - may only be used
303 //                                                     by loader and only when recursion is structurally
304 //                                                     impossible.)
305 //     szFunction,
306 //     szFile,
307 //     lineNum        - records location of holder so we can print it in assertion boxes
308 //
309 // Assumptions:
310 //     ClrDebugState must have been set up (executing any contract will do this.)
311 //     Thread need *not* have a Thread* structure set up.
312 //
313 // Notes:
314 //     The holder withholds the assert if a LoadsTypeViolation suppress is in effect (but
315 //     still sets up the new limit.)
316 //
317 //     As with other contract annoations, however, the violation suppression is *lifted*
318 //     within the scope guarded by the holder itself.
319 //-----------------------------------------------------------------------------------------------
320 LoadsTypeHolder::LoadsTypeHolder(BOOL       fConditional,
321                                  UINT       newLevel,
322                                  BOOL       fEnforceLevelChangeDirection,
323                                  const char *szFunction,
324                                  const char *szFile,
325                                  int        lineNum
326                                )
327 {
328     // This fcn makes non-scoped changes to ClrDebugState so we cannot use a runtime CONTRACT here.
329     STATIC_CONTRACT_NOTHROW;
330     STATIC_CONTRACT_GC_NOTRIGGER;
331     STATIC_CONTRACT_FORBID_FAULT;
332
333
334     m_fConditional = fConditional;
335     if (m_fConditional)
336     {
337         m_pClrDebugState = CheckClrDebugState();
338         _ASSERTE(m_pClrDebugState);
339
340         m_oldClrDebugState = *m_pClrDebugState;
341
342         if (fEnforceLevelChangeDirection)
343         {
344             if (newLevel > m_pClrDebugState->GetMaxLoadTypeLevel())
345             {
346                 if (!( (LoadsTypeViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
347                 {
348                     CONTRACT_ASSERT("Illegal attempt to load a type beyond the current level limit.",
349                                     (m_pClrDebugState->GetMaxLoadTypeLevel() + 1) << Contract::LOADS_TYPE_Shift,
350                                     Contract::LOADS_TYPE_Mask,
351                                     szFunction,
352                                     szFile,
353                                     lineNum
354                                     );
355                 }
356             }
357         }
358
359         m_pClrDebugState->ViolationMaskReset(LoadsTypeViolation);
360         m_pClrDebugState->SetMaxLoadTypeLevel(newLevel);
361
362         m_contractStackRecord.m_szFunction      = szFunction;
363         m_contractStackRecord.m_szFile          = szFile;
364         m_contractStackRecord.m_lineNum         = lineNum;
365         m_contractStackRecord.m_testmask        = (Contract::ALL_Disabled & ~((UINT)(Contract::LOADS_TYPE_Mask))) | (((newLevel) + 1) << Contract::LOADS_TYPE_Shift);
366         m_contractStackRecord.m_construct       = fEnforceLevelChangeDirection ? "TRIGGERS_TYPE_LOAD" : "OVERRIDE_TYPE_LOAD_LEVEL_LIMIT";
367         m_contractStackRecord.m_pNext           = m_pClrDebugState->GetContractStackTrace();
368         m_pClrDebugState->SetContractStackTrace(&m_contractStackRecord);
369
370
371     }
372 } // LoadsTypeHolder::LoadsTypeHolder
373
374 //-----------------------------------------------------------------------------------------------
375 // Restores prior typeload level limit.
376 //-----------------------------------------------------------------------------------------------
377 LoadsTypeHolder::~LoadsTypeHolder()
378 {
379     // This fcn makes non-scoped changes to ClrDebugState so we cannot use a runtime CONTRACT here.
380     STATIC_CONTRACT_NOTHROW;
381     STATIC_CONTRACT_GC_NOTRIGGER;
382     STATIC_CONTRACT_FORBID_FAULT;
383
384
385     if (m_fConditional)
386     {
387         *m_pClrDebugState = m_oldClrDebugState;
388     }
389 }
390
391 #endif //defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
392
393
394 //--------------------------------------------------------------------------
395 // Side by side inproc support
396 //
397 // These are new abstractions designed to support loading multiple CLR
398 // versions in the same process.
399 //--------------------------------------------------------------------------
400
401
402 //--------------------------------------------------------------------------
403 // One-time initialized called by coreclr.dll in its dllmain.
404 //--------------------------------------------------------------------------
405 VOID InitUtilcode(CoreClrCallbacks const & cccallbacks)
406 {
407     //! WARNING: At the time this function is invoked, the C Runtime has NOT been fully initialized, let alone the CLR.
408     //! So don't put in a runtime contract and don't invoke other functions in the CLR (not even _ASSERTE!) 
409
410     LIMITED_METHOD_CONTRACT;
411
412     g_CoreClrCallbacks = cccallbacks;
413 }
414
415 CoreClrCallbacks const & GetClrCallbacks()
416 {
417     LIMITED_METHOD_CONTRACT;
418
419     VALIDATECORECLRCALLBACKS();
420     return g_CoreClrCallbacks;
421 }
422
423 #ifdef _DEBUG
424 void OnUninitializedCoreClrCallbacks()
425 {
426     // Supports DAC since it can be called from GetCLRModule which supports DAC as well.
427     LIMITED_METHOD_DAC_CONTRACT;
428     
429     // If you got here, the most likely cause of the failure is that you're loading some DLL
430     // (other than coreclr.dll) that links to utilcode.lib, or that you're using a nohost
431     // variant of utilcode.lib but hitting code that assumes there is a CLR in the process.
432     //
433     // Under FEATURE_CORECLR (and not SELF_NO_HOST), it is expected that coreclr.dll 
434     // is the ONLY dll that links to utilcode libraries.
435     //
436     // If you must introduce a new dll that links to utilcode.lib, it is your responsibility
437     // to ensure that that dll invoke InitUtilcode() and forward it the right data from the *correct*
438     // loaded instance of coreclr. And you'll have to do without the CRT being initialized.
439     //
440     // Can't use an _ASSERTE here because even that's broken if we get to this point.
441     MessageBoxW(0, 
442                 W("g_CoreClrCallbacks not initialized."),
443                 W("\n\n")
444                 W("You got here because the dll that included this copy of utilcode.lib ")
445                 W("did not call InitUtilcode() The most likely cause is that you're running ")
446                 W("a dll (other than coreclr.dll) that links to utilcode.lib.") 
447                 ,
448                 0);
449     _ASSERTE(FALSE);
450     DebugBreak();
451 }
452 #endif // _DEBUG
453