265 lines
7.3 KiB
C
265 lines
7.3 KiB
C
|
#ifndef __SHARELOCK_H__
|
||
|
#define __SHARELOCK_H__
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// The standard include files.
|
||
|
//
|
||
|
// The standard include files setup a consistent environment
|
||
|
// for all of the modules in a program. The structure of each
|
||
|
// header file is as follows:
|
||
|
// 1. Standard include files.
|
||
|
// 2. Include files for inherited classes.
|
||
|
// 3. Constants exported from the class.
|
||
|
// 4. Data structures exported from the class.
|
||
|
// 5. Class specification.
|
||
|
// 6. Inline functions.
|
||
|
// Sections that are not required are omitted.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// #include "Global.h"
|
||
|
// #include "NewEx.h"
|
||
|
// #include "Standard.h"
|
||
|
// #include "System.h"
|
||
|
|
||
|
#include <irtlmisc.h>
|
||
|
|
||
|
typedef int SBIT32;
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Sharelock and Semaphore locking.
|
||
|
//
|
||
|
// This class provides a very conservative locking scheme.
|
||
|
// The assumption behind the code is that locks will be
|
||
|
// held for a very short time. A lock can be obtained in
|
||
|
// either exclusive mode or shared mode. If the lock is not
|
||
|
// available the caller waits by spinning or if that fails
|
||
|
// by sleeping.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
class IRTL_DLLEXP CSharelock
|
||
|
{
|
||
|
private:
|
||
|
|
||
|
// internally used constants
|
||
|
|
||
|
enum Internal
|
||
|
{
|
||
|
// The Windows NT kernel requires a maximum wakeup count when
|
||
|
// creating a semaphore.
|
||
|
m_MaxShareLockUsers = 256
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Private data.
|
||
|
//
|
||
|
volatile LONG m_lExclusive;
|
||
|
volatile LONG m_lTotalUsers;
|
||
|
|
||
|
SBIT32 m_lMaxSpins;
|
||
|
SBIT32 m_lMaxUsers;
|
||
|
HANDLE m_hSemaphore;
|
||
|
volatile LONG m_lWaiting;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
//
|
||
|
// Counters for debugging builds.
|
||
|
//
|
||
|
volatile LONG m_lTotalExclusiveLocks;
|
||
|
volatile LONG m_lTotalShareLocks;
|
||
|
volatile LONG m_lTotalSleeps;
|
||
|
volatile LONG m_lTotalSpins;
|
||
|
volatile LONG m_lTotalTimeouts;
|
||
|
volatile LONG m_lTotalWaits;
|
||
|
#endif
|
||
|
|
||
|
public:
|
||
|
//
|
||
|
// Public functions.
|
||
|
//
|
||
|
CSharelock( SBIT32 lNewMaxSpins = 4096, SBIT32 lNewMaxUsers = 256 );
|
||
|
|
||
|
inline SBIT32 ActiveUsers( void ) { return (SBIT32) m_lTotalUsers; }
|
||
|
|
||
|
inline void ChangeExclusiveLockToSharedLock( void );
|
||
|
|
||
|
inline BOOLEAN ChangeSharedLockToExclusiveLock( SBIT32 lSleep = INFINITE );
|
||
|
|
||
|
inline BOOLEAN ClaimExclusiveLock( SBIT32 lSleep = INFINITE );
|
||
|
|
||
|
inline BOOLEAN ClaimShareLock( SBIT32 lSleep = INFINITE );
|
||
|
|
||
|
inline void ReleaseExclusiveLock( void );
|
||
|
|
||
|
inline void ReleaseShareLock( void );
|
||
|
|
||
|
BOOLEAN UpdateMaxSpins( SBIT32 lNewMaxSpins );
|
||
|
|
||
|
BOOLEAN UpdateMaxUsers( SBIT32 lNewMaxUsers );
|
||
|
|
||
|
~CSharelock( void );
|
||
|
|
||
|
|
||
|
private:
|
||
|
//
|
||
|
// Private functions.
|
||
|
//
|
||
|
BOOLEAN SleepWaitingForLock( SBIT32 lSleep );
|
||
|
|
||
|
BOOLEAN WaitForExclusiveLock( SBIT32 lSleep );
|
||
|
|
||
|
BOOLEAN WaitForShareLock( SBIT32 lSleep );
|
||
|
|
||
|
void WakeAllSleepers( void );
|
||
|
|
||
|
private:
|
||
|
//
|
||
|
// Disabled operations.
|
||
|
//
|
||
|
CSharelock( const CSharelock & Copy );
|
||
|
|
||
|
void operator=( const CSharelock & Copy );
|
||
|
};
|
||
|
|
||
|
/********************************************************************/
|
||
|
/* */
|
||
|
/* Change an exclusive lock to a shread lock. */
|
||
|
/* */
|
||
|
/* Downgrade the existing exclusive lock to a shared lock. */
|
||
|
/* */
|
||
|
/********************************************************************/
|
||
|
|
||
|
inline void CSharelock::ChangeExclusiveLockToSharedLock( void )
|
||
|
{
|
||
|
(void) InterlockedDecrement( (LPLONG) & m_lExclusive );
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
(void) InterlockedIncrement( (LPLONG) & m_lTotalShareLocks );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/********************************************************************/
|
||
|
/* */
|
||
|
/* Change a shared lock to an exclusive lock. */
|
||
|
/* */
|
||
|
/* Upgrade the existing shared lock to an exclusive lock. */
|
||
|
/* */
|
||
|
/********************************************************************/
|
||
|
|
||
|
inline BOOLEAN CSharelock::ChangeSharedLockToExclusiveLock( SBIT32 lSleep )
|
||
|
{
|
||
|
(void) InterlockedIncrement( (LPLONG) & m_lExclusive );
|
||
|
|
||
|
if ( m_lTotalUsers != 1 )
|
||
|
{
|
||
|
if ( ! WaitForExclusiveLock( lSleep ) )
|
||
|
{ return FALSE; }
|
||
|
}
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
(void) InterlockedIncrement( (LPLONG) & m_lTotalExclusiveLocks );
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Claim an exclusive lock.
|
||
|
//
|
||
|
// Claim an exclusive lock if available else wait or exit.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
inline BOOLEAN CSharelock::ClaimExclusiveLock( SBIT32 lSleep )
|
||
|
{
|
||
|
(void) InterlockedIncrement( (LPLONG) & m_lExclusive );
|
||
|
(void) InterlockedIncrement( (LPLONG) & m_lTotalUsers );
|
||
|
|
||
|
if ( m_lTotalUsers != 1 )
|
||
|
{
|
||
|
if ( ! WaitForExclusiveLock( lSleep ) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
InterlockedIncrement( (LPLONG) & m_lTotalExclusiveLocks );
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Claim a shared lock.
|
||
|
//
|
||
|
// Claim a shared lock if available else wait or exit.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
inline BOOLEAN CSharelock::ClaimShareLock( SBIT32 lSleep )
|
||
|
{
|
||
|
(void) InterlockedIncrement( (LPLONG) & m_lTotalUsers );
|
||
|
|
||
|
if ( (m_lExclusive > 0) || (m_lTotalUsers > m_lMaxUsers) )
|
||
|
{
|
||
|
if ( ! WaitForShareLock( lSleep ) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
InterlockedIncrement( (LPLONG) & m_lTotalShareLocks );
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Release an exclusive lock.
|
||
|
//
|
||
|
// Release an exclusive lock and if needed wakeup any sleepers.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
inline void CSharelock::ReleaseExclusiveLock( void )
|
||
|
{
|
||
|
(void) InterlockedDecrement( (LPLONG) & m_lTotalUsers );
|
||
|
(void) InterlockedDecrement( (LPLONG) & m_lExclusive );
|
||
|
|
||
|
if ( m_lWaiting > 0 )
|
||
|
{
|
||
|
WakeAllSleepers();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Release a shared lock.
|
||
|
//
|
||
|
// Release a shared lock and if needed wakeup any sleepers.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
inline void CSharelock::ReleaseShareLock( void )
|
||
|
{
|
||
|
(void) InterlockedDecrement( (LPLONG) & m_lTotalUsers );
|
||
|
|
||
|
if ( m_lWaiting > 0 )
|
||
|
{
|
||
|
WakeAllSleepers();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif // __SHARELOCK_H__
|