windows-nt/Source/XPSP1/NT/shell/ext/shtl/invsemaphore.h
2020-09-26 16:20:57 +08:00

357 lines
7.8 KiB
C++

// CResGuard
// CSysGlobalType
// CSysGlobalScalar
// CInterlockedType
// CInverseSemaphore
#ifndef __SYSGLOB_H__
#define __SYSGLOB_H__
#include <assert.h>
// Instances of this class will be accessed by mutiple threads. So,
// all members of this class (except the constructor and destructor)
// must be thread-safe.
class CResGuard
{
private:
HANDLE m_hMutex;
long m_lGrdCnt; // # of C calls
public:
CResGuard(void * pObjectAddr)
{
TCHAR szObjectName[32];
wsprintf(szObjectName, TEXT("CResGuard :: %08X"), (DWORD) pObjectAddr);
m_lGrdCnt = 0;
m_hMutex = CreateMutex(NULL, FALSE, szObjectName);
assert(m_hMutex);
}
~CResGuard()
{
CloseHandle(m_hMutex);
}
// IsGuarded is used for debugging
BOOL IsGuarded() const
{
return(m_lGrdCnt > 0);
}
public:
class CGuard
{
private:
CResGuard& m_rg;
public:
CGuard(CResGuard& rg) : m_rg(rg)
{
m_rg.Guard();
};
~CGuard()
{
m_rg.Unguard();
}
};
private:
void Guard()
{
assert(WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex, INFINITE));
m_lGrdCnt++;
}
void Unguard()
{
m_lGrdCnt--;
ReleaseMutex(m_hMutex);
}
// Guard/Unguard can only be accessed by the nested CGuard class.
friend class CResGuard::CGuard;
};
// Instances of this class will be accessed by mutiple threads. So,
// all members of this class (except the constructor and destructor)
// must be thread-safe.
template <class TYPE>
class CInterlockedType
{
private:
TYPE * m_pTVal;
protected:
mutable CResGuard m_rg;
public:
// Public member functions
// Note: Constructors & destructors are always thread safe
CInterlockedType(TYPE * const pTVal) : m_rg( pTVal )
{
m_pTVal = pTVal;
}
virtual ~CInterlockedType()
{
}
// Cast operator to make writing code that uses
// thread-safe data type easier
operator TYPE() const
{
CResGuard::CGuard x(m_rg);
return(GetVal());
}
protected: // Protected function to be called by derived class
TYPE& GetVal()
{
assert(m_rg.IsGuarded());
return(*m_pTVal);
}
const TYPE& GetVal() const
{
assert(m_rg.IsGuarded());
return(*m_pTVal);
}
TYPE SetVal(const TYPE& TNewVal)
{
assert(m_rg.IsGuarded());
TYPE& TVal = GetVal();
if (TVal != TNewVal)
{
TYPE TPrevVal = TVal;
TVal = TNewVal;
OnValChanged(TNewVal, TPrevVal);
}
return(TVal);
}
protected: // Overridable functions
virtual void OnValChanged(const TYPE& TNewVal, const TYPE& TPrevVal) const
{
// Nothing to do here
}
};
// Instances of this class will be accessed by mutiple threads. So,
// all members of this class (except the constructor and destructor)
// must be thread-safe.
template <class TYPE>
class CSysGlobalScalar : protected CInterlockedType<TYPE>
{
public:
CSysGlobalScalar(TYPE * pTVal) : CInterlockedType<TYPE>(pTVal)
{
}
~CSysGlobalScalar()
{
}
// C++ does not allow operator cast to be inherited.
operator TYPE() const
{
return(CInterlockedType<TYPE>::operator TYPE());
}
TYPE operator=(TYPE TVal)
{
CResGuard::CGuard x(m_rg);
return(SetVal(TVal));
}
TYPE operator++(int) // Postfix increment operator
{
CResGuard::CGuard x(m_rg);
TYPE TPrevVal = GetVal();
SetVal(TPrevVal + 1);
return(TPrevVal); // Return value BEFORE increment
}
TYPE operator--(int) // Postfix decrement operator.
{
CResGuard::CGuard x(m_rg);
TYPE TPrevVal = GetVal();
SetVal(TPrevVal - 1);
return(TPrevVal); // Return value BEFORE decrement
}
TYPE operator += (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() + op)); }
TYPE operator++()
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() + 1)); }
TYPE operator -= (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() - op)); }
TYPE operator--()
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() - 1)); }
TYPE operator *= (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() * op)); }
TYPE operator /= (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() / op)); }
TYPE operator %= (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() % op)); }
TYPE operator ^= (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() ^ op)); }
TYPE operator &= (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() & op)); }
TYPE operator |= (TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() | op)); }
TYPE operator <<=(TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() << op)); }
TYPE operator >>=(TYPE op)
{ CResGuard::CGuard x(m_rg); return(SetVal(GetVal() >> op)); }
};
// CSysGlobalHandle
//
// Same as CSysGlobalScalar, but without all the operators that would
// work on only scalars
template <class TYPE>
class CSysGlobalHandle : protected CInterlockedType<TYPE>
{
public:
CSysGlobalHandle(TYPE * pTVal) : CInterlockedType<TYPE>(pTVal)
{
}
~CSysGlobalHandle()
{
}
// C++ does not allow operator cast to be inherited.
operator TYPE() const
{
return(CInterlockedType<TYPE>::operator TYPE());
}
TYPE operator=(TYPE TVal)
{
CResGuard::CGuard x(m_rg);
return(SetVal(TVal));
}
};
// Instances of this class will be accessed by mutiple threads. So,
// all members of this class (except the constructor and destructor)
// must be thread-safe.
template <class TYPE> class CInverseSemaphore :
public CSysGlobalScalar<TYPE>
{
public:
CInverseSemaphore(TYPE * pTVal, BOOL fManualReset = TRUE) : CSysGlobalScalar<TYPE>(pTVal)
{
// The event should be signaled if TVal is 0
m_hevtZero = CreateEvent(NULL, fManualReset, (*pTVal == 0), NULL);
// The event should be signaled if TVal is NOT 0
m_hevtNotZero = CreateEvent(NULL, fManualReset, (*pTVal != 0), NULL);
}
~CInverseSemaphore()
{
CloseHandle(m_hevtZero);
CloseHandle(m_hevtNotZero);
}
// C++ does not allow operator= to be inherited.
TYPE operator=(TYPE x)
{
return(CSysGlobalScalar<TYPE>::operator=(x));
}
// Return handle to event signaled when value is zero
operator HANDLE() const
{
return(m_hevtZero);
}
// Return handle to event signaled when value is not zero
HANDLE GetNotZeroHandle() const
{
return(m_hevtNotZero);
}
// C++ does not allow operator cast to be inherited.
operator TYPE() const
{
return(CSysGlobalScalar<TYPE>::operator TYPE());
}
protected:
void OnValChanged(const TYPE& TNewVal, const TYPE& TPrevVal) const
{
// For best performance, avoid jumping to
// kernel mode if we don't have to
if ((TNewVal == 0) && (TPrevVal != 0))
{
SetEvent(m_hevtZero);
ResetEvent(m_hevtNotZero);
}
if ((TNewVal != 0) && (TPrevVal == 0))
{
ResetEvent(m_hevtZero);
SetEvent(m_hevtNotZero);
}
}
private:
HANDLE m_hevtZero; // Signaled when data value is 0
HANDLE m_hevtNotZero; // Signaled when data value is not 0
};
#endif // __SYSGLOB_H__