summaryrefslogtreecommitdiff
path: root/src/jit/utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/utils.h')
-rw-r--r--src/jit/utils.h74
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_