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// CRST.H
6//
7
8//
9// Debug-instrumented hierarchical critical sections.
10//
11//
12// The hierarchy:
13// --------------
14// The EE divides critical sections into numbered groups or "levels."
15// Crsts that guard the lowest level data structures that don't
16// use other services are grouped into the lowest-numbered levels.
17// The higher-numbered levels are reserved for high-level crsts
18// that guard broad swatches of code. Multiple groups can share the
19// same number to indicate that they're disjoint (their locks will never
20// nest.)
21//
22// The fundamental rule of the hierarchy that threads can only request
23// a crst whose level is lower than any crst currently held by the thread.
24// E.g. if a thread current holds a level-3 crst, he can try to enter
25// a level-2 crst, but not a level-4 crst, nor a different level-3
26// crst. This prevents the cyclic dependencies that lead to deadlock.
27//
28// For debugging purposes Crsts are all also grouped by a type (e.g.
29// CrstRemoting, the type of Crst used to synchronize certain remoting
30// operations). Each type maps to one level (though a level may map to
31// multiple types). The idea here is for the programmer to express Crst types
32// and their dependencies (e.g. a CrstClassInit instance may be acquired
33// while a CrstRemoting instance is already held) in a high level manner
34// while an external script handles the mechanical process of assigning
35// numerical levels to each type. See file:..\inc\CrstTypes.def for these high level
36// type definitions.
37//
38//
39// To create a crst:
40//
41// Crst *pcrst = new Crst(type);
42//
43// where "type" is one of the enums created in the auto-generated
44// file:..\inc\CrstTypes.h header file (matching the definition in
45// file:..\inc\CrstTypes.def).
46//
47// By default, crsts don't support nested enters by the same thread. If
48// you need reentrancy, use the alternate form:
49//
50// Crst *pcrst = new Crst(type, TRUE);
51//
52// Since reentrancies never block the caller, they're allowed to
53// "violate" the level ordering rule.
54//
55//
56// To enter/leave a crst:
57// ----------------------
58//
59//
60// pcrst->Enter();
61// pcrst->Leave();
62//
63// An assertion will fire on Enter() if a thread attempts to take locks
64// in the wrong order.
65//
66// Finally, a few DEBUG-only methods:
67//
68// To assert taking a crst won't violate level order:
69// --------------------------------------------------
70//
71// _ASSERTE(pcrst->IsSafeToTake());
72//
73// This is a good line to put at the start of any function that
74// enters a crst in some circumstances but not others. If it
75// always enters the crst, it's not necessary to call IsSafeToTake()
76// since Enter() does this for you.
77//
78// To assert that the current thread owns a crst:
79// --------------------------------------------------
80//
81// _ASSERTE(pcrst->OwnedByCurrentThread());
82
83
84
85#ifndef __crst_h__
86#define __crst_h__
87
88#include "util.hpp"
89#include "debugmacros.h"
90#include "log.h"
91
92#define ShutDown_Start 0x00000001
93#define ShutDown_Finalize1 0x00000002
94#define ShutDown_Finalize2 0x00000004
95#define ShutDown_Profiler 0x00000008
96#define ShutDown_COM 0x00000010
97#define ShutDown_SyncBlock 0x00000020
98#define ShutDown_IUnknown 0x00000040
99#define ShutDown_Phase2 0x00000080
100
101#ifndef DACCESS_COMPILE
102extern bool g_fProcessDetach;
103extern DWORD g_fEEShutDown;
104#endif
105// Total count of Crst lock of the type (Shutdown) that are currently in use
106extern Volatile<LONG> g_ShutdownCrstUsageCount;
107extern Volatile<LONG> g_fForbidEnterEE;
108
109// The CRST.
110class CrstBase
111{
112// The following classes and methods violate the requirement that Crst usage be
113// exception-safe, or they satisfy that requirement using techniques other than
114// Holder objects:
115friend class Thread;
116friend class ThreadStore;
117friend class ThreadSuspend;
118template <typename ELEMENT>
119friend class ListLockBase;
120template <typename ELEMENT>
121friend class ListLockEntryBase;
122//friend class CExecutionEngine;
123friend struct SavedExceptionInfo;
124friend void EEEnterCriticalSection(CRITSEC_COOKIE cookie);
125friend void EELeaveCriticalSection(CRITSEC_COOKIE cookie);
126friend class CodeVersionManager;
127
128friend class Debugger;
129friend class Crst;
130
131#ifdef FEATURE_DBGIPC_TRANSPORT_VM
132 // The debugger transport code uses a holder for its Crst, but it needs to share the holder implementation
133 // with its right side code as well (which can't see the Crst implementation and actually uses a
134 // CRITICAL_SECTION as the base lock). So make DbgTransportSession a friend here so we can use Enter() and
135 // Leave() in order to build a shared holder class.
136 friend class DbgTransportLock;
137#endif // FEATURE_DBGIPC_TRANSPORT_VM
138
139 // PendingTypeLoadEntry acquires the lock during construction before anybody has a chance to see it to avoid
140 // level violations.
141 friend class PendingTypeLoadEntry;
142
143public:
144#ifdef _DEBUG
145 enum NoLevelCheckFlag
146 {
147 CRST_NO_LEVEL_CHECK = 1,
148 CRST_LEVEL_CHECK = 0,
149 };
150#endif
151
152private:
153 // Some Crsts have a "shutdown" mode.
154 // A Crst in shutdown mode can only be taken / released by special
155 // (the helper / finalizer / shutdown) threads. Any other thread that tries to take
156 // the a "shutdown" crst will immediately release the Crst and instead just block forever.
157 //
158 // This prevents random threads from blocking the special threads from doing finalization on shutdown.
159 //
160 // Unfortunately, each Crst needs its own "shutdown" flag because we can't convert all the locks
161 // into shutdown locks at once. For eg, the TSL needs to suspend the runtime before
162 // converting to a shutdown lock. But it can't suspend the runtime while holding
163 // a UNSAFE_ANYMODE lock (such as the debugger-lock). So at least the debugger-lock
164 // and TSL need to be set separately.
165 //
166 // So for such Crsts, it's the caller's responsibility to detect if the crst is in
167 // shutdown mode, and if so, call this function after enter.
168 void ReleaseAndBlockForShutdownIfNotSpecialThread();
169
170 // Enter & Leave are deliberately private to force callers to use the
171 // Holder class. If you bypass the Holder class and access these members
172 // directly, your lock is not exception-safe.
173 //
174 // noLevelCheckFlag parameter lets you disable the crst level checking. This is
175 // very dangerous so it is only used when the constructor is the one performing
176 // the Enter (that attempt cannot possibly block since the current thread is
177 // the only one with a pointer to the crst.)
178 //
179 // For obvious reasons, this parameter must never be made public.
180 void Enter(INDEBUG(NoLevelCheckFlag noLevelCheckFlag = CRST_LEVEL_CHECK));
181 void Leave();
182
183 void SpinEnter();
184
185#ifndef DACCESS_COMPILE
186 DEBUG_NOINLINE static void AcquireLock(CrstBase *c) PUB {
187 WRAPPER_NO_CONTRACT;
188 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
189 c->Enter();
190 }
191
192 DEBUG_NOINLINE static void ReleaseLock(CrstBase *c) PUB {
193 WRAPPER_NO_CONTRACT;
194 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
195 c->Leave();
196 }
197
198#else // DACCESS_COMPILE
199
200 // in DAC builds, we don't actually acquire the lock, we just determine whether the LS
201 // already holds it. If so, we assume the data is inconsistent and throw an exception.
202 // Argument:
203 // input: c - the lock to be checked.
204 // Note: Throws
205 static void AcquireLock(CrstBase * c) PUB
206 {
207 SUPPORTS_DAC;
208 if (c->GetEnterCount() != 0)
209 {
210 ThrowHR(CORDBG_E_PROCESS_NOT_SYNCHRONIZED);
211 }
212 };
213
214 static void ReleaseLock(CrstBase *c) PUB
215 {
216 SUPPORTS_DAC;
217 };
218#endif // DACCESS_COMPILE
219
220public:
221 //-----------------------------------------------------------------
222 // Clean up critical section
223 // Safe to call multiple times or on non-initialized critical section
224 //-----------------------------------------------------------------
225 void Destroy();
226
227#ifdef _DEBUG
228 //-----------------------------------------------------------------
229 // Check if attempting to take the lock would violate level order.
230 //-----------------------------------------------------------------
231 BOOL IsSafeToTake();
232 // Checks that the lock can be taken
233 BOOL Debug_CanTake()
234 {
235 WRAPPER_NO_CONTRACT;
236 // Actually take the lock and release it immediatelly, that will do all the necessary checks
237 Enter();
238 Leave();
239 return TRUE;
240 }
241 void SetCantLeave(BOOL bSet)
242 {
243 LIMITED_METHOD_CONTRACT;
244 if (bSet)
245 FastInterlockIncrement(&m_cannotLeave);
246 else
247 {
248 _ASSERTE(m_cannotLeave);
249 FastInterlockDecrement(&m_cannotLeave);
250 }
251 };
252 //-----------------------------------------------------------------
253 // Is the current thread the owner?
254 //-----------------------------------------------------------------
255 BOOL OwnedByCurrentThread()
256 {
257 WRAPPER_NO_CONTRACT;
258#ifdef CROSSGEN_COMPILE
259 return TRUE;
260#else
261 return m_holderthreadid.IsCurrentThread();
262#endif
263 }
264
265 CrstBase *GetThreadsOwnedCrsts();
266 void SetThreadsOwnedCrsts(CrstBase *pCrst);
267
268 __declspec(noinline) EEThreadId GetHolderThreadId()
269 {
270 LIMITED_METHOD_CONTRACT;
271 return m_holderthreadid;
272 }
273
274#endif //_DEBUG
275
276 //-----------------------------------------------------------------
277 // For clients who want to assert whether they are in or out of the
278 // region.
279 //-----------------------------------------------------------------
280 UINT GetEnterCount()
281 {
282 LIMITED_METHOD_DAC_CONTRACT;
283#ifdef _DEBUG
284 return m_entercount;
285#else
286 return 0;
287#endif //_DEBUG
288 }
289
290protected:
291
292 VOID InitWorker(INDEBUG_COMMA(CrstType crstType) CrstFlags flags);
293
294#ifdef _DEBUG
295 void DebugInit(CrstType crstType, CrstFlags flags);
296 void DebugDestroy();
297#endif
298
299 union {
300 CRITICAL_SECTION m_criticalsection;
301 };
302
303 typedef enum
304 {
305 // Mask to indicate reserved flags
306 CRST_RESERVED_FLAGS_MASK = 0xC0000000,
307 // private flag to indicate initialized Crsts
308 CRST_INITIALIZED = 0x80000000,
309 // private flag to indicate Crst is OS Critical Section
310 CRST_OS_CRIT_SEC = 0x40000000,
311 // rest of the flags are CrstFlags
312 } CrstReservedFlags;
313 DWORD m_dwFlags; // Re-entrancy and same level
314#ifdef _DEBUG
315 UINT m_entercount; // # of unmatched Enters.
316 CrstType m_crstType; // Type enum (should have a descriptive name for debugging)
317 const char *m_tag; // Stringized form of the tag for easy debugging
318 int m_crstlevel; // what level is the crst in?
319 EEThreadId m_holderthreadid; // current holder (or NULL)
320 CrstBase *m_next; // link for global linked list
321 CrstBase *m_prev; // link for global linked list
322 Volatile<LONG> m_cannotLeave;
323
324 // Check for dead lock situation.
325 ULONG m_countNoTriggerGC;
326
327 void PostEnter ();
328 void PreEnter ();
329 void PreLeave ();
330#endif //_DEBUG
331
332private:
333
334 void SetOSCritSec ()
335 {
336 m_dwFlags |= CRST_OS_CRIT_SEC;
337 }
338 void ResetOSCritSec ()
339 {
340 m_dwFlags &= ~CRST_OS_CRIT_SEC;
341 }
342 BOOL IsOSCritSec ()
343 {
344 return m_dwFlags & CRST_OS_CRIT_SEC;
345 }
346 void SetCrstInitialized()
347 {
348 m_dwFlags |= CRST_INITIALIZED;
349 }
350
351 BOOL IsCrstInitialized()
352 {
353 return m_dwFlags & CRST_INITIALIZED;
354 }
355
356 BOOL CanBeTakenDuringShutdown()
357 {
358 return m_dwFlags & CRST_TAKEN_DURING_SHUTDOWN;
359 }
360
361 void SetFlags(CrstFlags f)
362 {
363 WRAPPER_NO_CONTRACT;
364 _ASSERTE(((CrstFlags)(f & ~CRST_RESERVED_FLAGS_MASK)) == f);
365 m_dwFlags = (f & ~CRST_RESERVED_FLAGS_MASK) | (m_dwFlags & CRST_RESERVED_FLAGS_MASK);
366 }
367
368 void ResetFlags() // resets the reserved and the CrstFlags
369 {
370 m_dwFlags = 0;
371 }
372 // ------------------------------- Holders ------------------------------
373 public:
374 //
375 // CrstHolder is optimized for the common use that takes the lock in constructor
376 // and releases it in destructor. Users that require all Holder features
377 // can use CrstHolderWithState.
378 //
379 class CrstHolder
380 {
381 CrstBase * m_pCrst;
382
383 public:
384 inline CrstHolder(CrstBase * pCrst)
385 : m_pCrst(pCrst)
386 {
387 WRAPPER_NO_CONTRACT;
388 AcquireLock(pCrst);
389 }
390
391 inline ~CrstHolder()
392 {
393 WRAPPER_NO_CONTRACT;
394
395 VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(HSV_ValidateMinimumStackReq);
396 ReleaseLock(m_pCrst);
397 }
398 };
399
400 // Note that the holders for CRSTs are used in extremely low stack conditions. Because of this, they
401 // aren't allowed to use more than HOLDER_CODE_MINIMUM_STACK_LIMIT pages of stack.
402 typedef DacHolder<CrstBase *, CrstBase::AcquireLock, CrstBase::ReleaseLock, 0, CompareDefault, HSV_ValidateMinimumStackReq> CrstHolderWithState;
403
404 // We have some situations where we're already holding a lock, and we need to release and reacquire the lock across a window.
405 // This is a dangerous construct because the backout code can block.
406 // Generally, it's better to use a regular CrstHolder, and then use the Release() / Acquire() methods on it.
407 // This just exists to convert legacy OS Critical Section patterns over to holders.
408 typedef DacHolder<CrstBase *, CrstBase::ReleaseLock, CrstBase::AcquireLock, 0, CompareDefault, HSV_ValidateMinimumStackReq> UnsafeCrstInverseHolder;
409};
410
411typedef CrstBase::CrstHolder CrstHolder;
412typedef CrstBase::CrstHolderWithState CrstHolderWithState;
413
414
415// The CRST.
416class Crst : public CrstBase
417{
418public:
419 void *operator new(size_t size)
420 {
421 WRAPPER_NO_CONTRACT;
422 return new BYTE[size];
423 }
424
425private:
426 // Do not use inplace operator new on Crst. A wrong destructor would be called if the constructor fails.
427 // Use CrstStatic or CrstExplicitInit instead of the inplace operator new.
428 void *operator new(size_t size, void *pInPlace);
429
430public:
431
432#ifndef DACCESS_COMPILE
433
434 //-----------------------------------------------------------------
435 // Constructor.
436 //-----------------------------------------------------------------
437 Crst(CrstType crstType, CrstFlags flags = CRST_DEFAULT)
438 {
439 WRAPPER_NO_CONTRACT;
440
441 // throw away the debug-only parameter in retail
442 InitWorker(INDEBUG_COMMA(crstType) flags);
443 }
444
445 //-----------------------------------------------------------------
446 // Destructor.
447 //-----------------------------------------------------------------
448 ~Crst()
449 {
450 WRAPPER_NO_CONTRACT;
451
452 Destroy();
453 };
454
455#else
456
457 Crst(CrstType crstType, CrstFlags flags = CRST_DEFAULT) {
458 LIMITED_METHOD_CONTRACT;
459 };
460
461#endif
462
463 Crst() {
464 LIMITED_METHOD_CONTRACT;
465 }
466};
467
468typedef DPTR(Crst) PTR_Crst;
469
470/* to be used as static variable - no constructor/destructor, assumes zero
471 initialized memory */
472class CrstStatic : public CrstBase
473{
474public:
475 VOID Init(CrstType crstType, CrstFlags flags = CRST_DEFAULT)
476 {
477 WRAPPER_NO_CONTRACT;
478
479 _ASSERTE((flags & CRST_INITIALIZED) == 0);
480
481 // throw away the debug-only parameter in retail
482 InitWorker(INDEBUG_COMMA(crstType) flags);
483 }
484
485 bool InitNoThrow(CrstType crstType, CrstFlags flags = CRST_DEFAULT)
486 {
487 CONTRACTL {
488 NOTHROW;
489 } CONTRACTL_END;
490
491 _ASSERTE((flags & CRST_INITIALIZED) == 0);
492
493 bool fSuccess = false;
494
495 EX_TRY
496 {
497 // throw away the debug-only parameter in retail
498 InitWorker(INDEBUG_COMMA(crstType) flags);
499 fSuccess = true;
500 }
501 EX_CATCH
502 {
503 }
504 EX_END_CATCH(SwallowAllExceptions)
505
506 return fSuccess;
507 }
508};
509
510/* to be used as regular variable when a explicit call to Init method is needed */
511class CrstExplicitInit : public CrstStatic
512{
513public:
514 CrstExplicitInit() {
515 m_dwFlags = 0;
516 }
517 ~CrstExplicitInit() {
518#ifndef DACCESS_COMPILE
519 Destroy();
520#endif
521 }
522};
523
524__inline BOOL IsOwnerOfCrst(LPVOID lock)
525{
526 WRAPPER_NO_CONTRACT;
527
528#ifdef _DEBUG
529 return ((Crst*)lock)->OwnedByCurrentThread();
530#else
531 // This function should not be called on free build.
532 DebugBreak();
533 return TRUE;
534#endif
535}
536
537#ifdef TEST_DATA_CONSISTENCY
538// used for test purposes. Determines if a crst is held.
539void DebugTryCrst(CrstBase * pLock);
540#endif
541#endif // __crst_h__
542
543
544