summaryrefslogtreecommitdiff
path: root/src/vm/listlock.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/listlock.h')
-rw-r--r--src/vm/listlock.h179
1 files changed, 147 insertions, 32 deletions
diff --git a/src/vm/listlock.h b/src/vm/listlock.h
index e16741a7d7..db953c8b55 100644
--- a/src/vm/listlock.h
+++ b/src/vm/listlock.h
@@ -17,7 +17,8 @@
#include "threads.h"
#include "crst.h"
-class ListLock;
+template < typename ELEMENT >
+class ListLockBase;
// This structure is used for running class init methods or JITing methods
// (m_pData points to a FunctionDesc). This class cannot have a destructor since it is used
// in function that also have EX_TRY's and the VC compiler doesn't allow classes with destructors
@@ -25,9 +26,14 @@ class ListLock;
// <TODO>@FUTURE Keep a pool of these (e.g. an array), so we don't have to allocate on the fly</TODO>
// m_hInitException contains a handle to the exception thrown by the class init. This
// allows us to throw this information to the caller on subsequent class init attempts.
-class ListLockEntry
+template < typename ELEMENT >
+class ListLockEntryBase
{
- friend class ListLock;
+ friend class ListLockBase<ELEMENT>;
+ typedef ListLockEntryBase<ELEMENT> Entry_t;
+ typedef ListLockBase<ELEMENT> List_t;
+ typedef typename List_t::LockHolder ListLockHolder;
+
public:
#ifdef _DEBUG
@@ -40,11 +46,11 @@ public:
#endif // DEBUG
DeadlockAwareLock m_deadlock;
- ListLock * m_pList;
- void * m_pData;
+ List_t * m_pList;
+ ELEMENT m_data;
Crst m_Crst;
const char * m_pszDescription;
- ListLockEntry * m_pNext;
+ Entry_t * m_pNext;
DWORD m_dwRefCount;
HRESULT m_hrResultCode;
LOADERHANDLE m_hInitException;
@@ -54,9 +60,27 @@ public:
CorruptionSeverity m_CorruptionSeverity;
#endif // FEATURE_CORRUPTING_EXCEPTIONS
- ListLockEntry(ListLock *pList, void *pData, const char *description = NULL);
+ ListLockEntryBase(List_t *pList, ELEMENT data, const char *description = NULL)
+ : m_deadlock(description),
+ m_pList(pList),
+ m_data(data),
+ m_Crst(CrstListLock,
+ (CrstFlags)(CRST_REENTRANCY | (pList->IsHostBreakable() ? CRST_HOST_BREAKABLE : 0))),
+ m_pszDescription(description),
+ m_pNext(NULL),
+ m_dwRefCount(1),
+ m_hrResultCode(S_FALSE),
+ m_hInitException(NULL),
+ m_pLoaderAllocator(dac_cast<PTR_LoaderAllocator>(nullptr))
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ ,
+ m_CorruptionSeverity(NotCorrupting)
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ {
+ WRAPPER_NO_CONTRACT;
+ }
- virtual ~ListLockEntry()
+ virtual ~ListLockEntryBase()
{
}
@@ -102,10 +126,65 @@ public:
m_Crst.Leave();
}
- static ListLockEntry *Find(ListLock* pLock, LPVOID pPointer, const char *description = NULL) DAC_EMPTY_RET(NULL);
+ static Entry_t *Find(List_t* pLock, ELEMENT data, const char *description = NULL)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(pLock->HasLock());
+
+ Entry_t *pEntry = pLock->Find(data);
+ if (pEntry == NULL)
+ {
+ pEntry = new Entry_t(pLock, data, description);
+ pLock->AddElement(pEntry);
+ }
+ else
+ pEntry->AddRef();
+
+ return pEntry;
+ };
+
+
+ void AddRef()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(this));
+ }
+ CONTRACTL_END;
+
+ FastInterlockIncrement((LONG*)&m_dwRefCount);
+ }
+
+ void Release()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(this));
+ }
+ CONTRACTL_END;
- void AddRef() DAC_EMPTY_ERR();
- void Release() DAC_EMPTY_ERR();
+ ListLockHolder lock(m_pList);
+
+ if (FastInterlockDecrement((LONG*)&m_dwRefCount) == 0)
+ {
+ // Remove from list
+ m_pList->Unlink(this);
+ delete this;
+ }
+ };
#ifdef _DEBUG
BOOL HasLock()
@@ -117,14 +196,14 @@ public:
// LockHolder holds the lock of the element, not the element itself
- DEBUG_NOINLINE static void LockHolderEnter(ListLockEntry *pThis) PUB
+ DEBUG_NOINLINE static void LockHolderEnter(Entry_t *pThis) PUB
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
pThis->Enter();
}
- DEBUG_NOINLINE static void LockHolderLeave(ListLockEntry *pThis) PUB
+ DEBUG_NOINLINE static void LockHolderLeave(Entry_t *pThis) PUB
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
@@ -139,7 +218,7 @@ public:
m_deadlock.EndEnterLock();
}
- typedef Wrapper<ListLockEntry *, ListLockEntry::LockHolderEnter, ListLockEntry::LockHolderLeave> LockHolderBase;
+ typedef Wrapper<Entry_t *, LockHolderEnter, LockHolderLeave> LockHolderBase;
class LockHolder : public LockHolderBase
{
@@ -150,32 +229,36 @@ public:
{
}
- LockHolder(ListLockEntry *value, BOOL take = TRUE)
+ LockHolder(Entry_t *value, BOOL take = TRUE)
: LockHolderBase(value, take)
{
}
BOOL DeadlockAwareAcquire()
{
- if (!m_acquired && m_value != NULL)
+ if (!this->m_acquired && this->m_value != NULL)
{
- if (!m_value->m_deadlock.TryBeginEnterLock())
+ if (!this->m_value->m_deadlock.TryBeginEnterLock())
return FALSE;
- m_value->FinishDeadlockAwareEnter();
- m_acquired = TRUE;
+ this->m_value->FinishDeadlockAwareEnter();
+ this->m_acquired = TRUE;
}
return TRUE;
}
};
};
-class ListLock
+template < typename ELEMENT >
+class ListLockBase
{
+ typedef ListLockBase<ELEMENT> List_t;
+ typedef ListLockEntryBase<ELEMENT> Entry_t;
+
protected:
CrstStatic m_Crst;
BOOL m_fInited;
BOOL m_fHostBreakable; // Lock can be broken by a host for deadlock detection
- ListLockEntry * m_pHead;
+ Entry_t * m_pHead;
public:
@@ -219,7 +302,7 @@ class ListLock
return m_fHostBreakable;
}
- void AddElement(ListLockEntry* pElement)
+ void AddElement(Entry_t* pElement)
{
WRAPPER_NO_CONTRACT;
pElement->m_pNext = m_pHead;
@@ -257,10 +340,39 @@ class ListLock
// Must own the lock before calling this or is ok if the debugger has
// all threads stopped
- ListLockEntry *Find(void *pData);
+ inline Entry_t *Find(ELEMENT data)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+#ifdef DEBUGGING_SUPPORTED
+ PRECONDITION(m_Crst.OwnedByCurrentThread() ||
+ CORDebuggerAttached()
+ // This condition should be true, but it is awkward to assert it because adding dbginterface.h creates lots of cycles in the includes
+ // It didn't seem valuable enough to refactor out a wrapper just to preserve it
+ /* && g_pDebugInterface->IsStopped() */);
+#else
+ PRECONDITION(m_Crst.OwnedByCurrentThread());
+#endif // DEBUGGING_SUPPORTED
+
+ }
+ CONTRACTL_END;
+
+ Entry_t *pSearch;
+
+ for (pSearch = m_pHead; pSearch != NULL; pSearch = pSearch->m_pNext)
+ {
+ if (pSearch->m_data == data)
+ return pSearch;
+ }
+
+ return NULL;
+ }
// Must own the lock before calling this!
- ListLockEntry* Pop(BOOL unloading = FALSE)
+ Entry_t* Pop(BOOL unloading = FALSE)
{
LIMITED_METHOD_CONTRACT;
#ifdef _DEBUG
@@ -269,13 +381,13 @@ class ListLock
#endif
if(m_pHead == NULL) return NULL;
- ListLockEntry* pEntry = m_pHead;
+ Entry_t* pEntry = m_pHead;
m_pHead = m_pHead->m_pNext;
return pEntry;
}
// Must own the lock before calling this!
- ListLockEntry* Peek()
+ Entry_t* Peek()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(m_Crst.OwnedByCurrentThread());
@@ -283,12 +395,12 @@ class ListLock
}
// Must own the lock before calling this!
- BOOL Unlink(ListLockEntry *pItem)
+ BOOL Unlink(Entry_t *pItem)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(m_Crst.OwnedByCurrentThread());
- ListLockEntry *pSearch;
- ListLockEntry *pPrev;
+ Entry_t *pSearch;
+ Entry_t *pPrev;
pPrev = NULL;
@@ -320,21 +432,21 @@ class ListLock
}
#endif
- DEBUG_NOINLINE static void HolderEnter(ListLock *pThis)
+ DEBUG_NOINLINE static void HolderEnter(List_t *pThis)
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
pThis->Enter();
}
- DEBUG_NOINLINE static void HolderLeave(ListLock *pThis)
+ DEBUG_NOINLINE static void HolderLeave(List_t *pThis)
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
pThis->Leave();
}
- typedef Wrapper<ListLock*, ListLock::HolderEnter, ListLock::HolderLeave> LockHolder;
+ typedef Wrapper<List_t*, List_t::HolderEnter, List_t::HolderLeave> LockHolder;
};
class WaitingThreadListElement
@@ -344,6 +456,9 @@ public:
WaitingThreadListElement * m_pNext;
};
+typedef class ListLockBase<void*> ListLock;
+typedef class ListLockEntryBase<void*> ListLockEntry;
+
// Holds the lock of the ListLock
typedef ListLock::LockHolder ListLockHolder;