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.
19 CoreClrCallbacks g_CoreClrCallbacks;
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
31 struct CantAllocThread
37 #define MaxCantAllocThreadNum 100
38 static CantAllocThread g_CantAllocThreads[MaxCantAllocThreadNum] = {};
39 static Volatile<LONG> g_CantAllocStressLogCount = 0;
41 void IncCantAllocCount()
44 if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
46 _ASSERTE (count >= 0);
47 ClrFlsSetValue(TlsIdx_CantAllocCount, (LPVOID)(count+1));
50 PVOID fiberId = ClrTeb::GetFiberPtrId();
51 for (int i = 0; i < MaxCantAllocThreadNum; i ++)
53 if (g_CantAllocThreads[i].m_fiberId == fiberId)
55 g_CantAllocThreads[i].m_CantCount ++;
59 for (int i = 0; i < MaxCantAllocThreadNum; i ++)
61 if (g_CantAllocThreads[i].m_fiberId == NULL)
63 if (InterlockedCompareExchangeT(&g_CantAllocThreads[i].m_fiberId, fiberId, NULL) == NULL)
65 _ASSERTE(g_CantAllocThreads[i].m_CantCount == 0);
66 g_CantAllocThreads[i].m_CantCount = 1;
71 count = InterlockedIncrement (&g_CantAllocStressLogCount);
72 _ASSERTE (count >= 1);
76 void DecCantAllocCount()
79 if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
83 ClrFlsSetValue(TlsIdx_CantAllocCount, (LPVOID)(count-1));
87 PVOID fiberId = ClrTeb::GetFiberPtrId();
88 for (int i = 0; i < MaxCantAllocThreadNum; i ++)
90 if (g_CantAllocThreads[i].m_fiberId == fiberId)
92 _ASSERTE (g_CantAllocThreads[i].m_CantCount > 0);
93 g_CantAllocThreads[i].m_CantCount --;
94 if (g_CantAllocThreads[i].m_CantCount == 0)
96 g_CantAllocThreads[i].m_fiberId = NULL;
101 _ASSERTE (g_CantAllocStressLogCount > 0);
102 InterlockedDecrement (&g_CantAllocStressLogCount);
107 // for stress log the rule is more restrict, we have to check the global counter too
108 BOOL IsInCantAllocStressLogRegion()
111 if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
118 PVOID fiberId = ClrTeb::GetFiberPtrId();
119 for (int i = 0; i < MaxCantAllocThreadNum; i ++)
121 if (g_CantAllocThreads[i].m_fiberId == fiberId)
123 _ASSERTE (g_CantAllocThreads[i].m_CantCount > 0);
128 return g_CantAllocStressLogCount > 0;
133 #ifdef FAILPOINTS_ENABLED
134 typedef int (*FHashStack) ();
136 static FHashStack fHashStack = 0;
137 static _TEB *HashStackSetupThread = NULL;
138 static _TEB *RFSCustomDataSetupThread = NULL;
140 static void SetupHashStack ()
142 CANNOT_HAVE_CONTRACT;
144 FHashStack oldValue = InterlockedCompareExchangeT(&fHashStack,
145 reinterpret_cast<FHashStack>(1), reinterpret_cast<FHashStack>(0));
146 if ((size_t) oldValue >= 2) {
149 else if ((size_t) oldValue == 0) {
150 // We are the first thread to initialize
151 HashStackSetupThread = NtCurrentTeb();
153 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HashStack) == 0) {
154 fHashStack = (FHashStack) 2;
158 PAL_TRY(void *, unused, NULL) {
160 HMODULE hmod = LoadLibraryExA ("mscorrfs.dll", NULL, 0);
162 func = (FHashStack)GetProcAddress (hmod, "HashStack");
164 func = (FHashStack)2;
168 func = (FHashStack)2;
171 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
173 fHashStack = (FHashStack) 2;
177 else if (NtCurrentTeb() == HashStackSetupThread) {
178 // We get here while initializing
182 // All other threads will wait
183 while (fHashStack == (FHashStack) 1) {
184 ClrSleepEx (100, FALSE);
191 CANNOT_HAVE_CONTRACT;
193 if ((size_t)fHashStack < 2) {
197 if ((size_t)fHashStack <= 2) {
201 return fHashStack ();
204 #endif // FAILPOINTS_ENABLED
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.
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.)
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
220 //-----------------------------------------------------------------------------------
221 HMODULE GetCLRModule ()
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!)
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.
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.
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.
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
242 DACCOP_IGNORE(UndacizedGlobalVariable, "g_CoreClrCallbacks has the dual mode DAC issue.");
243 #endif // DACCESS_COMPILE
244 VALIDATECORECLRCALLBACKS();
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.
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.
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
259 DACCOP_IGNORE(UndacizedGlobalVariable, "g_CoreClrCallbacks has the dual mode DAC issue.");
260 #endif // DACCESS_COMPILE
261 return g_CoreClrCallbacks.m_hmodCoreCLR;
266 #if defined(SELF_NO_HOST)
268 HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName)
271 return CLRLoadLibraryEx(lpLibFileName, NULL, 0);
274 HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
277 return WszLoadLibraryEx(lpLibFileName, hFile, dwFlags);
280 BOOL CLRFreeLibrary(HMODULE hModule)
283 return FreeLibrary(hModule);
286 #endif // defined(SELF_NO_HOST)
289 #if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
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.
295 // Do not invoke this directly. Invoke it through TRIGGERS_TYPE_LOAD or OVERRIDE_TYPE_LOAD_LEVEL_LIMIT.
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
307 // lineNum - records location of holder so we can print it in assertion boxes
310 // ClrDebugState must have been set up (executing any contract will do this.)
311 // Thread need *not* have a Thread* structure set up.
314 // The holder withholds the assert if a LoadsTypeViolation suppress is in effect (but
315 // still sets up the new limit.)
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,
322 BOOL fEnforceLevelChangeDirection,
323 const char *szFunction,
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;
334 m_fConditional = fConditional;
337 m_pClrDebugState = CheckClrDebugState();
338 _ASSERTE(m_pClrDebugState);
340 m_oldClrDebugState = *m_pClrDebugState;
342 if (fEnforceLevelChangeDirection)
344 if (newLevel > m_pClrDebugState->GetMaxLoadTypeLevel())
346 if (!( (LoadsTypeViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
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,
359 m_pClrDebugState->ViolationMaskReset(LoadsTypeViolation);
360 m_pClrDebugState->SetMaxLoadTypeLevel(newLevel);
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);
372 } // LoadsTypeHolder::LoadsTypeHolder
374 //-----------------------------------------------------------------------------------------------
375 // Restores prior typeload level limit.
376 //-----------------------------------------------------------------------------------------------
377 LoadsTypeHolder::~LoadsTypeHolder()
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;
387 *m_pClrDebugState = m_oldClrDebugState;
391 #endif //defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
394 //--------------------------------------------------------------------------
395 // Side by side inproc support
397 // These are new abstractions designed to support loading multiple CLR
398 // versions in the same process.
399 //--------------------------------------------------------------------------
402 //--------------------------------------------------------------------------
403 // One-time initialized called by coreclr.dll in its dllmain.
404 //--------------------------------------------------------------------------
405 VOID InitUtilcode(CoreClrCallbacks const & cccallbacks)
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!)
410 LIMITED_METHOD_CONTRACT;
412 g_CoreClrCallbacks = cccallbacks;
415 CoreClrCallbacks const & GetClrCallbacks()
417 LIMITED_METHOD_CONTRACT;
419 VALIDATECORECLRCALLBACKS();
420 return g_CoreClrCallbacks;
424 void OnUninitializedCoreClrCallbacks()
426 // Supports DAC since it can be called from GetCLRModule which supports DAC as well.
427 LIMITED_METHOD_DAC_CONTRACT;
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.
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.
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.
440 // Can't use an _ASSERTE here because even that's broken if we get to this point.
442 W("g_CoreClrCallbacks not initialized."),
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.")