diff options
Diffstat (limited to 'src/jit/utils.h')
-rw-r--r-- | src/jit/utils.h | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/jit/utils.h b/src/jit/utils.h index db7756809b..af9f2db009 100644 --- a/src/jit/utils.h +++ b/src/jit/utils.h @@ -578,4 +578,78 @@ public: static double round(double d); }; + +// The CLR requires that critical section locks be initialized via its ClrCreateCriticalSection API...but +// that can't be called until the CLR is initialized. If we have static data that we'd like to protect by a +// lock, and we have a statically allocated lock to protect that data, there's an issue in how to initialize +// that lock. We could insert an initialize call in the startup path, but one might prefer to keep the code +// more local. For such situations, CritSecObject solves the initialization problem, via a level of +// indirection. A pointer to the lock is initially null, and when we query for the lock pointer via "Val()". +// If the lock has not yet been allocated, this allocates one (here a leaf lock), and uses a +// CompareAndExchange-based lazy-initialization to update the field. If this fails, the allocated lock is +// destroyed. This will work as long as the first locking attempt occurs after enough CLR initialization has +// happened to make ClrCreateCriticalSection calls legal. + +class CritSecObject +{ +public: + + CritSecObject() + { + m_pCs = NULL; + } + + CRITSEC_COOKIE Val() + { + if (m_pCs == NULL) + { + // CompareExchange-based lazy init. + CRITSEC_COOKIE newCs = ClrCreateCriticalSection(CrstLeafLock, CRST_DEFAULT); + CRITSEC_COOKIE observed = InterlockedCompareExchangeT(&m_pCs, newCs, NULL); + if (observed != NULL) + { + ClrDeleteCriticalSection(newCs); + } + } + return m_pCs; + } + +private: + + // CRITSEC_COOKIE is an opaque pointer type. + CRITSEC_COOKIE m_pCs; + + // No copying or assignment allowed. + CritSecObject(const CritSecObject&) = delete; + CritSecObject& operator=(const CritSecObject&) = delete; +}; + +// Stack-based holder for a critial section lock. +// Ensures lock is released. + +class CritSecHolder +{ +public: + + CritSecHolder(CritSecObject& critSec) + : m_CritSec(critSec) + { + ClrEnterCriticalSection(m_CritSec.Val()); + } + + ~CritSecHolder() + { + ClrLeaveCriticalSection(m_CritSec.Val()); + } + +private: + + CritSecObject& m_CritSec; + + // No copying or assignment allowed. + CritSecHolder(const CritSecHolder&) = delete; + CritSecHolder& operator=(const CritSecHolder&) = delete; +}; + + #endif // _UTILS_H_ |