diff options
Diffstat (limited to 'src/vm/listlock.h')
-rw-r--r-- | src/vm/listlock.h | 179 |
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; |