Leaked source code of windows server 2003
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.
 
 
 
 
 
 

820 lines
17 KiB

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// SYNCHRO.H
//
// Header for DAV synchronization classes.
//
// Copyright 1986-1998 Microsoft Corporation, All Rights Reserved
//
#ifndef _EX_SYNCHRO_H_
#define _EX_SYNCHRO_H_
#include <caldbg.h> // for Assert/DebugTrace/etc
// ========================================================================
//
// CLASS CCriticalSection
//
// Implements a critical section around a Win32 CRITICAL_SECTION.
//
// Adds safety by explicitly disallowing copying (copying a raw
// CRITICAL_SECTION can cause very unpredictable and hard to debug
// behavior -- trust me).
//
// Automatically cleans up the CRITICAL_SECTION resource when done.
//
class CCriticalSection
{
// The critical section
//
CRITICAL_SECTION m_cs;
// NOT IMPLEMENTED
//
CCriticalSection& operator=( const CCriticalSection& );
CCriticalSection( const CCriticalSection& );
public:
// CREATORS
//
CCriticalSection()
{
InitializeCriticalSection(&m_cs);
#ifdef DBG
m_cLockRefs = 0;
m_dwLockOwnerThreadId = 0;
#endif
}
~CCriticalSection()
{
DeleteCriticalSection(&m_cs);
}
BOOL FTryEnter()
{
if ( TryEnterCriticalSection (&m_cs) ) {
#ifdef DBG
Assert (
m_dwLockOwnerThreadId == GetCurrentThreadId() ||
( m_cLockRefs == 0 && m_dwLockOwnerThreadId == 0 )
);
m_dwLockOwnerThreadId = GetCurrentThreadId ();
m_cLockRefs++;
#endif
return TRUE;
}
else
return FALSE;
}
void Enter()
{
EnterCriticalSection(&m_cs);
#ifdef DBG
Assert (
m_dwLockOwnerThreadId == GetCurrentThreadId() ||
( m_cLockRefs == 0 && m_dwLockOwnerThreadId == 0 )
);
m_dwLockOwnerThreadId = GetCurrentThreadId ();
m_cLockRefs++;
#endif
}
void Leave()
{
#ifdef DBG
Assert ( m_cLockRefs > 0 );
Assert ( m_dwLockOwnerThreadId != 0 );
m_cLockRefs--;
if ( m_cLockRefs == 0 ) {
m_dwLockOwnerThreadId = 0;
}
#endif
LeaveCriticalSection(&m_cs);
}
void AssertLocked ( ) const
{
#ifdef DBG
// This routine allows us to verify our correctness even when
// running in the single-threaded case.
//
// If this assert fires, it means that nobody has the lock:
AssertSz ( m_cLockRefs > 0, "Calling method without the lock." );
// If this assert fires, it means that somebody else has the lock:
AssertSz ( m_dwLockOwnerThreadId == GetCurrentThreadId(),
"Calling method, but another thread owns the lock!" );
#endif
}
private:
#ifdef DBG
// # of Lock() calls - # of Unlock() calls. Used by AssertInLock()
DWORD m_cLockRefs;
// Thread ID of the current lock owner (or 0 if unowned).
DWORD m_dwLockOwnerThreadId;
#endif
};
// ========================================================================
//
// CLASS CSynchronizedBlock
//
// Synchronizes (serializes) any block of code in which an instance of
// this class is declared on the critical section with which it
// is initialized.
//
// To use, just declare one of these in the block you want synchronized:
//
// ...
// {
// CSynchronizedBlock sb(critsec);
//
// //
// // Do some stuff that must be synchronized
// //
// ...
//
// //
// // Do more synchronized stuff
// //
// ...
// }
//
// //
// // Do stuff that doesn't have to be synchronized
// //
// ...
//
// and the block is automatically synchronized. Why bother? Because
// you don't need to have any cleanup code; the critical section is
// automatically released when execution leaves the block, even if via
// an exception thrown from any of the synchronized stuff.
//
class CSynchronizedBlock
{
// The critical section
//
CCriticalSection& m_cs;
// NOT IMPLEMENTED
//
CSynchronizedBlock& operator=( const CSynchronizedBlock& );
CSynchronizedBlock( const CSynchronizedBlock& );
public:
// CREATORS
//
CSynchronizedBlock( CCriticalSection& cs ) :
m_cs(cs)
{
m_cs.Enter();
}
~CSynchronizedBlock()
{
m_cs.Leave();
}
};
#include <except.h>
// ========================================================================
//
// CLASS CEvent
//
// Implements an event around a Win32 event handle resource.
//
class CEvent
{
// NOT IMPLEMENTED
//
CEvent& operator=(const CEvent&);
CEvent(const CEvent&);
protected:
HANDLE m_hevt;
public:
CEvent() : m_hevt(NULL) {}
BOOL FInitialized() const
{
return m_hevt && m_hevt != INVALID_HANDLE_VALUE;
}
~CEvent()
{
if ( FInitialized() )
{
CloseHandle( m_hevt );
}
}
BOOL FCreate( LPSECURITY_ATTRIBUTES lpsa,
BOOL fManualReset,
BOOL fSignalled,
LPCWSTR lpwszEventName,
BOOL fDontMungeTheEventName = FALSE)
{
Assert( !FInitialized() );
// create event does not take backslashes. so replace
// them with ? which won't be part of URI at this point.
//
//$HACK
// ARGH! Who put this slash-munging hack in here? Modifying a
// const parameter and munging the name. Most events are smart
// enough not to use backward slashes in their names since they
// aren't allowed by the underlying Win32 API, CreateEvent()....
//
// At any rate, this is not good in the Terminal Server case which
// must prefix event names with either "Global\" or "Local\" (note
// the backslash!)
//
// So the hack upon a hack here (fDontMungeTheEventName) is for
// callers who really can be trusted to know what they are doing.
// Unfortunately, short of grepping a lot of sources, there is
// no way of knowing who can and can't be trusted, so we have to
// assume the worst.
//
if (!fDontMungeTheEventName)
{
LPWSTR lpwszTemp = const_cast<LPWSTR>(lpwszEventName);
if (lpwszTemp)
{
while( NULL != (lpwszTemp = wcschr (lpwszTemp, L'\\')) )
{
lpwszTemp[0] = L'?';
}
}
}
m_hevt = CreateEventW( lpsa,
fManualReset,
fSignalled,
lpwszEventName );
// According to MSDN, if the creation fails, CreateEvent returns NULL, not
// INVALID_HANDLE_VALUE. We'll just do a quick DBG check to make sure we never
// see INVALID_HANDLE_VALUE here.
//
Assert(INVALID_HANDLE_VALUE != m_hevt);
if ( !m_hevt )
return FALSE;
return TRUE;
}
void Set()
{
Assert( FInitialized() );
SideAssert( SetEvent(m_hevt) );
}
void Reset()
{
Assert( FInitialized() );
SideAssert( ResetEvent(m_hevt) );
}
void Wait()
{
Assert( FInitialized() );
SideAssert( WaitForSingleObject( m_hevt, INFINITE ) == WAIT_OBJECT_0 );
}
void AlertableWait()
{
Assert( FInitialized() );
DWORD dwResult;
do
{
dwResult = WaitForSingleObjectEx( m_hevt, INFINITE, TRUE );
Assert( dwResult != 0xFFFFFFFF );
}
while ( dwResult == WAIT_IO_COMPLETION );
Assert( dwResult == WAIT_OBJECT_0 );
}
};
// ========================================================================
//
// CLASS CMRWLock
//
// Implements a multi-reader, single writer-with-promote lock for
// efficient, thread-safe access of a per-process resource.
//
class CMRWLock
{
//
// The implementation uses a really clever trick where
// the high bit of the reader count is reserved for use
// as a one-bit flag that it set whenever there is a
// writer in the lock or waiting to enter it.
//
// Combining the reader count and a writer flag into
// a single DWORD allows InterlockedXXX() calls to
// be used to manipulate the two pieces of information
// atomically as part of a spinlock which eliminates
// the need for an entering reader to pass through
// a critical section.
//
// Entering a critical section, even for the short amount
// of time necessary to get a reader into the lock,
// drastically impacts the performance of heavily used
// process-wide locks.
//
//
// The write lock bit
//
enum { WRITE_LOCKED = 0x80000000 };
//
// Critical section to allow only one writer at a time.
//
CCriticalSection m_csWriter;
//
// ThreadID of the thread that owns the write lock.
// This value is 0 when no one owns the write lock.
//
DWORD m_dwWriteLockOwner;
//
// Promoter recursion count used to allow a single thread
// which holds the promote/write lock to reenter the lock.
//
DWORD m_dwPromoterRecursion;
//
// Event signalled when a writer leaves the lock to
// allow blocked readers to enter.
//
CEvent m_evtEnableReaders;
//
// Event signalled when the last reader leaves the lock
// to allow a blocked writer to enter.
//
CEvent m_evtEnableWriter;
//
// Count of readers plus a flag bit (WRITE_LOCKED)
// indicating whether a writer owns the lock or is
// waiting to enter it.
//
LONG m_lcReaders;
BOOL FAcquireReadLock(BOOL fAllowCallToBlock);
// NOT IMPLEMENTED
//
CMRWLock& operator=(const CMRWLock&);
CMRWLock(const CMRWLock&);
public:
// CREATORS
//
CMRWLock();
BOOL FInitialize();
~CMRWLock() {};
// MANIPULATORS
//
void EnterRead();
BOOL FTryEnterRead();
void LeaveRead();
void EnterWrite();
BOOL FTryEnterWrite();
void LeaveWrite();
void EnterPromote();
BOOL FTryEnterPromote();
void LeavePromote();
void Promote();
};
// ========================================================================
//
// CLASS CCrossThreadLock
//
// Implements a simple mutual exclusion lock to guard access to objects.
// This object can be locked and unlocked from different threads (difference
// from critsec-style locks).
//
// ONLY USE THIS LOCK IF YOU _REALLY_ _REALLY_ NEED CROSS-THREAD
// LOCK/UNLOCK CAPABILITY.
//
// Possible future plans for improvement:
// o This object currently sets NULL for lpSemaphoreAttributes. This will
// not allow the lock to be used cross-process or from a different
// user security context.
// o This object always specifies an INFINITE timeout. In the future, there
// could be an optional parameter to FEnter that allows you to set
// something other than INFINITE.
//
class
CCrossThreadLock
{
HANDLE m_hSemaphore;
// NOT IMPLEMENTED
//
CCrossThreadLock& operator=(const CCrossThreadLock&);
CCrossThreadLock(const CCrossThreadLock&);
public:
CCrossThreadLock() :
m_hSemaphore(NULL)
{ }
~CCrossThreadLock()
{
if (NULL != m_hSemaphore)
CloseHandle(m_hSemaphore);
}
BOOL FInitialize()
{
BOOL fSuccess = FALSE;
m_hSemaphore = CreateSemaphore(NULL, // lpSemaphoreAttributes
1, // lInitialCount
1, // lMaximumCount
NULL); // lpName
// According to MSDN, if the creation fails, CreateSemaphore returns NULL, not
// INVALID_HANDLE_VALUE. We'll just do a quick DBG check to make sure we never
// see INVALID_HANDLE_VALUE here.
//
Assert(INVALID_HANDLE_VALUE != m_hSemaphore);
if (NULL == m_hSemaphore)
goto Exit;
fSuccess = TRUE;
Exit:
return fSuccess;
}
BOOL FEnter(DWORD dwTimeOut = INFINITE)
{
Assert(NULL != m_hSemaphore);
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hSemaphore,
dwTimeOut))
return TRUE;
return FALSE;
}
VOID Leave()
{
Assert(NULL != m_hSemaphore);
if (!ReleaseSemaphore(m_hSemaphore,
1,
NULL))
{
DebugTrace("CCrossThreadLock::Leave(): Failed to release semaphore, last error 0x%08lX.\n",
GetLastError());
TrapSz("CCrossThreadLock::Leave(): Failed to release semaphore!\n");
}
}
};
// ========================================================================
//
// CLASS CGate
//
// Implements gating mechanism, that alows to close the EXECUTION PATH and
// push out all the threads using it. Very usefull on shutdown scenarios.
//
// Here is a sketch of the gate usage:
//
// ...
//
// {
// CGatedBlock gb(gate);
//
// if (gb.FIsGateOpen())
// {
// ...
// EXECUTION PATH that is to be gated
// ...
// }
// else
// {
// ...
// Do whatever has to be done if EXECUTION PATH
// is not to be executed any more
// ...
// }
// }
// ...
//
class CGate
{
// Number of users in the zone framed by this gate
//
LONG m_lcUsers;
// Flag indicating if the gate is open
//
BOOL m_fClosed;
// NOT IMPLEMENTED
//
CGate& operator=(const CGate&);
CGate(const CGate&);
public:
// The fact that all member variables of the class are
// 0 on creation, allows to use it as a static variable
// without additional burden of explicit initialization
//
CGate() : m_lcUsers(0),
m_fClosed(FALSE) {};
// INITIALIZER
//
inline
VOID Init()
{
m_lcUsers = 0;
m_fClosed = FALSE;
}
// MANIPULATORS
//
inline
VOID Enter()
{
InterlockedIncrement(&m_lcUsers);
}
inline
VOID Leave()
{
InterlockedDecrement(&m_lcUsers);
}
inline
VOID Close()
{
// Mark the gate as closed
//
m_fClosed = TRUE;
// Wait until all the threads that use execution
// path framed by this gate will leave the zone
// it is framing. As FIsOpen() call is allowed only
// inside the gated zone, we will know that after
// this call returns there is no thread thinking
// that the gate is still open
//
while (0 != m_lcUsers)
{
Sleep(200);
}
}
// ACCESSORS
//
inline
BOOL FIsOpen()
{
// We must be in the gated zone in order
// to be able to determine if the gate is
// open.
//
Assert(m_lcUsers > 0);
return !m_fClosed;
}
};
// ========================================================================
//
// TEMPLATE CLASS SynchronizedReadBlock
//
template<class _Lock>
class SynchronizedReadBlock
{
// The read/write lock
//
_Lock& m_lock;
// NOT IMPLEMENTED
//
SynchronizedReadBlock& operator=( const SynchronizedReadBlock& );
SynchronizedReadBlock( const SynchronizedReadBlock& );
public:
SynchronizedReadBlock (_Lock& mrw)
: m_lock(mrw)
{
m_lock.EnterRead();
}
~SynchronizedReadBlock()
{
m_lock.LeaveRead();
}
};
typedef SynchronizedReadBlock<CMRWLock> CSynchronizedReadBlock;
// ========================================================================
//
// TEMPLATE CLASS CSynchronizedWriteBlock
//
template<class _Lock>
class SynchronizedWriteBlock
{
// The read/write lock
//
_Lock& m_lock;
// NOT IMPLEMENTED
//
SynchronizedWriteBlock& operator=( const SynchronizedWriteBlock& );
SynchronizedWriteBlock( const SynchronizedWriteBlock& );
public:
SynchronizedWriteBlock (_Lock& mrw)
: m_lock(mrw)
{
m_lock.EnterWrite();
}
~SynchronizedWriteBlock()
{
m_lock.LeaveWrite();
}
};
typedef SynchronizedWriteBlock<CMRWLock> CSynchronizedWriteBlock;
// ========================================================================
//
// TEMPLATE CLASS TryWriteBlock
//
// Like SynchronizedWriteBlock except that the block must be
// entered via the FTryEnter() method. A return value of TRUE
// from FTryEnter() indicates the lock is entered.
//
template<class _Lock>
class TryWriteBlock
{
// The read/write lock
//
_Lock& m_lock;
// TRUE if write lock entered
//
BOOL m_fLocked;
// NOT IMPLEMENTED
//
TryWriteBlock& operator=( const TryWriteBlock& );
TryWriteBlock( const TryWriteBlock& );
public:
TryWriteBlock (_Lock& mrw) :
m_lock(mrw),
m_fLocked(FALSE)
{
}
BOOL FTryEnter()
{
return m_fLocked = m_lock.FTryEnterWrite();
}
~TryWriteBlock()
{
if ( m_fLocked )
m_lock.LeaveWrite();
}
};
typedef TryWriteBlock<CMRWLock> CTryWriteBlock;
// ========================================================================
//
// TEMPLATE CLASS SynchronizedPromoteBlock
//
template<class _Lock>
class SynchronizedPromoteBlock
{
// The read/write lock
//
_Lock& m_lock;
// NOT IMPLEMENTED
//
SynchronizedPromoteBlock& operator=( const SynchronizedPromoteBlock& );
SynchronizedPromoteBlock( const SynchronizedPromoteBlock& );
public:
SynchronizedPromoteBlock (_Lock& mrw)
: m_lock(mrw)
{
m_lock.EnterPromote();
}
~SynchronizedPromoteBlock()
{
m_lock.LeavePromote();
}
void Promote()
{
m_lock.Promote();
}
};
typedef SynchronizedPromoteBlock<CMRWLock> CSynchronizedPromoteBlock;
// ========================================================================
//
// TEMPLATE CLASS GatedBlock
//
template<class _Gate>
class GatedBlock
{
// The gate
//
_Gate& m_gate;
// NOT IMPLEMENTED
//
GatedBlock& operator=( const GatedBlock& );
GatedBlock( const GatedBlock& );
public:
GatedBlock (_Gate& gate)
: m_gate(gate)
{
m_gate.Enter();
}
BOOL FGateIsOpen()
{
return m_gate.FIsOpen();
}
~GatedBlock()
{
m_gate.Leave();
}
};
typedef GatedBlock<CGate> CGatedBlock;
// ========================================================================
//
// InterlockedExchangeOr - A multithread safe way to OR bits into a LONG
//
LONG InterlockedExchangeOr( LONG * plVariable, LONG lOrBits );
#endif // !_EX_SYNCHRO_H_