From ef1e2ab328087c61a6878c1e84f4fc5d710aebce Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Fri, 30 Jan 2015 14:14:42 -0800 Subject: Initial commit to populate CoreCLR repo [tfs-changeset: 1407945] --- src/vm/listlock.h | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 src/vm/listlock.h (limited to 'src/vm/listlock.h') diff --git a/src/vm/listlock.h b/src/vm/listlock.h new file mode 100644 index 0000000000..284d2dad4f --- /dev/null +++ b/src/vm/listlock.h @@ -0,0 +1,358 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// =========================================================================== +// File: ListLock.h +// + +// +// =========================================================================== +// This file decribes the list lock and deadlock aware list lock. +// =========================================================================== + +#ifndef LISTLOCK_H +#define LISTLOCK_H + +#include "vars.hpp" +#include "threads.h" +#include "crst.h" + +class ListLock; +// 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 +// to be allocated in a function that used SEH. +// @FUTURE Keep a pool of these (e.g. an array), so we don't have to allocate on the fly +// 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 +{ + friend class ListLock; + +public: +#ifdef _DEBUG + bool Check() + { + WRAPPER_NO_CONTRACT; + + return m_dwRefCount != (DWORD)-1; + } +#endif // DEBUG + + DeadlockAwareLock m_deadlock; + ListLock * m_pList; + void * m_pData; + Crst m_Crst; + const char * m_pszDescription; + ListLockEntry * m_pNext; + DWORD m_dwRefCount; + HRESULT m_hrResultCode; + LOADERHANDLE m_hInitException; + PTR_LoaderAllocator m_pLoaderAllocator; +#ifdef FEATURE_CORRUPTING_EXCEPTIONS + // Field to maintain the corruption severity of the exception + CorruptionSeverity m_CorruptionSeverity; +#endif // FEATURE_CORRUPTING_EXCEPTIONS + + ListLockEntry(ListLock *pList, void *pData, const char *description = NULL); + + virtual ~ListLockEntry() + { + } + + DEBUG_NOINLINE void Enter() + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + + m_deadlock.BeginEnterLock(); + DeadlockAwareLock::BlockingLockHolder dlLock; + m_Crst.Enter(); + m_deadlock.EndEnterLock(); + } + + BOOL CanDeadlockAwareEnter() + { + WRAPPER_NO_CONTRACT; + + return m_deadlock.CanEnterLock(); + } + + DEBUG_NOINLINE BOOL DeadlockAwareEnter() + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + + if (!m_deadlock.TryBeginEnterLock()) + return FALSE; + + DeadlockAwareLock::BlockingLockHolder dlLock; + m_Crst.Enter(); + m_deadlock.EndEnterLock(); + + return TRUE; + } + + DEBUG_NOINLINE void Leave() + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + + m_deadlock.LeaveLock(); + m_Crst.Leave(); + } + + static ListLockEntry *Find(ListLock* pLock, LPVOID pPointer, const char *description = NULL) DAC_EMPTY_RET(NULL); + + void AddRef() DAC_EMPTY_ERR(); + void Release() DAC_EMPTY_ERR(); + +#ifdef _DEBUG + BOOL HasLock() + { + WRAPPER_NO_CONTRACT; + return(m_Crst.OwnedByCurrentThread()); + } +#endif + + // LockHolder holds the lock of the element, not the element itself + + DEBUG_NOINLINE static void LockHolderEnter(ListLockEntry *pThis) PUB + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->Enter(); + } + + DEBUG_NOINLINE static void LockHolderLeave(ListLockEntry *pThis) PUB + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->Leave(); + } + + DEBUG_NOINLINE void FinishDeadlockAwareEnter() + { + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + DeadlockAwareLock::BlockingLockHolder dlLock; + m_Crst.Enter(); + m_deadlock.EndEnterLock(); + } + + typedef Wrapper LockHolderBase; + + class LockHolder : public LockHolderBase + { + public: + + LockHolder() + : LockHolderBase(NULL, FALSE) + { + } + + LockHolder(ListLockEntry *value, BOOL take = TRUE) + : LockHolderBase(value, take) + { + } + + BOOL DeadlockAwareAcquire() + { + if (!m_acquired && m_value != NULL) + { + if (!m_value->m_deadlock.TryBeginEnterLock()) + return FALSE; + m_value->FinishDeadlockAwareEnter(); + m_acquired = TRUE; + } + return TRUE; + } + }; +}; + +class ListLock +{ + protected: + CrstStatic m_Crst; + BOOL m_fInited; + BOOL m_fHostBreakable; // Lock can be broken by a host for deadlock detection + ListLockEntry * m_pHead; + + public: + + BOOL IsInitialized() + { + LIMITED_METHOD_CONTRACT; + return m_fInited; + } + inline void PreInit() + { + LIMITED_METHOD_CONTRACT; + memset(this, 0, sizeof(*this)); + } + + // DO NOT MAKE A CONSTRUCTOR FOR THIS CLASS - There are global instances + void Init(CrstType crstType, CrstFlags flags, BOOL fHostBreakable = FALSE) + { + WRAPPER_NO_CONTRACT; + PreInit(); + m_Crst.Init(crstType, flags); + m_fInited = TRUE; + m_fHostBreakable = fHostBreakable; + } + + void Destroy() + { + WRAPPER_NO_CONTRACT; + // There should not be any of these around + _ASSERTE(m_pHead == NULL || dbg_fDrasticShutdown || g_fInControlC); + + if (m_fInited) + { + m_fInited = FALSE; + m_Crst.Destroy(); + } + } + + BOOL IsHostBreakable () const + { + LIMITED_METHOD_CONTRACT; + return m_fHostBreakable; + } + + void AddElement(ListLockEntry* pElement) + { + WRAPPER_NO_CONTRACT; + pElement->m_pNext = m_pHead; + m_pHead = pElement; + } + + + DEBUG_NOINLINE void Enter() + { + CANNOT_HAVE_CONTRACT; // See below + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; +#if 0 // The cleanup logic contract will cause any forbid GC state from the Crst to + // get deleted. This causes asserts from Leave. We probably should make the contract + // implementation tolerant of this pattern, or else ensure that the state the contract + // modifies is not used by any other code. + CONTRACTL + { + NOTHROW; + UNCHECKED(GC_TRIGGERS); // May trigger or not based on Crst's type + MODE_ANY; + PRECONDITION(CheckPointer(this)); + } + CONTRACTL_END; +#endif + + m_Crst.Enter(); + } + + DEBUG_NOINLINE void Leave() + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + m_Crst.Leave(); + } + + // Must own the lock before calling this or is ok if the debugger has + // all threads stopped + ListLockEntry *Find(void *pData); + + // Must own the lock before calling this! + ListLockEntry* Pop(BOOL unloading = FALSE) + { + LIMITED_METHOD_CONTRACT; +#ifdef _DEBUG + if(unloading == FALSE) + _ASSERTE(m_Crst.OwnedByCurrentThread()); +#endif + + if(m_pHead == NULL) return NULL; + ListLockEntry* pEntry = m_pHead; + m_pHead = m_pHead->m_pNext; + return pEntry; + } + + // Must own the lock before calling this! + ListLockEntry* Peek() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(m_Crst.OwnedByCurrentThread()); + return m_pHead; + } + + // Must own the lock before calling this! + BOOL Unlink(ListLockEntry *pItem) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(m_Crst.OwnedByCurrentThread()); + ListLockEntry *pSearch; + ListLockEntry *pPrev; + + pPrev = NULL; + + for (pSearch = m_pHead; pSearch != NULL; pSearch = pSearch->m_pNext) + { + if (pSearch == pItem) + { + if (pPrev == NULL) + m_pHead = pSearch->m_pNext; + else + pPrev->m_pNext = pSearch->m_pNext; + + return TRUE; + } + + pPrev = pSearch; + } + + // Not found + return FALSE; + } + +#ifdef _DEBUG + BOOL HasLock() + { + WRAPPER_NO_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; + return(m_Crst.OwnedByCurrentThread()); + } +#endif + + DEBUG_NOINLINE static void HolderEnter(ListLock *pThis) + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->Enter(); + } + + DEBUG_NOINLINE static void HolderLeave(ListLock *pThis) + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->Leave(); + } + + typedef Wrapper LockHolder; +}; + +class WaitingThreadListElement +{ +public: + Thread * m_pThread; + WaitingThreadListElement * m_pNext; +}; + +// Holds the lock of the ListLock +typedef ListLock::LockHolder ListLockHolder; + +// Holds the ownership of the lock element +typedef ReleaseHolder ListLockEntryHolder; + +// Holds the lock of the lock element +typedef ListLockEntry::LockHolder ListLockEntryLockHolder; + + +#endif // LISTLOCK_H -- cgit v1.2.3