windows-nt/Source/XPSP1/NT/com/oleutest/stgbvt/comtools/h/syncwrap.hxx
2020-09-26 16:20:57 +08:00

617 lines
20 KiB
C++

//+-------------------------------------------------------------------
//
// File: syncwrap.hxx
//
// Contents: Wrapper classes for Win32 synchronization objects.
//
// Classes: CMutex - Creates/destroys a Mutex object
// CSemaphore - Creates/destroys a Semaphore object
// CEvent - Creates/destroys an Event object
// CCritSec - Creates/destroys a critical section
// CTCLock - Locks/Unlock one of the above
//
// Functions:
//
// History: 31-Jan-92 BryanT Created
// 04-Feb-92 BryanT Added Critical section support
// 23-Feb-92 BryanT Add OS/2 support for a Critical
// section-like synchronization object.
// Code is stolen from tom\dispatcher
// semaphore class.
// 26-Jun-92 DwightKr Added ifndef MIDL
// 29-Jun-93 DwightKr Changed MIDL to MIDL_PASS *
// 08-Nov-93 DarrylA Changed __WIN32__ to WIN32
// 16-Mar-95 NaveenB Changed NO_ERROR to ERROR_SUCCESS
// and added facility to check the
// status of the constructor using
// QueryError functions in CMutex,
// CSemaphone, CEvent and CTCLock
//
//--------------------------------------------------------------------
#ifndef SYNCWRAP_HXX
#define SYNCWRAP_HXX
#ifndef MIDL_PASS
#if defined (WIN32)
// Make sure windows.h has been included prior to this
#if !defined (_WINDOWS_)
#error windows.h must be included prior to syncwrap.hxx... Aborting.
#endif
#define CMUTEX 1
#define CSEMAPHORE 2
#define CEVENT 3
#define CCRITSEC 4
#ifndef STATUS_POSSIBLE_DEADLOCK
typedef LONG NTSTATUS;
#define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS)0xC0000194L)
#endif
//+-------------------------------------------------------------------
//
// Class: CMutex
//
// Purpose: Wrapper for Win32 Mutexes. Creates an un-named, un-owned
// mutex in an un-signaled state and makes sure it is cleaned
// up when destructed.
//
// Interface: CMutex(lpsa, fInitialOwner, lpszMutexName, fCreate) -
// See CreateMutex/OpenMutex in the Win32 api for the
// definition of the first three arguments. The last
// one indicates if a new mutex should be created
// (TRUE) or an existing one opened (FALSE). If no name
// is used, this flag will be ignored and an unnamed
// mutex will be created.
// By default, the arguments are set to NULL, FALSE, NULL,
// and TRUE to create an unowned, unnamed mutex with
// no particular security attributes.
//
// ~CMutex() - Destroys the handle that is created in the
// constructor. If this is the last instance of
// a handle to this Mutex, the OS will destroy
// the mutex.
//
// History: 31-Jan-92 BryanT Created
//
// Notes: The error code of the constructor can be obtained by
// calling the QueryError function and if everything
// goes well, the ERROR_SUCCESS is returned by the call
// to QueryError.
// It is important that no virtual pointers are defined
// in this class and the member varaible _mutex is the first
// variable defined in this class.
//
//--------------------------------------------------------------------
class CMutex
{
friend class CTCLock;
public:
inline CMutex( LPSECURITY_ATTRIBUTES lpsa = NULL,
BOOL fInitialOwner = FALSE,
LPTSTR lpszMutexName = NULL,
BOOL fCreate = TRUE)
{
if ((FALSE == fCreate) && (NULL != lpszMutexName))
{
_mutex = OpenMutex(MUTANT_ALL_ACCESS,
FALSE,
lpszMutexName);
}
else
{
_mutex = CreateMutex(lpsa, fInitialOwner, lpszMutexName);
}
_dwLastError = (_mutex == NULL) ? GetLastError() : ERROR_SUCCESS;
}
inline ~CMutex()
{
CloseHandle(_mutex);
}
inline DWORD QueryError()
{
return _dwLastError;
}
private:
HANDLE _mutex;
DWORD _dwLastError;
};
//+-------------------------------------------------------------------
//
// Class: CSemaphore
//
// Purpose: Wrapper for Win32 semaphores. Creates a semaphore in the
// constructor. Deletes it in the destructor.
//
// Interface: CSemaphore( lpsa, cSemInitial, cSemMax, lpszSemName, fCreate)
// See CreateSemaphore in Win32 API docs for detail
// of the first three arguments. The last indicates
// if a new semaphore should be created (TRUE) or an
// existing one opened (FALSE). In the case of
// opening an existing semaphore, all access rights
// will be requested and the handle will not be
// inherited by any child processes that are created
// by the calling process. By default, an
// unnamed semaphore with a initial count of 1 (not
// used) a maximum count of 1 and no security
// attributes will be created.
//
// ~CSemaphore - Destroys the semaphore
//
// History: 31-Jan-92 BryanT Created
//
// Notes: The error code of the constructor can be obtained by
// calling the QueryError function and if everything
// goes well, the ERROR_SUCCESS is returned by the call
// to QueryError.
// It is important that no virtual pointers are defined
// in this class and the member varaible _semaphore is the first
// variable defined in this class.
//
//--------------------------------------------------------------------
class CSemaphore
{
friend class CTCLock;
public:
inline CSemaphore( LPSECURITY_ATTRIBUTES lpsa = NULL,
LONG cSemInitial = 1,
LONG cSemMax = 1,
LPTSTR lpszSemName = NULL,
BOOL fCreate = TRUE)
{
if ((FALSE == fCreate) && (lpszSemName != NULL))
{
_semaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS,
FALSE,
lpszSemName);
}
else
{
_semaphore = CreateSemaphore(lpsa,
cSemInitial,
cSemMax,
lpszSemName);
}
_dwLastError = (_semaphore == NULL) ? GetLastError() : ERROR_SUCCESS;
}
inline ~CSemaphore()
{
CloseHandle(_semaphore);
}
inline DWORD QueryError()
{
return _dwLastError;
}
private:
HANDLE _semaphore;
DWORD _dwLastError;
};
//+-------------------------------------------------------------------
//
// Class: CEvent
//
// Purpose: Wrapper for Win32 Events. Creates an event in the constructor.
// deletes it in the destructor.
//
// Interface: CEvent(lpsa, fManualReset, fInitialState, lpszName, fCreate)
// See Win32 API docs for details of first three
// arguments. The last argument inicates whether a new
// event should be created (TRUE) or an existing named
// event should be opened. It no name is specified,
// an unnamed event will be created and this argument is
// ignored. By default, an unnamed, unowned event
// will be created with no security attributes. It
// will automatically reset.
//
// ~CEvent() - Destroys the event.
//
// History: 31-Jan-92 BryanT Created
//
// Notes: The error code of the constructor can be obtained by
// calling the QueryError function and if everything
// goes well, the ERROR_SUCCESS is returned by the call
// to QueryError.
// It is important that no virtual pointers are defined
// in this class and the member varaible _event is the first
// variable defined in this class.
//
//--------------------------------------------------------------------
class CEvent
{
friend class CTCLock;
public:
inline CEvent(LPSECURITY_ATTRIBUTES lpsa = NULL,
BOOL fManualReset = FALSE,
BOOL fInitialState = FALSE,
LPTSTR lpszName = NULL,
BOOL fCreate = TRUE)
{
if ((FALSE == fCreate) && (lpszName != NULL))
{
_event = OpenEvent(EVENT_ALL_ACCESS,
FALSE,
lpszName);
}
else
{
_event = CreateEvent(lpsa,
fManualReset,
fInitialState,
lpszName);
}
_dwLastError = (_event == NULL) ? GetLastError() : ERROR_SUCCESS;
}
inline ~CEvent()
{
CloseHandle(_event);
}
inline DWORD QueryError()
{
return _dwLastError;
}
private:
HANDLE _event;
DWORD _dwLastError;
};
//+-------------------------------------------------------------------
//
// Class: CCritSec
//
// Purpose: Wrapper for Win32 Critical Sections. Creates an critical
// section in the constructor and deletes it in the destructor.
//
// Interface: CCritSec() - Creates a critical section
//
// ~CCritSec() - Destroys the critical section
//
// History: 04-Feb-92 BryanT Created
//
// Notes: For this code, there really isn't any exceptions that
// I can trap (or return). Therefore, this class is finished.
//
//--------------------------------------------------------------------
class CCritSec
{
friend class CTCLock;
public:
inline CCritSec()
{
InitializeCriticalSection(&_CritSec);
}
inline ~CCritSec()
{
DeleteCriticalSection( &_CritSec );
}
private:
CRITICAL_SECTION _CritSec;
};
//+-------------------------------------------------------------------
//
// Class: CTCLock
//
// Purpose: Provide lock/unlock capabilities for one of the
// synchrnization objects (CMutex, CSemaphore, CEvent, or
// CCritSec). If no timeout is specified, INFINITE timeout is
// used. In the case of an event, no lock is actually obtained.
// Instead, we wait till the event occurs. For a critical
// section object, no timeout argument is needed.
//
// Interface: CTCLock(CMutex, dwTimeOut) - Obtain a lock on a mutex.
// CTCLock(CSemaphore, dwTimeOut) - Obtain a lock on a semaphore.
// CTCLock(CEvent, dwTimeOut) - Wait for this event to occur.
// CTCLock(CCritSec) - Enter this critical section.
//
// ~CTCLock() - Release/leave the object
//
// _dwLastError -
// The error code from the last operation on this
// object. If successfully constructed/destructed
// it should be ERROR_SUCCESS.
//
// History: 31-Jan-92 BryanT Created
// 23-Feb-92 BryanT Add _dwLastError in order to be
// compatible with the OS/2 version.
// 29-Jan-93 BryanT Continue the Critical Section if it times
// out (340 does this now).
// 26-Apr-96 MikeW Mac doesn't support SEH so #ifdef out
// the continue.
//
// Notes: The error code of the constructor can be obtained by
// calling the QueryError function and if everything
// goes well, the ERROR_SUCCESS is returned by the call
// to QueryError.
//
//--------------------------------------------------------------------
class CTCLock
{
public:
inline CTCLock(CMutex& cm, DWORD dwTimeOut = INFINITE)
{
if ((_dwLastError = cm.QueryError()) == ERROR_SUCCESS)
{
_lock = cm._mutex;
_idLock = CMUTEX;
_dwLastError = WaitForSingleObject(_lock, dwTimeOut);
}
}
inline CTCLock(CSemaphore& cs, DWORD dwTimeOut = INFINITE)
{
if ((_dwLastError = cs.QueryError()) == ERROR_SUCCESS)
{
_lock = cs._semaphore;
_idLock = CSEMAPHORE;
_dwLastError = WaitForSingleObject(_lock, dwTimeOut);
}
}
inline CTCLock(CEvent& ce, DWORD dwTimeOut = INFINITE)
{
if ((_dwLastError = ce.QueryError()) == ERROR_SUCCESS)
{
_lock = ce._event;
_idLock = CEVENT;
_dwLastError = WaitForSingleObject(_lock, dwTimeOut);
}
}
inline CTCLock(CCritSec& ccs)
{
_idLock = CCRITSEC;
_lpcs = &ccs._CritSec;
#ifndef _MAC
_try
#endif
{
EnterCriticalSection(_lpcs);
}
#ifndef _MAC
_except (GetExceptionCode() == STATUS_POSSIBLE_DEADLOCK ?
EXCEPTION_CONTINUE_EXECUTION :
EXCEPTION_CONTINUE_SEARCH){}
#endif
_dwLastError = ERROR_SUCCESS;
}
inline ~CTCLock()
{
switch (_idLock)
{
case CMUTEX:
if (ReleaseMutex(_lock) == TRUE)
_dwLastError = ERROR_SUCCESS;
else
_dwLastError = GetLastError();
break;
case CSEMAPHORE:
if (ReleaseSemaphore(_lock, 1, NULL) == TRUE)
_dwLastError = ERROR_SUCCESS;
else
_dwLastError = GetLastError();
break;
case CEVENT:
_dwLastError = ERROR_SUCCESS;
break;
case CCRITSEC:
LeaveCriticalSection(_lpcs);
_dwLastError = ERROR_SUCCESS;
break;
}
}
inline DWORD QueryError()
{
return _dwLastError;
}
private:
union
{
HANDLE _lock;
LPCRITICAL_SECTION _lpcs;
};
INT _idLock;
DWORD _dwLastError;
};
#elif defined (__OS2__) // defined (WIN32)
#ifndef SEM_TIMEOUT
#define SEM_TIMEOUT SEM_INDEFINITE_WAIT
#endif
#ifndef _MT
#error ERROR: Must Build for Multi-thread.
#endif
#ifndef _INC_STDDEF
#include <stddef.h> // For _threadid in CTCLock code
#endif
#include <assert.h> // For assert() code
//+-------------------------------------------------------------------
//
// Class: CCritSec
//
// Purpose: Define an OS/2 version of a Win32 critical section. In
// other words, define a synchronization onject that can be
// entered any number of times by one thread without waiting.
// Keeps a count of number of times it is entered and the TID
// of who currently has access.
//
// Interface: CCritSec() - Creates a critical section
//
// ~CCritSec() - Destroys the critical section
//
// History: 23-Feb-92 BryanT Created
//
// Notes: For this code, there really isn't any exceptions that
// I can trap (or return). Therefore, this class is finished.
//
//--------------------------------------------------------------------
class CCritSec
{
friend class CTCLock;
public:
inline CCritSec()
{
// Initialize everything to zero.
hSem = 0;
tid = 0;
cLockCount = 0;
}
inline ~CCritSec()
{
#if defined(TRACE)
if (cLockCount != 0)
{
fprintf(stderr,
"CCritSec object destructed with %d locks",
cLockCount);
fprintf(stderr,
" outstanding by TID: %x\n",
tid);
}
#endif
}
private:
HSEM hSem; // Exclusive use RAM semaphore
TID tid; // The thread owning the semaphore
USHORT cLockCount; // # times semaphore locked
};
//+-------------------------------------------------------------------
//
// Class: CTCLock
//
// Purpose: Provide OS/2 lock/unlock capabilities for a CCritSec
// synchrnization object.
//
// Interface: CTCLock(CCritSec) - Enter this critical section.
//
// ~CTCLock() - Release/leave the object
//
// _usLastError - The error code from the last operation on this
// object. If successfully constructed/destructed
// it should be ERROR_SUCCESS.
//
// History: 23-Feb-92 BryanT Created
//
// Notes: This is the OS/2 version of Win32 critical sections.
// By default, the timeout will be SEM_INDEFINITE_WAIT. If
// you wish to change this, merely define SEM_TIMEOUT before
// including this file.
//
//--------------------------------------------------------------------
class CTCLock
{
public:
inline CTCLock(CCritSec& ccs)
{
// Is the semaphore already in use?
if (ERROR_SEM_TIMEOUT == (_usLastError = DosSemRequest(&ccs.hSem,
SEM_IMMEDIATE_RETURN)))
{
// If it's us, increment the counter and return.
if (ccs.tid == *_threadid)
{
ccs.cLockCount++; // Increment the lock counter
_usLastError = ERROR_SUCCESS;
_pCritSec = &ccs;
return;
}
}
// Either it's not in use or we don't own it. Wait for access.
// Once obtained, store the appropriate data and return.
if ((ERROR_SUCCESS == _usLastError) ||
(ERROR_SUCCESS == (_usLastError = DosSemRequest(&ccs.hSem,SEM_TIMEOUT))))
{
ccs.tid = *_threadid;
ccs.cLockCount = 1;
_pCritSec = &ccs;
}
else
{
_pCritSec = NULL; // Indicate we don't have it
}
return;
}
inline ~CTCLock()
{
//
// The lock counter should always be > 0. If not, then we don't
// have a matching lock for every unlock.
//
if (_pCritSec == NULL)
{
_usLastError = ERROR_SUCCESS;
return;
}
assert (_pCritSec->cLockCount > 0);
_pCritSec->cLockCount--;
if (_pCritSec->cLockCount == 0)
{
_pCritSec->tid = 0;
_usLastError = DosSemClear(&(_pCritSec->hSem));
return;
}
else
{
_usLastError = ERROR_SUCCESS;
return;
}
}
USHORT _usLastError;
private:
CCritSec * _pCritSec;
};
#endif // Defined __OS2__ or WIN32
#endif // ifndef MIDL_PASS
#endif // #ifndef SYNCWRAP_HXX