//----------------------------------------------------------------- // Acquire the lock. //----------------------------------------------------------------- void CrstBase::Enter() { #ifdef _DEBUG PreEnter (); #endif _ASSERTE(IsSafeToTake() || g_fEEShutDown); #ifdef _DEBUG char buffer[100]; sprintf(buffer, "Enter in crst.h - %s", m_tag); CRSTBLOCKCOUNTINCL(); LOCKCOUNTINCL(buffer); #endif EnterCriticalSection(&m_criticalsection); CRSTELOCKCOUNTINCL(); #ifdef _DEBUG m_holderthreadid = GetCurrentThreadId(); m_entercount++; PostEnter (); #endif }
//===================================================================== BOOL SimpleRWLock::TryEnterWrite() { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_CAN_TAKE_LOCK; #ifdef _DEBUG PreEnter(); #endif //_DEBUG LONG RWLock = InterlockedCompareExchange( &m_RWLock, -1, 0 ); _ASSERTE (RWLock >= 0 || RWLock == -1); if( RWLock ) { return FALSE; } INCTHREADLOCKCOUNT(); EE_LOCK_TAKEN(this); #ifdef _DEBUG PostEnter(); #endif //_DEBUG ResetWriterWaiting(); return TRUE; }
BOOL SimpleRWLock::TryEnterRead() { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_CAN_TAKE_LOCK; #ifdef _DEBUG PreEnter(); #endif //_DEBUG LONG RWLock; do { RWLock = m_RWLock; if( RWLock == -1 ) return FALSE; _ASSERTE (RWLock >= 0); } while( RWLock != InterlockedCompareExchange( &m_RWLock, RWLock+1, RWLock )); INCTHREADLOCKCOUNT(); EE_LOCK_TAKEN(this); #ifdef _DEBUG PostEnter(); #endif //_DEBUG return TRUE; }
//===================================================================== void SimpleRWLock::EnterRead() { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_CAN_TAKE_LOCK; // Custom contract is needed for PostEnter()'s unscoped GC_NoTrigger counter change #ifdef ENABLE_CONTRACTS_IMPL CheckGCNoTrigger(); #endif //ENABLE_CONTRACTS_IMPL GCX_MAYBE_PREEMP(m_gcMode == PREEMPTIVE); #ifdef _DEBUG PreEnter(); #endif //_DEBUG DWORD dwSwitchCount = 0; while (TRUE) { // prevent writers from being starved. This assumes that writers are rare and // dont hold the lock for a long time. while (IsWriterWaiting()) { int spinCount = m_spinCount; while (spinCount > 0) { spinCount--; YieldProcessor(); } __SwitchToThread(0, ++dwSwitchCount); } if (TryEnterRead()) { return; } DWORD i = g_SpinConstants.dwInitialDuration; do { if (TryEnterRead()) { return; } if (g_SystemInfo.dwNumberOfProcessors <= 1) { break; } // Delay by approximately 2*i clock cycles (Pentium III). // This is brittle code - future processors may of course execute this // faster or slower, and future code generators may eliminate the loop altogether. // The precise value of the delay is not critical, however, and I can't think // of a better way that isn't machine-dependent. for (int delayCount = i; --delayCount; ) { YieldProcessor(); // indicate to the processor that we are spining } // exponential backoff: wait a factor longer in the next iteration i *= g_SpinConstants.dwBackoffFactor; } while (i < g_SpinConstants.dwMaximumDuration); __SwitchToThread(0, ++dwSwitchCount); } }
//===================================================================== void SimpleRWLock::EnterWrite() { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_CAN_TAKE_LOCK; // Custom contract is needed for PostEnter()'s unscoped GC_NoTrigger counter change #ifdef ENABLE_CONTRACTS_IMPL CheckGCNoTrigger(); #endif //ENABLE_CONTRACTS_IMPL GCX_MAYBE_PREEMP(m_gcMode == PREEMPTIVE); #ifdef _DEBUG PreEnter(); #endif //_DEBUG BOOL set = FALSE; DWORD dwSwitchCount = 0; while (TRUE) { if (TryEnterWrite()) { return; } // set the writer waiting word, if not already set, to notify potential // readers to wait. Remember, if the word is set, so it can be reset later. if (!IsWriterWaiting()) { SetWriterWaiting(); set = TRUE; } DWORD i = g_SpinConstants.dwInitialDuration; do { if (TryEnterWrite()) { return; } if (g_SystemInfo.dwNumberOfProcessors <= 1) { break; } // Delay by approximately 2*i clock cycles (Pentium III). // This is brittle code - future processors may of course execute this // faster or slower, and future code generators may eliminate the loop altogether. // The precise value of the delay is not critical, however, and I can't think // of a better way that isn't machine-dependent. for (int delayCount = i; --delayCount; ) { YieldProcessor(); // indicate to the processor that we are spining } // exponential backoff: wait a factor longer in the next iteration i *= g_SpinConstants.dwBackoffFactor; } while (i < g_SpinConstants.dwMaximumDuration); __SwitchToThread(0, ++dwSwitchCount); } }