windows-nt/Source/XPSP1/NT/com/ole32/ih/olesem.hxx
2020-09-26 16:20:57 +08:00

560 lines
18 KiB
C++

///+---------------------------------------------------------------------------
//
// File: olesem.hxx
//
// Contents: Semaphore classes for use in OLE code
//
// Classes: COleStaticMutexSem - Mutex semaphore class for statically
// allocated objects
// COleDebugMutexSem - Mutex semaphore class for statically
// allocated objects that are not destructed
// on DLL unload (and thus are leaks..used
// for trace packages and such).
//
// History: 14-Dec-95 Jeffe Initial entry, derived from
// sem32.hxx by AlexT.
//
// Notes: This module defines a set of classes to wrap WIN32
// Critical Sections.
//
// Note the distinction of allocation class: the reason for this
// is to avoid static constructors and destructors.
//
// The classes in this module *must* be used for mutex semaphores
// that are statically allocated. Use the classes in sem32.hxx
// for dynamically allocated (from heap or on the stack) objects.
//
//----------------------------------------------------------------------------
#ifndef __OLESEM_HXX__
#define __OLESEM_HXX__
#include <windows.h>
#if LOCK_PERF==1
#include <lockperf.hxx>
#endif
//+---------------------------------------------------------------------------
//
// Macros for use in the code.
//
//----------------------------------------------------------------------------
#if DBG==1
#if LOCK_PERF==1
#define LOCK_WRITE(mxs) mxs.AcquireWriterLock(__FILE__, __LINE__, #mxs)
#define LOCK_READ(mxs) mxs.AcquireReaderLock(__FILE__, __LINE__, #mxs)
#else
#define LOCK_WRITE(mxs) mxs.AcquireWriterLock()
#define LOCK_READ(mxs) mxs.AcquireReaderLock()
#endif
#define LOCK(mxs) mxs.Request(__FILE__, __LINE__, #mxs)
#define FAST_LOCK(mxs) mxs.FastRequest(__FILE, __LINE__, #mxs)
#define UNLOCK_WRITE(mxs) mxs.ReleaseWriterLock()
#define UNLOCK_READ(mxs) mxs.ReleaseReaderLock()
#define UNLOCK(mxs) mxs.Release()
#if LOCK_PERF==1
#define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f, __FILE__, __LINE__, #mxs)
#define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck, __FILE__, __LINE__, #mxs)
#define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck, NULL, __FILE__, __LINE__, #mxs)
#else
#define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f)
#define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck)
#define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck)
#endif
#define LOCK_RELEASE(mxs, ck) mxs.ReleaseLock(ck)
#define ASSERT_LOCK_HELD(mxs) mxs.AssertHeld()
#define ASSERT_LOCK_NOT_HELD(mxs) mxs.AssertNotHeld()
#define ASSERT_LOCK_DONTCARE(mxs) // just exists to comment the code better
#define ASSERT_LOCK_TAKEN_ONLY_ONCE(mxs) mxs.AssertTakenOnlyOnce()
#define ASSERT_HELD_CONTINUOS_START(mxs) mxs.AssetHeldContinousStart()
#define ASSERT_HELD_CONTINUOS_FINISH(mxs) mxs.AssetHeldContinousFinish()
#define ASSERT_WRITE_LOCK_HELD(mxs) mxs.AssertWriterLockHeld()
#define ASSERT_READ_LOCK_HELD(mxs) mxs.AssertReaderLockHeld()
#define ASSERT_RORW_LOCK_HELD(mxs) mxs.AssertReaderOrWriterLockHeld()
#define STATIC_LOCK(name, mxs) COleStaticLock name(mxs, __FILE__, __LINE__, #mxs)
#define STATIC_WRITE_LOCK(name, mxs) CStaticWriteLock name(mxs, __FILE__, __LINE__, #mxs)
#else // DBG!=1
#if LOCK_PERF==1
#define LOCK_WRITE(mxs) mxs.AcquireWriterLock(__FILE__, __LINE__, #mxs)
#define LOCK_READ(mxs) mxs.AcquireReaderLock(__FILE__, __LINE__, #mxs)
#define LOCK(mxs) mxs.Request(__FILE__, __LINE__, #mxs)
#define FAST_LOCK(mxs) mxs.FastRequest(__FILE__, __LINE__,#mxs)
#else
#define LOCK_WRITE(mxs) mxs.AcquireWriterLock()
#define LOCK_READ(mxs) mxs.AcquireReaderLock()
#define LOCK(mxs) mxs.Request()
#define FAST_LOCK(mxs) mxs.FastRequest()
#endif
#define UNLOCK_WRITE(mxs) mxs.ReleaseWriterLock()
#define UNLOCK_READ(mxs) mxs.ReleaseReaderLock()
#define UNLOCK(mxs) mxs.Release()
#if LOCK_PERF==1
#define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f, __FILE__, __LINE__, #mxs)
#define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck, __FILE__, __LINE__, #mxs)
#define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck, NULL, __FILE__, __LINE__, #mxs)
#else
#define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f)
#define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck)
#define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck)
#endif
#define LOCK_RELEASE(mxs, ck) mxs.ReleaseLock(ck)
#define ASSERT_LOCK_HELD(mxs)
#define ASSERT_LOCK_NOT_HELD(mxs)
#define ASSERT_LOCK_DONTCARE(mxs)
#define ASSERT_LOCK_TAKEN_ONLY_ONCE(mxs)
#define ASSERT_HELD_CONTINUOS_START(mxs)
#define ASSERT_HELD_CONTINUOS_FINISH(mxs)
#define ASSERT_WRITE_LOCK_HELD(mxs)
#define ASSERT_READ_LOCK_HELD(mxs)
#define ASSERT_RORW_LOCK_HELD(mxs)
#if LOCK_PERF==1
#define STATIC_LOCK(name, mxs) COleStaticLock name(mxs,__FILE__, __LINE__,#mxs)
#define STATIC_WRITE_LOCK(name, mxs) CStaticWriteLock name(mxs, __FILE__, __LINE__,#mxs)
#else
#define STATIC_LOCK(name, mxs) COleStaticLock name(mxs)
#define STATIC_WRITE_LOCK(name, mxs) CStaticWriteLock name(mxs)
#endif
#endif // DBG!=1
//
// List of initialized static mutexes (which must be destroyed
// during DLL exit). We know that PROCESS_ATTACH and PROCESS_DETACH
// are thread-safe, so we don't protect this list with a critical section.
//
class COleStaticMutexSem;
extern COleStaticMutexSem * g_pInitializedStaticMutexList;
//
// Critical section used to protect the creation of other semaphores
//
extern CRITICAL_SECTION g_OleMutexCreationSem;
//
// Critical section used as the backup lock when a COleStaticMutexSem
// cannot be faulted in.
//
extern CRITICAL_SECTION g_OleGlobalLock;
#if DBG
//
// DLL states used to ensure we don't use the wrong type of
// semaphore at the wrong time
//
typedef enum _DLL_STATE_
{
DLL_STATE_STATIC_CONSTRUCTING = 0,
DLL_STATE_NORMAL,
DLL_STATE_PROCESS_DETACH,
DLL_STATE_STATIC_DESTRUCTING,
DLL_STATE_COUNT
} DLL_STATE, * PDLL_STATE;
//
// Flag used to indicate if we're past executing the C++ constructors
// during DLL initialization
//
extern DLL_STATE g_fDllState;
#endif // DBG
//+---------------------------------------------------------------------------
//
// Class: COleStaticMutexSem (mxs)
//
// Purpose: This class defines a mutual exclusion semaphore for use in
// objects that are statically allocated (extern or static storage
// class).
//
// Interface: FastRequest - acquire semaphore an already-initialized
// semaphore
// Request - acquire semaphore
// Release - release semaphore
// ReleaseFn - release semaphore (non inline version)
//
// History: 14-Dec-95 JeffE Initial entry.
//
// Notes: This class must NOT be used in dynamically allocated objects!
//
// This class uses the fact that static objects are initialized
// by C++ to all zeroes.
//
//----------------------------------------------------------------------------
class COleStaticMutexSem
{
public:
COleStaticMutexSem(BOOLEAN fUseSpincount);
COleStaticMutexSem();
// This pointer *must* be the first member in this class
class COleStaticMutexSem * pNextMutex;
#if DBG==1 || LOCK_PERF==1
private:
// The following track lock usage for debugging purposes
DWORD _dwTid; // Thread id of the thread currently holding the lock, 0 if free
DWORD _cLocks; // Number of times the thread has taken the lock
const char *_pszFile; // Filename of the code which last took the lock
DWORD _dwLine; // Line number of the code which last took the lock
BOOL _fTakeOnce; // Lock is to be taken only once
ULONG _cContinuous;// ensure the lock is not released while count is positive
public:
#if DBG==1 || LOCK_PERF==1
const char *_pszLockName;// Name of the lock (eg. gComLock)
#endif
#endif // DBG==1
BOOLEAN _fInitialized;// has the lock been initialized
BOOLEAN _fUsingGlobal;// are we using the global lock?
BOOLEAN _fAutoDestruct;
BOOLEAN _fUseSpincount;
HRESULT Init();
void Destroy();
#if DBG==1 || LOCK_PERF==1
void FastRequest(const char *pszFile, DWORD dwLine,const char *pszLockName);
inline void FastRequest();
void Request(const char *pszFile, DWORD dwLine, const char *pszLockName);
void Release();
#else // DBG!=1
void FastRequest();
inline void Release();
#endif // DBG==1
void Request();
// debugging/diagnostic functions
#if DBG==1
void AssertHeld(DWORD cLocks=0);
void AssertNotHeld();
void AssertTakenOnlyOnce();
void AssetHeldContinousStart() { _cContinuous++; }
void AssetHeldContinousFinish() { Win4Assert(_cContinuous); _cContinuous--; }
#else // DBG!=1
inline void AssertHeld(DWORD cLocks=0) {;}
inline void AssertNotHeld() {;}
inline void AssertTakenOnlyOnce() {;}
inline void AssetHeldContinousStart() {;}
inline void AssetHeldContinousFinish() {;}
#endif // DBG==1
#ifdef _CHICAGO_
// This is present for rpccall.asm which cannot use the inline version
void ReleaseFn();
#endif // _CHICAGO_
// The following definition *should* be private...but C-10 insists on supplying
// an empty constructor if we use it. Since it doesn't really matter, we just
// don't use it in retail builds.
#if DBG==1
private:
#endif // DBG
CRITICAL_SECTION _cs;
};
#if DBG==1
//+---------------------------------------------------------------------------
//
// Class: COleDebugMutexSem (mxs)
//
// Purpose: This class defines a mutual exclusion semaphore for use in
// objects that are statically allocated (extern or static storage
// class) but are not destructed when the DLL unloads.
//
// Interface: FastRequest - acquire semaphore an already-initialized
// semaphore
// Request - acquire semaphore
// Release - release semaphore
//
// History: 14-Dec-95 JeffE Initial entry.
//
// Notes: This class must only be used in staticly allocated objects!
//
// This class may only be used in CHECKED builds...since it doesn't
// clean up after itself on DLL unload.
//
//----------------------------------------------------------------------------
class COleDebugMutexSem : public COleStaticMutexSem
{
public:
COleDebugMutexSem();
};
#endif // DBG==1
//+---------------------------------------------------------------------------
//
// Class: COleStaticLock (lck)
//
// Purpose: Lock using a static (or debug) Mutex Semaphore
//
// History: 02-Oct-91 BartoszM Created.
//
// Notes: Simple lock object to be created on the stack.
// The constructor acquires the semaphor, the destructor
// (called when lock is going out of scope) releases it.
//
//----------------------------------------------------------------------------
class COleStaticLock
{
public:
#if DBG==1 || LOCK_PERF==1
COleStaticLock ( COleStaticMutexSem& mxs, const char * pszFile, DWORD dwLine, const char *pszLockName );
#endif // DBG==1 || LOCK_PERF==1
COleStaticLock ( COleStaticMutexSem& mxs );
~COleStaticLock ();
private:
COleStaticMutexSem& _mxs;
};
//+---------------------------------------------------------------------------
//
// Class: CMutexSem2 (mxs)
//
// Purpose: Mutex Semaphore services. Created this version because CMutexSem will
// raise exceptions. CMutexSem2 uses the Rtl* functions and will not raise
// exceptions.
// will not throw
//
// Interface: Init - initializer (two-step)
// Request - acquire semaphore
// Release - release semaphore
//
// History: 19-Mar-01 danroth Created.
//
// Notes: This class wraps a mutex semaphore. Mutex semaphores protect
// access to resources by only allowing one client through at a
// time. The client Requests the semaphore before accessing the
// resource and Releases the semaphore when it is done. The
// same client can Request the semaphore multiple times (a nest
// count is maintained).
// The mutex semaphore is a wrapper around a critical section
// which does not support a timeout mechanism. Therefore the
// usage of any value other than INFINITE is discouraged. It
// is provided merely for compatibility.
//
//----------------------------------------------------------------------------
class CMutexSem2
{
public:
CMutexSem2();
BOOL FInit();
~CMutexSem2();
void Request();
void Release();
BOOL FInitialized() { return m_fCsInitialized; }
private:
CRITICAL_SECTION m_cs;
BOOL m_fCsInitialized;
};
//+---------------------------------------------------------------------------
//
// Class: CLock2(lck)
//
// Purpose: Lock using a Mutex Semaphore
//
// History: 20-Mar-01 danroth Created.
//
// Notes: Simple lock object to be created on the stack.
// The constructor acquires the semaphor, the destructor
// (called when lock is going out of scope) releases it.
//
//----------------------------------------------------------------------------
class CLock2
{
public:
CLock2(CMutexSem2& mxs) : m_mxs(mxs)
{
m_mxs.Request();
}
~CLock2() { m_mxs.Release(); }
private:
CMutexSem2& m_mxs;
};
//+---------------------------------------------------------------------------
//
// Member: COleStaticMutexSem::FastRequest
//
// Synopsis: Acquire the semaphore without checking to see if it's
// initialized. If another thread already has it,
// wait until it is released.
//
// History: 14-Dec-1995 Jeffe
//
// Notes: You may only use this method on code paths where you're
// *certain* the semaphore has already been initialized (either
// by invoking Init, or by calling the Request method).
//
//----------------------------------------------------------------------------
#if DBG!=1 && LOCK_PERF!=1
inline void COleStaticMutexSem::FastRequest()
{
Win4Assert (_fInitialized && "You must use Request here, not FastRequest");
if (!_fUsingGlobal)
EnterCriticalSection (&_cs);
else
EnterCriticalSection (&g_OleGlobalLock);
}
#endif // DBG!=1
//+---------------------------------------------------------------------------
//
// Member: COleStaticMutexSem::Release
//
// Synopsis: Release the semaphore.
//
// History: 14-Dec-1995 Jeffe
//
//----------------------------------------------------------------------------
#if DBG!=1 && LOCK_PERF!=1
inline void COleStaticMutexSem::Release()
{
if (!_fUsingGlobal)
LeaveCriticalSection (&_cs);
else
LeaveCriticalSection (&g_OleGlobalLock);
}
#endif
#if DBG==1 || LOCK_PERF==1
//+---------------------------------------------------------------------------
//
// Member: COleStaticMutexSem::COleStaticMutexSem
//
// Synopsis: Debug constructor: ensure we weren't allocated dynamically.
//
// History: 14-Dec-1995 Jeffe
//
//----------------------------------------------------------------------------
inline COleStaticMutexSem::COleStaticMutexSem()
{
Win4Assert (g_fDllState == DLL_STATE_STATIC_CONSTRUCTING);
_dwTid = 0;
_cLocks = 0;
_dwLine = 0;
_pszFile = "";
_pszLockName = "";
_fTakeOnce = FALSE;
_cContinuous = 0;
}
#else
inline COleStaticMutexSem::COleStaticMutexSem() {}
#endif // DBG
//+---------------------------------------------------------------------------
//
// Member: COleStaticMutexSem::COleStaticMutexSem(BOOLEAN fUseSpincount)
//
// Synopsis: Construct the Mutex with a spin count.
//
// History: 14-Apr-2000 ScottRob
//
//----------------------------------------------------------------------------
inline COleStaticMutexSem::COleStaticMutexSem(BOOLEAN fUseSpincount)
{
#if DBG==1 || LOCK_PERF==1
COleStaticMutexSem::COleStaticMutexSem();
#endif // DBG
_fUseSpincount = fUseSpincount;
}
//+---------------------------------------------------------------------------
//
// Member: COleStaticLock::COleStaticLock
//
// Synopsis: Acquire semaphore
//
// History: 02-Oct-91 BartoszM Created.
//
//----------------------------------------------------------------------------
#if DBG==1 || LOCK_PERF==1
inline COleStaticLock::COleStaticLock ( COleStaticMutexSem& mxs, const char * pszFile, DWORD dwLine, const char *pszLockName ) : _mxs ( mxs )
{
_mxs.Request(pszFile, dwLine, pszLockName);
}
#endif // DBG==1
inline COleStaticLock::COleStaticLock ( COleStaticMutexSem& mxs)
: _mxs ( mxs )
{
#if DBG==1 || LOCK_PERF==1
_mxs.Request("Unknown File", 0L, "Unknown Lock");
#else // DBG!=1
_mxs.Request();
#endif // DBG==1
}
//+---------------------------------------------------------------------------
//
// Member: COleStaticLock::~COleStaticLock
//
// Synopsis: Release semaphore
//
// History: 02-Oct-91 BartoszM Created.
//
//----------------------------------------------------------------------------
inline COleStaticLock::~COleStaticLock ()
{
_mxs.Release();
}
// include the reader/writer lock
#include <rwlock.hxx>
#endif // _OLESEM_HXX