//+------------------------------------------------------------------- // // 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 // For _threadid in CTCLock code #endif #include // 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