546 lines
14 KiB
C++
546 lines
14 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1991 - 2000.
|
||
|
//
|
||
|
// File: CiSem.Hxx
|
||
|
//
|
||
|
// Contents: Semaphore classes
|
||
|
//
|
||
|
// Classes: CMutexSem - Mutex semaphore class
|
||
|
// CStaticMutexSem - statically allocated Mutex semaphore class
|
||
|
// CEventSem - Event semaphore
|
||
|
//
|
||
|
// History: 21-Jun-91 AlexT Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CMutexSem (mxs)
|
||
|
//
|
||
|
// Purpose: Mutex Semaphore services
|
||
|
//
|
||
|
// Interface: 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).
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CMutexSem
|
||
|
{
|
||
|
public:
|
||
|
CMutexSem()
|
||
|
{
|
||
|
InitializeCriticalSection( &_cs );
|
||
|
_fInitedCS = TRUE;
|
||
|
}
|
||
|
|
||
|
CMutexSem(BOOL fInit)
|
||
|
{
|
||
|
if (fInit)
|
||
|
{
|
||
|
InitializeCriticalSection( &_cs );
|
||
|
_fInitedCS = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memset( &_cs, 0, sizeof _cs );
|
||
|
_fInitedCS = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
~CMutexSem()
|
||
|
{
|
||
|
if (_fInitedCS)
|
||
|
{
|
||
|
DeleteCriticalSection( &_cs );
|
||
|
_fInitedCS = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Init()
|
||
|
{
|
||
|
InitializeCriticalSection(&_cs);
|
||
|
_fInitedCS = TRUE;
|
||
|
}
|
||
|
|
||
|
void Request()
|
||
|
{
|
||
|
#if DBG == 1
|
||
|
if (!_fInitedCS)
|
||
|
DbgPrint( "CMutexSem not initialized!\n" );
|
||
|
#endif
|
||
|
EnterCriticalSection( &_cs );
|
||
|
}
|
||
|
|
||
|
void Release()
|
||
|
{
|
||
|
LeaveCriticalSection( &_cs );
|
||
|
}
|
||
|
|
||
|
BOOL Try()
|
||
|
{
|
||
|
return TryEnterCriticalSection( &_cs );
|
||
|
}
|
||
|
|
||
|
BOOL IsHeld()
|
||
|
{
|
||
|
return ( LongToHandle( GetCurrentThreadId() ) == _cs.OwningThread );
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
BOOL _fInitedCS;
|
||
|
CRITICAL_SECTION _cs;
|
||
|
};
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CStaticMutexSem
|
||
|
//
|
||
|
// Purpose: Mutex Semaphore services
|
||
|
//
|
||
|
// Interface: Init - initializer (two-step)
|
||
|
// Request - acquire semaphore
|
||
|
// Release - release semaphore
|
||
|
//
|
||
|
// History: 20 May 99 AlawW Created.
|
||
|
//
|
||
|
// Notes: Like a CMutexSem, but initialization is deferred. Useful
|
||
|
// for statically allocated critical sections where there is
|
||
|
// the (unlikely) potential to get a STATUS_NO_MEMORY exception
|
||
|
// thrown from the InitializeCriticalSection call.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CStaticMutexSem : public CMutexSem
|
||
|
{
|
||
|
public:
|
||
|
CStaticMutexSem( ) : CMutexSem( FALSE ) {}
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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
|
||
|
{
|
||
|
public:
|
||
|
CLock( CMutexSem& mxs ) : _mxs ( mxs )
|
||
|
{
|
||
|
_mxs.Request();
|
||
|
}
|
||
|
|
||
|
~CLock()
|
||
|
{
|
||
|
_mxs.Release();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CMutexSem & _mxs;
|
||
|
};
|
||
|
|
||
|
#define CPriLock CLock
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CReleasableLock
|
||
|
//
|
||
|
// Purpose: Lock using a Mutex Semaphore that can be released/requested
|
||
|
//
|
||
|
// History: 16-Sep-96 dlee Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CReleasableLock
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
CReleasableLock( CMutexSem& mxs, BOOL fHeld = TRUE ) :
|
||
|
_fHeld( fHeld ), _mxs(mxs)
|
||
|
{
|
||
|
if ( fHeld )
|
||
|
_mxs.Request();
|
||
|
}
|
||
|
|
||
|
~CReleasableLock()
|
||
|
{
|
||
|
if ( _fHeld )
|
||
|
_mxs.Release();
|
||
|
}
|
||
|
|
||
|
void Release()
|
||
|
{
|
||
|
Win4Assert( _fHeld );
|
||
|
_mxs.Release();
|
||
|
_fHeld = FALSE;
|
||
|
}
|
||
|
|
||
|
void Request()
|
||
|
{
|
||
|
Win4Assert( !_fHeld );
|
||
|
_mxs.Request();
|
||
|
_fHeld = TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL Try()
|
||
|
{
|
||
|
Win4Assert( !_fHeld );
|
||
|
return ( _fHeld = _mxs.Try() );
|
||
|
}
|
||
|
|
||
|
BOOL IsHeld() const { return _fHeld; }
|
||
|
|
||
|
private:
|
||
|
CMutexSem & _mxs;
|
||
|
BOOL _fHeld;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 );
|
||
|
inline CEventSem( HANDLE hEvent );
|
||
|
inline CEventSem( DWORD dwMustBeZero, WCHAR const * pwszName,
|
||
|
DWORD dwAccess = EVENT_ALL_ACCESS | EVENT_MODIFY_STATE | SYNCHRONIZE );
|
||
|
inline CEventSem( WCHAR const * pwszName,
|
||
|
BOOL fInitState = FALSE,
|
||
|
const LPSECURITY_ATTRIBUTES lpsa = NULL );
|
||
|
|
||
|
HANDLE AcquireHandle()
|
||
|
{
|
||
|
HANDLE hVal = _hEvent;
|
||
|
_hEvent = 0;
|
||
|
return hVal;
|
||
|
}
|
||
|
|
||
|
void Create()
|
||
|
{
|
||
|
Win4Assert( 0 == _hEvent );
|
||
|
|
||
|
_hEvent = CreateEventW( 0, TRUE, FALSE, 0 );
|
||
|
if ( 0 == _hEvent )
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CAutoEventSem
|
||
|
//
|
||
|
// Purpose: Auto-reset version of CEventSem
|
||
|
//
|
||
|
// History: 16-Sep-96 dlee Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CAutoEventSem
|
||
|
{
|
||
|
public:
|
||
|
CAutoEventSem()
|
||
|
{
|
||
|
_hEvent = CreateEventW( 0, FALSE, FALSE, 0 );
|
||
|
if ( 0 == _hEvent )
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
|
||
|
~CAutoEventSem()
|
||
|
{
|
||
|
if ( 0 != _hEvent )
|
||
|
{
|
||
|
BOOL f = CloseHandle ( _hEvent );
|
||
|
Win4Assert( f && "can't close event handle" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Set()
|
||
|
{
|
||
|
if ( !SetEvent ( _hEvent ) )
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
|
||
|
void Wait()
|
||
|
{
|
||
|
WaitForSingleObject( _hEvent, INFINITE );
|
||
|
}
|
||
|
|
||
|
const HANDLE GetHandle() const { return _hEvent; }
|
||
|
|
||
|
private:
|
||
|
HANDLE _hEvent;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CEventSetter
|
||
|
//
|
||
|
// Purpose: Sets an event when exiting scope
|
||
|
//
|
||
|
// History: 16-Sep-96 dlee Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CEventSetter
|
||
|
{
|
||
|
public:
|
||
|
CEventSetter( CAutoEventSem &event ) : _event( event )
|
||
|
{ }
|
||
|
|
||
|
~CEventSetter() { _event.Set(); }
|
||
|
|
||
|
private:
|
||
|
CAutoEventSem & _event;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 = CreateEventW( lpsa, TRUE, bInitState, 0 );
|
||
|
if ( _hEvent == 0 )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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: Constructor to "open" an already existing event sem.
|
||
|
//
|
||
|
// Arguments: [dwMustBeZero] - Just to distinguish from the constructor
|
||
|
// used to "create" named event semaphores.
|
||
|
// [pwszName] - Name of the semaphore
|
||
|
// [dwAccess] - Access.
|
||
|
//
|
||
|
// History: 2-15-96 srikants Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
inline CEventSem::CEventSem( DWORD dwMustBeZero, WCHAR const * pwszName, DWORD dwAccess )
|
||
|
{
|
||
|
Win4Assert( 0 == dwMustBeZero && 0 != pwszName );
|
||
|
|
||
|
_hEvent = OpenEventW( dwAccess, TRUE, pwszName );
|
||
|
if ( 0 == _hEvent )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEventSem::CEventSem
|
||
|
//
|
||
|
// Synopsis: Constructor to "create" a named event semaphore.
|
||
|
//
|
||
|
// Arguments: [pwszName] - Name of the event semaphore.
|
||
|
// [fInitState] -
|
||
|
// [lpsa] -
|
||
|
//
|
||
|
// History: 2-15-96 srikants Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
inline CEventSem::CEventSem( WCHAR const * pwszName, BOOL fInitState,
|
||
|
const LPSECURITY_ATTRIBUTES lpsa )
|
||
|
{
|
||
|
|
||
|
_hEvent = CreateEventW( lpsa, TRUE, fInitState, pwszName );
|
||
|
if ( _hEvent == 0 )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEventSem::~CEventSem
|
||
|
//
|
||
|
// Synopsis: Releases event
|
||
|
//
|
||
|
// History: 27-Feb-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
inline CEventSem::~CEventSem ()
|
||
|
{
|
||
|
if ( 0 != _hEvent )
|
||
|
{
|
||
|
BOOL f = CloseHandle( _hEvent );
|
||
|
Win4Assert( f && "can't close event handle" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 ) )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 ) )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 ( 0xffffffff == res )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
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 ) )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
}
|
||
|
|