Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

545 lines
14 KiB

//+---------------------------------------------------------------------------
//
// 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() );
}
}