|
|
//+-------------------------------------------------------------------
//
// 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
|