windows-nt/Source/XPSP1/NT/net/ias/protocol/radius/rwlock.h
2020-09-26 16:20:57 +08:00

270 lines
6.3 KiB
C++

/*--------------------------------------------------------
rwlock.h
CReadWriteLock class provides functions that allow
threads to lock any resource in two different
modes (read-mode and write-mode).
The class will allow multiple reader threads to access
the resource simultaneously, but will make sure that
a writer thread doesn't access the resource when
reader threads or a writer thread is currently accessing
the resource. The class also assures fairness in access
i.e. the access will be regulated by a first-come-first-in
policy.
Note:- ALL the functions in the class are INLINE functions.
So, this header can be directly used in the source.
Copyright (C) 1997-98 Microsoft Corporation
All rights reserved.
Authors:
rsraghav R.S. Raghavan
History:
04-20-95 rsraghav Created.
-------------------------------------------------------*/
#ifdef __cplusplus // this file should be include only if this is
// is included in a c++ source file.
#ifndef _RWLOCK_H_
#define _RWLOCK_H_
#if defined(DEBUG) && defined(INLINE)
#undef THIS_FILE
static char BASED_CODE RWLOCK_H[] = "rwlock.h";
#define THIS_FILE RWLOCK_H
#endif
#include <windows.h>
#define INLINE_EXPORT_SPEC __declspec( dllexport)
typedef enum {RWLOCK_READ_MODE, RWLOCK_WRITE_MODE} RWLOCK_MODE;
//////////////////////////////////////////////////////////////////////
// CReadWriteLock - Class that can be used to regulate read-write
// access to resource, where multiple readers are
// allowed simultaneously, but writers are excluded
// from each other and from the readers.
class CReadWriteLock
{
HANDLE hResource;
CRITICAL_SECTION csReader;
CRITICAL_SECTION csWriter;
DWORD cReaders;
DWORD cWriteRecursion;
public:
CReadWriteLock() // object constructor
{
cReaders =0;
cWriteRecursion = 0;
hResource = CreateEvent(NULL, FALSE, TRUE, NULL); // no manual reset & initial state is signalled
InitializeCriticalSection(&csReader);
InitializeCriticalSection(&csWriter);
}
~CReadWriteLock() // object destructor
{
if (hResource)
CloseHandle(hResource);
DeleteCriticalSection(&csReader);
DeleteCriticalSection(&csWriter);
}
CReadWriteLock *PrwLock()
{
return this;
}
BOOL FInit()
{
return (BOOL)hResource;
}
void LockReadMode() // Get read access to the resource
{
EnterCriticalSection(&csWriter);
LeaveCriticalSection(&csWriter);
EnterCriticalSection(&csReader);
if (!cReaders)
{
if (hResource)
WaitForSingleObject(hResource, INFINITE);
}
cReaders++;
LeaveCriticalSection(&csReader);
}
int LockReadModeEx(int iTimeOut) // Get read access to the resource w/ Timeout
{
int status = 0;
EnterCriticalSection(&csWriter);
LeaveCriticalSection(&csWriter);
EnterCriticalSection(&csReader);
if (!cReaders)
{
if (hResource) {
status = WaitForSingleObject(hResource, iTimeOut);
if (status == WAIT_TIMEOUT)
{
status = -1;
} else {
status = 0;
}
}
}
cReaders++;
LeaveCriticalSection(&csReader);
return status;
}
void UnlockReadMode() // Relinquish read access to the resource
{
EnterCriticalSection(&csReader);
if (!(--cReaders))
{
if (hResource)
SetEvent(hResource);
}
LeaveCriticalSection(&csReader);
}
void LockCSUnderRead()
{
EnterCriticalSection(&csReader);
}
void UnlockCSUnderRead()
{
LeaveCriticalSection(&csReader);
}
void LockWriteMode() // Get write access to the resource
{
EnterCriticalSection(&csWriter);
if (!cWriteRecursion)
{
if (hResource)
WaitForSingleObject(hResource, INFINITE);
}
cWriteRecursion++;
}
int LockWriteModeEx(int iTimeOut) // Get write access to the resource
{
int status = 0;
EnterCriticalSection(&csWriter);
if (!cWriteRecursion)
{
if (hResource)
{
status = WaitForSingleObject(hResource, iTimeOut);
if (status == WAIT_TIMEOUT)
{
status = -1;
} else {
status = 0;
}
}
}
if (status == 0)
cWriteRecursion++;
return status;
}
void UnlockWriteMode() // Relinquish write access to the resource
{
if (!(--cWriteRecursion))
{
if (hResource)
SetEvent(hResource);
}
LeaveCriticalSection(&csWriter);
}
};
//////////////////////////////////////////////////////////////////////
// Following class is just a utility class - users don't need to
// necessarily use this class for obtaining read-write lock functionalities.
//////////////////////////////////////////////////////////////////////
// CScopeRWLock - This can be used to lock the given CReadWriteLock
// object for the rest of the scope. The user just
// needs to define this object in the scope by passing
// a pointer to the CReadWriteLock object in the constructor.
// When this CScopeRWLock object goes out of scope the
// CReadWriteLock object will automatically be unlocked.
// This is provided just for user convenience so that the
// user can choose to avoid remembering to unlock the object
// before every possible return/break path of the scope.
// Use the RWLOCK_READ_MODE or RWLOCK_WRITE_MODE in the constructor
// to indicate which type of access is requested.
// Assumption:- CReadWriteLock object used here is expected to
// be valid at lease until the end of the scope.
class CScopeRWLock
{
CReadWriteLock *m_prwLock;
LPCRITICAL_SECTION m_pcs;
RWLOCK_MODE m_rwMode;
public:
CScopeRWLock(CReadWriteLock * prwLock, RWLOCK_MODE rwMode)
{
m_prwLock = prwLock;
m_pcs = NULL;
m_rwMode = rwMode;
if (m_prwLock)
{
if (m_rwMode == RWLOCK_READ_MODE)
m_prwLock->LockReadMode();
else if (m_rwMode == RWLOCK_WRITE_MODE)
m_prwLock->LockWriteMode();
}
}
CScopeRWLock(LPCRITICAL_SECTION pcsLock)
{
m_pcs = pcsLock;
m_prwLock = NULL;
if (m_pcs)
EnterCriticalSection(m_pcs);
}
~CScopeRWLock()
{
if (m_prwLock)
{
if (m_rwMode == RWLOCK_READ_MODE)
m_prwLock->UnlockReadMode();
else if (m_rwMode == RWLOCK_WRITE_MODE)
m_prwLock->UnlockWriteMode();
}
if (m_pcs)
{
LeaveCriticalSection(m_pcs);
}
}
};
#endif // _RWLOCK_H_
#endif // #if __cplusplus