/*++ Copyright (c) 2000 Microsoft Corporation Module Name : kLocks.h Abstract: A collection of kernel-mode locks for multithreaded access to data structures that provide the same abstractions as Author: George V. Reilly (GeorgeRe) 24-Oct-2000 Environment: Win32 - Kernel Mode Project: Internet Information Server Http.sys Revision History: --*/ #ifndef __KLOCKS_H__ #define __KLOCKS_H__ #define LOCKS_KERNEL_MODE #ifdef __LOCKS_H__ #error Do not #include before #endif #include //-------------------------------------------------------------------- // CKSpinLock is a mutex lock based on KSPIN_LOCK class IRTL_DLLEXP CKSpinLock : public CLockBase { private: // BUGBUG: this data must live in non-paged memory mutable KSPIN_LOCK KSpinLock; LOCK_INSTRUMENTATION_DECL(); public: #ifndef LOCK_INSTRUMENTATION CKSpinLock() { KeInitializeSpinLock(&KSpinLock); } #else // LOCK_INSTRUMENTATION CKSpinLock( const TCHAR* ptszName) { KeInitializeSpinLock(&KSpinLock); LOCK_INSTRUMENTATION_INIT(ptszName); } #endif // LOCK_INSTRUMENTATION #ifdef IRTLDEBUG ~CKSpinLock() {} #endif // IRTLDEBUG typedef KIRQL ResultType; // Acquire an exclusive lock for writing. // Blocks (if needed) until acquired. ResultType WriteLock() { ResultType OldIrql; KeAcquireSpinLock(&KSpinLock, &OldIrql); return OldIrql; } // Acquire a (possibly shared) lock for reading. // Blocks (if needed) until acquired. ResultType ReadLock() { return WriteLock(); } // Try to acquire an exclusive lock for writing. Returns true // if successful. Non-blocking. bool TryWriteLock() { return false; } // Try to acquire a (possibly shared) lock for reading. Returns true // if successful. Non-blocking. bool TryReadLock() { return TryWriteLock(); } // Unlock the lock after a successful call to {,Try}WriteLock(). // Assumes caller owned the lock. void WriteUnlock( ResultType OldIrql) { KeReleaseSpinLock(&KSpinLock, OldIrql); } // Unlock the lock after a successful call to {,Try}ReadLock(). // Assumes caller owned the lock. void ReadUnlock( ResultType OldIrql) { WriteUnlock(OldIrql); } // Is the lock already locked for writing by this thread? bool IsWriteLocked() const { return false; // no way of determining this w/o auxiliary info } // Is the lock already locked for reading? bool IsReadLocked() const { return IsWriteLocked(); } // Is the lock unlocked for writing? bool IsWriteUnlocked() const { return !IsWriteLocked(); } // Is the lock unlocked for reading? bool IsReadUnlocked() const { return IsWriteUnlocked(); } // Convert a reader lock to a writer lock void ConvertSharedToExclusive() { // no-op } // Convert a writer lock to a reader lock void ConvertExclusiveToShared() { // no-op } #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION // Set the spin count for this lock. // Returns true if successfully set the per-lock spincount, false otherwise bool SetSpinCount(WORD wSpins) { IRTLASSERT((wSpins == LOCK_DONT_SPIN) || (wSpins == LOCK_USE_DEFAULT_SPINS) || (LOCK_MINIMUM_SPINS <= wSpins && wSpins <= LOCK_MAXIMUM_SPINS)); return false; } // Return the spin count for this lock. WORD GetSpinCount() const { return sm_wDefaultSpinCount; } LOCK_DEFAULT_SPIN_IMPLEMENTATION(); #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION static const TCHAR* ClassName() {return _TEXT("CKSpinLock");} }; // CKSpinLock //-------------------------------------------------------------------- // CFastMutex is a mutex lock based on FAST_MUTEX class IRTL_DLLEXP CFastMutex : public CLockBase { private: mutable FAST_MUTEX FastMutex; LOCK_INSTRUMENTATION_DECL(); public: #ifndef LOCK_INSTRUMENTATION CFastMutex() { ExInitializeFastMutex(&FastMutex); } #else // LOCK_INSTRUMENTATION CFastMutex( const TCHAR* ptszName) { ExInitializeFastMutex(&FastMutex); LOCK_INSTRUMENTATION_INIT(ptszName); } #endif // LOCK_INSTRUMENTATION #ifdef IRTLDEBUG ~CFastMutex() {} #endif // IRTLDEBUG // Acquire an exclusive lock for writing. // Blocks (if needed) until acquired. void WriteLock() { ExAcquireFastMutex(&FastMutex); } // Acquire a (possibly shared) lock for reading. // Blocks (if needed) until acquired. void ReadLock() { WriteLock(); } // Try to acquire an exclusive lock for writing. Returns true // if successful. Non-blocking. bool TryWriteLock() { return ExTryToAcquireFastMutex(&FastMutex) != FALSE; } // Try to acquire a (possibly shared) lock for reading. Returns true // if successful. Non-blocking. bool TryReadLock() { return TryWriteLock(); } // Unlock the lock after a successful call to {,Try}WriteLock(). // Assumes caller owned the lock. void WriteUnlock() { ExReleaseFastMutex(&FastMutex); } // Unlock the lock after a successful call to {,Try}ReadLock(). // Assumes caller owned the lock. void ReadUnlock() { WriteUnlock(); } // Is the lock already locked for writing by this thread? bool IsWriteLocked() const { return false; // no way of determining this w/o auxiliary info } // Is the lock already locked for reading? bool IsReadLocked() const { return IsWriteLocked(); } // Is the lock unlocked for writing? bool IsWriteUnlocked() const { return !IsWriteLocked(); } // Is the lock unlocked for reading? bool IsReadUnlocked() const { return IsWriteUnlocked(); } // Convert a reader lock to a writer lock void ConvertSharedToExclusive() { // no-op } // Convert a writer lock to a reader lock void ConvertExclusiveToShared() { // no-op } #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION // Set the spin count for this lock. // Returns true if successfully set the per-lock spincount, false otherwise bool SetSpinCount(WORD wSpins) { IRTLASSERT((wSpins == LOCK_DONT_SPIN) || (wSpins == LOCK_USE_DEFAULT_SPINS) || (LOCK_MINIMUM_SPINS <= wSpins && wSpins <= LOCK_MAXIMUM_SPINS)); return false; } // Return the spin count for this lock. WORD GetSpinCount() const { return sm_wDefaultSpinCount; } LOCK_DEFAULT_SPIN_IMPLEMENTATION(); #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION static const TCHAR* ClassName() {return _TEXT("CFastMutex");} }; // CFastMutex //-------------------------------------------------------------------- // CEResource is a multi-reader, single-writer lock based on ERESOURCE class IRTL_DLLEXP CEResource : public CLockBase { private: mutable ERESOURCE Resource; public: CEResource() { ExInitializeResourceLite(&Resource); } #ifdef LOCK_INSTRUMENTATION CEResource( const TCHAR* ptszName) { ExInitializeResourceLite(&Resource); LOCK_INSTRUMENTATION_INIT(ptszName); } #endif // LOCK_INSTRUMENTATION ~CEResource() { ExDeleteResourceLite(&Resource); } inline void WriteLock() { KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&Resource, TRUE); } inline void ReadLock() { KeEnterCriticalRegion(); ExAcquireResourceSharedLite(&Resource, TRUE); } bool ReadOrWriteLock(); inline bool TryWriteLock() { KeEnterCriticalRegion(); BOOLEAN fLocked = ExAcquireResourceExclusiveLite(&Resource, FALSE); if (! fLocked) KeLeaveCriticalRegion(); return fLocked != FALSE; } inline bool TryReadLock() { KeEnterCriticalRegion(); BOOLEAN fLocked = ExAcquireResourceSharedLite(&Resource, FALSE); if (! fLocked) KeLeaveCriticalRegion(); return fLocked != FALSE; } inline void WriteUnlock() { ExReleaseResourceLite(&Resource); KeLeaveCriticalRegion(); } inline void ReadUnlock() { WriteUnlock(); } void ReadOrWriteUnlock(bool fIsReadLocked); // Does current thread hold a write lock? bool IsWriteLocked() const { return ExIsResourceAcquiredExclusiveLite(&Resource) != FALSE; } bool IsReadLocked() const { return ExIsResourceAcquiredSharedLite(&Resource) > 0; } bool IsWriteUnlocked() const { return !IsWriteLocked(); } bool IsReadUnlocked() const { return !IsReadLocked(); } void ConvertSharedToExclusive() { ReadUnlock(); WriteLock(); } // There is no such window when converting from a writelock to a readlock void ConvertExclusiveToShared() { #if 0 ExConvertExclusiveToShared(&Resource); #else WriteUnlock(); ReadLock(); #endif } #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION bool SetSpinCount(WORD wSpins) {return false;} WORD GetSpinCount() const {return sm_wDefaultSpinCount;} LOCK_DEFAULT_SPIN_IMPLEMENTATION(); #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION static const TCHAR* ClassName() {return _TEXT("CEResource");} }; // CEResource #endif // __KLOCKS_H__