477 lines
10 KiB
C
477 lines
10 KiB
C
|
/*++
|
|||
|
|
|||
|
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 <locks.h>
|
|||
|
|
|||
|
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 <locks.h> before <klocks.h>
|
|||
|
#endif
|
|||
|
|
|||
|
#include <locks.h>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//--------------------------------------------------------------------
|
|||
|
// CKSpinLock is a mutex lock based on KSPIN_LOCK
|
|||
|
|
|||
|
class IRTL_DLLEXP CKSpinLock :
|
|||
|
public CLockBase<LOCK_KSPINLOCK, LOCK_MUTEX,
|
|||
|
LOCK_NON_RECURSIVE, LOCK_WAIT_SPIN, LOCK_QUEUE_KERNEL,
|
|||
|
LOCK_CLASS_SPIN
|
|||
|
>
|
|||
|
{
|
|||
|
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<LOCK_FASTMUTEX, LOCK_MUTEX,
|
|||
|
LOCK_NON_RECURSIVE, LOCK_WAIT_SPIN, LOCK_QUEUE_KERNEL,
|
|||
|
LOCK_CLASS_SPIN
|
|||
|
>
|
|||
|
{
|
|||
|
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<LOCK_ERESOURCE, LOCK_MRSW,
|
|||
|
LOCK_RECURSIVE, LOCK_WAIT_HANDLE, LOCK_QUEUE_KERNEL,
|
|||
|
LOCK_CLASS_SPIN
|
|||
|
>
|
|||
|
{
|
|||
|
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__
|