// File: Sem.Hxx // Contents: Semaphore classes // Classes: CMutexSem - Mutex semaphore class // CShareSem - Multiple Reader, Single Writer class // CEventSem - Event semaphore // History: 21-Jun-91 AlexT Created. // Notes: No 32-bit implementation exists yet for these classes, it // will be provided when we have a 32-bit development // environment. In the meantime, the 16-bit implementations // provided here can be used to ensure your code not blocking // while you hold a semaphore. #ifndef __SEM32_HXX__ #define __SEM32_HXX__ #define INHERIT_UNWIND_IF_CAIRO #define DECLARE_UNWIND #define END_CONSTRUCTION(class) #define INLINE_UNWIND(cls) #define IMPLEMENT_UNWIND(cls) /* extern "C" { #include }; #include */ // This is temporary. To be moved to the appropriate error file // BUGBUG: use NT error codes. Conversion is expensive! (BartoszM) enum SEMRESULT { SEMSUCCESS = 0, SEMTIMEOUT, SEMNOBLOCK, SEMERROR }; enum SEMSTATE { SEMSHARED, SEMSHAREDOWNED }; // BUGBUG: inlcude winbase.h or some such // infinite timeout when requesting a semaphore #if !defined INFINITE #define INFINITE 0xFFFFFFFF #endif // Class: CMutexSem (mxs) // Purpose: Mutex Semaphore services // Interface: Init - initializer (two-step) // Request - acquire semaphore // Release - release semaphore // History: 14-Jun-91 AlexT Created. // 30-oct-91 SethuR 32 bit implementation // 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 CMutexSem { public: CMutexSem(); inline BOOL Init(); ~CMutexSem(); SEMRESULT Request(DWORD dwMilliseconds = INFINITE); void Release(); private: CRITICAL_SECTION _cs; }; // Class: CLock (lck) // Purpose: Lock using a 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 CLock INHERIT_UNWIND_IF_CAIRO { EXPORTDEF DECLARE_UNWIND public: CLock ( CMutexSem& mxs ); ~CLock (); private: CMutexSem& _mxs; }; // Class: CEventSem (evs) // Purpose: Event Semaphore services // Interface: Wait - wait for semaphore to be signalled // Set - set signalled state // Reset - clear signalled state // Pulse - set and clear semaphore // History: 21-Jun-91 AlexT Created. // 27-Feb-92 BartoszM Use exceptions for errors // Notes: Used for communication between consumers and producers. // Consumer threads block by calling Wait. A producer // calls Set waking up all the consumers who go ahead // and consume until there's nothing left. They call // Reset, release whatever lock protected the resources, // and call Wait. There has to be a separate lock // to protect the shared resources. // Remember: call Reset under lock. // don't call Wait under lock. class CEventSem { public: inline CEventSem( BOOL fInitState=FALSE, const LPSECURITY_ATTRIBUTES lpsa=NULL ) { _hEvent = CreateEvent ( lpsa, TRUE, fInitState, 0 ); if ( _hEvent == 0 ) { //XTHROW ( CSystemException ( GetLastError() )); } } inline CEventSem( HANDLE hEvent ) : _hEvent( hEvent ) { } inline ~CEventSem(); inline ULONG Wait(DWORD dwMilliseconds = INFINITE, BOOL fAlertable = FALSE ); inline void Set(); inline void Reset(); inline void Pulse(); inline const HANDLE GetHandle() const { return _hEvent; } private: HANDLE _hEvent; }; #if 0 // BUGBUG: This class is superceded by CResource, in resource.hxx and // resource.cxx. It should be deleted by July 21, 1993 // WadeR, July 8, 1883 // Class: CShareSem (shs) // Purpose: Shared Semaphore services // Interface: RequestExclusive - acquire exclusive ownership // RequestShared - acquire shared access // RequestSharedOwned - acquire ownership, allowing shared access // Release - release semaphore // Upgrade - upgrade from SharedOwned to Exclusive // Downgrade - downgrade to SharedOwned or Shared // History: 21-Jun-91 AlexT Created. // Notes: Shared semaphores allow multiple readers/single writers // access to resources. Readers bracket their use of a resource // with calls to RequestShared and Release. Writers bracket // their use of a resource with calls to RequestExclusive and // Release. // RequestSharedOwned gives a client ownership of the semaphore // but still allows other Readers to share the semaphore. At // some later point, the owning client can call Upgrade to get // Exclusive access to the semaphore. This is useful when a // client needs to examine a data structure before modifying it, // as it allows other clients to continue viewing the data // until the owning client actually needs to modify it. // Downgrade allows a client to release ownership of a semaphore // without releasing access to it. // For now, this just uses a mutex semaphore. // BUGBUG -- Ownership related methods needs to be implemented. class CShareSem { public: CShareSem(); BOOL Init(); ~CShareSem(); SEMRESULT RequestExclusive(DWORD dwMilliseconds); SEMRESULT RequestShared(DWORD dwMilliseconds); SEMRESULT RequestSharedOwned(DWORD dwMilliseconds); void Release(); SEMRESULT Upgrade(DWORD dwMilliseconds); SEMRESULT Downgrade(SEMSTATE fl); private: // Ownership related methods.... BOOL ClaimOwnership(); BOOL ReleaseOwnership(); // Private methods to facilitate code sharing void EnableReaders(); CMutexSem _cmtx; CEventSem _evsReaders; CEventSem _evsWriters; BOOL _fWrite; ULONG _cReaders; ULONG _cWaitingReaders; ULONG _cWaitingWriters; }; // Class: CShareSemObject // Purpose: The Semaphore Object -- the constructor accquires the // semaphore and the destructor releases it. // Interface: // History: 05-July-91 SethuR Created. class CShareSemObject INHERIT_UNWIND_IF_CAIRO { DECLARE_UNWIND public: inline CShareSemObject(CShareSem& shs); inline ~CShareSemObject(); inline void RequestExclusive(DWORD dw); inline void RequestShared(DWORD dw); inline void RequestSharedOwned(DWORD dw); inline SEMRESULT Upgrade(DWORD dw); inline void Downgrade(SEMSTATE ss); private: CShareSem* _pshs; BOOL _fAccquired; }; // Member: CShareSemObject::CShareSemObject, public // Synopsis: Constructor // Arguments: [shs] -- shared semaphore // History: 29-Aug-91 SethuR Created. inline CShareSemObject::CShareSemObject(CShareSem& shs) { _pshs = &shs; _fAccquired = FALSE; END_CONSTRUCTION(CShareSemObject) } // Member: CShareSemObject::RequestExclusive, public // Synopsis: Get Exclusive acess // Arguments: [dwMilliseconds] -- Timeout value // History: 29-Aug-91 SethuR Created. inline void CShareSemObject::RequestExclusive(DWORD dw) { if (_pshs->RequestExclusive(dw) == SEMSUCCESS) _fAccquired = TRUE; else THROW (CException(Win4ErrSemaphoreInvalid)); } // Member: CShareSemObject::RequestShared, public // Synopsis: Get allow shared access // Arguments: [dwMilliseconds] -- Timeout value // History: 29-Aug-91 SethuR Created. inline void CShareSemObject::RequestShared(DWORD dw) { if (_pshs->RequestSharedOwned(dw) == SEMSUCCESS) _fAccquired = TRUE; else THROW (CException(Win4ErrSemaphoreInvalid)); } // Member: CShareSemObject::RequestSharedOwned, public // Synopsis: Get ownership but allow shared access // Arguments: [dwMilliseconds] -- Timeout value // History: 29-Aug-91 SethuR Created. inline void CShareSemObject::RequestSharedOwned(DWORD dw) { if (_pshs->RequestSharedOwned(dw) == SEMSUCCESS) _fAccquired = TRUE; else THROW (CException(Win4ErrSemaphoreInvalid)); } // Member: CShareSemObject::~CShareSemObject, public // Synopsis: Destructor -- Releases the semaphore if accquired // History: 27-Aug-91 AlexT Created. inline CShareSemObject::~CShareSemObject() { if (_fAccquired) _pshs->Release(); } // Member: CShareSemObject::Upgrade, public // Synopsis: Get exclusive access (must have ownership already) // Arguments: [dwMilliseconds] -- Timeout value // History: 21-Jun-91 AlexT Created. inline SEMRESULT CShareSemObject::Upgrade(DWORD dw) { if (_fAccquired) return _pshs->Upgrade(dw); THROW (CException(Win4ErrSemaphoreInvalid)); return SEMTIMEOUT; // BUGBUG -- This is to satisfy compiler limitation } // Member: CShareSemObject::Downgrade, public // Synopsis: Release exclusive access (but keep access) // Arguments: [fl] -- SEMSHARED or SEMSHAREDOWNED // History: 21-Jun-91 AlexT Created. inline void CShareSemObject::Downgrade(SEMSTATE ss) { if (_fAccquired) _pshs->Downgrade(ss); else THROW (CException(Win4ErrSemaphoreInvalid)); return; } #endif // 0 BUGBUG // Member: CMutexSem::CMutexSem, public // Synopsis: Mutex semaphore constructor // Effects: Initializes the semaphores data // History: 14-Jun-91 AlexT Created. inline CMutexSem::CMutexSem() { Init(); } inline CMutexSem::Init() { InitializeCriticalSection(&_cs); return TRUE; }; // Member: CMutexSem::~CMutexSem, public // Synopsis: Mutex semaphore destructor // Effects: Releases semaphore data // History: 14-Jun-91 AlexT Created. inline CMutexSem::~CMutexSem() { DeleteCriticalSection(&_cs); } // Member: CMutexSem::Request, public // Synopsis: Acquire semaphore // Effects: Asserts correct owner // Arguments: [dwMilliseconds] -- Timeout value // History: 14-Jun-91 AlexT Created. // Notes: Uses GetCurrentTask to establish the semaphore owner, but // written to work even if GetCurrentTask fails. inline SEMRESULT CMutexSem::Request(DWORD dwMilliseconds) { dwMilliseconds; EnterCriticalSection(&_cs); return(SEMSUCCESS); } // Member: CMutexSem::Release, public // Synopsis: Release semaphore // Effects: Asserts correct owner // History: 14-Jun-91 AlexT Created. // Notes: Uses GetCurrentTask to establish the semaphore owner, but // written to work even if GetCurrentTask fails. inline void CMutexSem::Release() { LeaveCriticalSection(&_cs); } // Member: CLock::CLock // Synopsis: Acquire semaphore // History: 02-Oct-91 BartoszM Created. inline CLock::CLock ( CMutexSem& mxs ) : _mxs ( mxs ) { _mxs.Request ( INFINITE ); END_CONSTRUCTION (CLock); } // Member: CLock::~CLock // Synopsis: Release semaphore // History: 02-Oct-91 BartoszM Created. inline CLock::~CLock () { _mxs.Release(); } #ifdef EVENT_SEM //#include "except.hxx" #define XTHROW(x) //#define CSystemException CException // Member: CEventSem::CEventSem // Synopsis: Creates an event // Arguments: [bInitState] -- TRUE: signaled state, FALSE non-signaled // [lpsa] -- security attributes // History: 27-Feb-92 BartoszM Created /* inline CEventSem::CEventSem ( BOOL bInitState, const LPSECURITY_ATTRIBUTES lpsa ) { _hEvent = CreateEvent ( lpsa, TRUE, bInitState, 0 ); if ( _hEvent == 0 ) { XTHROW ( CSystemException ( GetLastError() )); } } */ // Member: CEventSem::CEventSem // Synopsis: Opens an event // Arguments: [hEvent] -- handle of event to open // [bInitState] -- TRUE: signaled state, FALSE non-signaled // History: 02-Jul-94 DwightKr Created /* inline CEventSem::CEventSem ( HANDLE hEvent ) : _hEvent( hEvent ) { } */ // Member: CEventSem::~CEventSem // Synopsis: Releases event // History: 27-Feb-92 BartoszM Created inline CEventSem::~CEventSem () { if ( !CloseHandle ( _hEvent ) ) { XTHROW ( CSystemException ( GetLastError() )); } } // Member: CEventSem::Set // Synopsis: Set the state to signaled. Wake up waiting threads. // For manual events the state remains set // until Reset is called // History: 27-Feb-92 BartoszM Created inline void CEventSem::Set() { if ( !SetEvent ( _hEvent ) ) { XTHROW ( CSystemException ( GetLastError() )); } } // Member: CEventSem::Reset // Synopsis: Reset the state to non-signaled. Threads will block. // History: 27-Feb-92 BartoszM Created inline void CEventSem::Reset() { if ( !ResetEvent ( _hEvent ) ) { XTHROW ( CSystemException ( GetLastError() )); } } // Member: CEventSem::Wait // Synopsis: Block until event set // History: 27-Feb-92 BartoszM Created inline ULONG CEventSem::Wait( DWORD msec, BOOL fAlertable ) { DWORD res = WaitForSingleObjectEx ( _hEvent, msec, fAlertable ); if ( res < 0 ) { XTHROW ( CSystemException ( GetLastError() )); } return(res); } // Member: CEventSem::Pulse // Synopsis: Set the state to signaled. Wake up waiting threads. // History: 27-Feb-92 BartoszM Created inline void CEventSem::Pulse() { if ( !PulseEvent ( _hEvent ) ) { XTHROW ( CSystemException ( GetLastError() )); } } #endif //EVENT_SEM #endif /* __SEM32_HXX__ */