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.
 
 
 
 
 
 

583 lines
11 KiB

/*++
Microsoft Windows NT RPC Name Service
Copyright (C) Microsoft Corporation, 1995 - 1999
Module Name:
mutex.hxx
Abstract:
This file contains definitions of classes which provide several variations
on mutexes, including shared and private mutexes, reader/writer mutexes,
and semaphores in the NT sense (which for us are mutexes which can be
acquired and released by different threads).
Author:
Satish Thatte (SatishT) 09/01/95 Created all the code below except where
otherwise indicated.
--*/
#ifndef __MUTEX_HXX__
#define __MUTEX_HXX__
/*++
Class Definition:
CPrivateCriticalSection
Abstract:
This class implements an intra process critical section which allows
only one thread in the process at a time to gain access to resources.
Rather than being the CRITICAL_SECTION itself, the CSharedCriticalSection
contains a pointer to the CRITICAL_SECTION. This isolates the system
dependent code at a tiny expense in compilation speed since all the code
for the methods is inline.
It seems strange to talk of a private critical section -- if it is
really private why use it? The sense in which this class of object is
meant to be private is that CPrivateCriticalSection objects are expected
to have a single reference and a single destruction point and therefore
do not need reference counting.
--*/
class CPrivateCriticalSection {
CRITICAL_SECTION * pNTCS; // Reference to system CRITICAL_SECTION object
// we are impersonating
public:
CPrivateCriticalSection(
);
virtual ~CPrivateCriticalSection(
);
void
Enter(
) ;
void
Leave(
);
};
/*++
Class Definition:
SimpleCriticalSection
Abstract:
A convenient way to acquire and release a lock on a CPrivateCriticalSection.
Entry occurs on creation and exit on destruction of this object, and hence
can be made to coincide with a local scope. Especially convenient when
there are multiple exit points from the scope (returns, breaks, etc.).
--*/
class SimpleCriticalSection {
CPrivateCriticalSection& MyPCS;
public:
SimpleCriticalSection(CPrivateCriticalSection& PCS) : MyPCS(PCS)
{
MyPCS.Enter();
}
~SimpleCriticalSection()
{
MyPCS.Leave();
}
};
/*++
Class Definition:
CSharedCriticalSection
Abstract:
This class implements an intra process critical section which allows
only one thread in the process at a time to gain access to resources.
Continuing the remarks in relation to CPrivateCriticalSection, this
class of object is shared as in "referenced, and released in multiple
other objects" such as guarded lists and iterators, for instance.
Using the primary (impersonated) CRITICAL_SECTION for locking the
reference count is cute but not viable. If the CRITICAL_SECTION
is being held for real locking, just acquiring a reference to the
CSharedCriticalSection object becomes a blocking operation.
--*/
class CSharedCriticalSection : public CRefCounted {
CPrivateCriticalSection PCSprimary; // Reference to system CRITICAL_SECTION object
// we are impersonating
CPrivateCriticalSection PCScount; // CRITICAL_SECTION object used for ref counting
public:
void
Enter(
) ;
void
Leave(
);
virtual void
hold(
);
virtual void
release(
);
};
/*++
Class Definition:
CPrivateSemaphore
Abstract:
This class implements an intra process semaphore which allows
multiple and shared access to resources. The enter and leave
operators are delinked -- they do not have to be performed
by the same thread.
As in the case of a private critical section, a private semaphore
is not meant to be shared as an object, and is not reference counted.
--*/
class CPrivateSemaphore {
HANDLE pNTSem; // Reference to system semaphore object
// we are impersonating
public:
CPrivateSemaphore(long lMaxCount = 1);
~CPrivateSemaphore();
void Enter() ;
void Leave(long lIncrement = 1);
};
/*++
Class Definition:
CReadWriteSection
Abstract:
This class implements a simple solution of the usual readers/writers
problem. The writer block is a semaphore rather than critical section
because it is acquired by the first reader thread and released by the
last one, hence it is not "owned" by any thread at any time.
--*/
class CReadWriteSection : public CRefCounted {
/* PCSReaderBlock: mutex used by writers to block readers and by readers
to guard access to ulReaderCount and PSemWriterBlock.
*/
CPrivateCriticalSection PCSReaderBlock;
/* PSemWriterBlock: semaphore used by readers to block writers. This is a
semaphore because the first reader blocks it and the last one releases it,
which doesn't work with critical sections!
*/
CPrivateSemaphore PSemWriterBlock;
/* The reason we use an explicit lock instead of InterlockedIncrement etc is
that we need to lock out access to reader count not only to change its
value but also to decide on taking or releasing the writer block.
*/
CPrivateCriticalSection PCSCountBlock;
long ulReaderCount;
public:
CReadWriteSection();
int
readerEnter(
) ;
int
readerLeave(
);
void
writerEnter(
) ;
void
writerLeave(
);
};
/*++
Class Definition:
CriticalWriter
Abstract:
A convenient way to acquire and release a writer-lock on a CReadWriteSection.
Entry occurs on creation and exit on destruction of this object, and hence
can be made to coincide with a local scope. Especially convenient when
there are multiple exit points from the scope (returns, breaks, etc.).
--*/
class CriticalWriter {
CReadWriteSection& rwHost;
public:
CriticalWriter(CReadWriteSection& rw) : rwHost(rw) {
DBGOUT(SEM1, "Starting Construction of Critical Writer\n\n");
rwHost.writerEnter();
DBGOUT(SEM1, "Ending Construction of Critical Writer\n\n");
}
~CriticalWriter() {
DBGOUT(SEM1, "Starting Destruction of Critical Writer\n\n");
rwHost.writerLeave();
DBGOUT(SEM1, "Ending Destruction of Critical Writer\n\n");
}
};
/*++
Class Definition:
CriticalReader
Abstract:
A convenient way to acquire and release a reader-lock on a CReadWriteSection.
Entry occurs on creation and exit on destruction of this object, and hence
can be made to coincide with a local scope. Especially convenient when
there are multiple exit points from the scope (returns, breaks, etc.).
--*/
class CriticalReader {
CReadWriteSection& rwHost;
public:
CriticalReader(CReadWriteSection& rw) : rwHost(rw) {
DBGOUT(SEM1, "Starting Construction of Critical Reader\n\n");
rwHost.readerEnter();
DBGOUT(SEM1, "Ending Construction of Critical Reader\n\n");
}
~CriticalReader() {
DBGOUT(SEM1, "Starting Destruction of Critical Reader\n\n");
rwHost.readerLeave();
DBGOUT(SEM1, "Ending Destruction of Critical Reader\n\n");
}
};
/******** inline methods for CPrivateCriticalSection ********/
inline
CPrivateCriticalSection::CPrivateCriticalSection (
)
/*++
Routine Description:
Rather than being the CRITICAL_SECTION itself, the CPrivateCriticalSection
contains a pointer to the CRITICAL_SECTION. This isolates the system
dependent code at a tiny expense in compilation speed since all the code
for the methods is inline.
Results:
None unless an exception occurs.
--*/
{
if ((pNTCS = new RTL_CRITICAL_SECTION))
InitializeCriticalSection(pNTCS);
else RaiseException(
NSI_S_OUT_OF_MEMORY,
EXCEPTION_NONCONTINUABLE,
0,
NULL
);
}
inline
CPrivateCriticalSection::~CPrivateCriticalSection (
)
/*++
Routine Description:
Delete the NT critical section object and the memory it uses.
--*/
{
DeleteCriticalSection(pNTCS);
delete pNTCS;
}
inline void
CPrivateCriticalSection::Leave (
)
/*++
Routine Description:
Clear the CPrivateCriticalSection indicating that the current thread is done with it.
--*/
{
LeaveCriticalSection(pNTCS);
}
inline void
CPrivateCriticalSection::Enter (
)
/*++
Routine Description:
Request exclusive access to the CPrivateCriticalSection. This routine will
not return until the current thread has exclusive access to the
CSharedCriticalSection.
--*/
{
EnterCriticalSection(pNTCS);
}
/******** inline methods for CSharedCriticalSection ********/
inline void
CSharedCriticalSection::Leave (
)
/*++
Routine Description:
Clear the CSharedCriticalSection indicating that the current thread is done with it.
--*/
{
PCSprimary.Leave();
}
inline void
CSharedCriticalSection::Enter (
)
/*++
Routine Description:
Request exclusive access to the CSharedCriticalSection. This routine will
not return until the current thread has exclusive access to the
CSharedCriticalSection.
--*/
{
PCSprimary.Enter();
}
inline void
CSharedCriticalSection::hold (
)
/*++
Routine Description:
We need this new implementation of hold to make sure the reference
counts are accurate. For instance, suppose two iterators are
being created for the same list in different threads. Unless we
use locking, there is a chance that the references will be
undercounted due to race conditions.
--*/
{
CRefCounted::hold();
}
inline void
CSharedCriticalSection::release (
)
/*++
Routine Description:
See above. Note that we cannot call the parent release method
because it may cause self-destruct before we can perform Leave
on PCScount! However, we are using a "cooperative" rather than
"opportunistic" sharing model here -- we don't deal with the
situation where an opportunistic thread may grab this object
and bump up its ulRefCount after it has dropped to zero.
--*/
{
PCScount.Enter();
ASSERT(ulRefCount, "Decrementing nonpositive reference count\n");
ulRefCount--;
PCScount.Leave();
if (!ulRefCount)
delete this;
}
/******** inline methods for CReadWriteSection ********/
inline
CReadWriteSection::CReadWriteSection()
/*++
Routine Description:
Simple constructor for CReadWriteSection.
Results:
None.
--*/
{
ulReaderCount = 0;
}
inline void
CReadWriteSection::writerEnter()
/*++
Routine Description:
The writer must block new readers from entering otherwise it
may starve. Must also wait for current readers to leave.
Blocking other writers is a simple side-effect of these.
Results:
None.
--*/
{
DBGOUT(SEM, "Entering writerEnter\n");
PCSReaderBlock.Enter(); // block any further readers
DBGOUT(SEM, "Got Past PCSReaderBlock\n");
PSemWriterBlock.Enter(); // wait for current readers to leave
DBGOUT(SEM, "Leaving writerEnter\n");
}
inline void
CReadWriteSection::writerLeave()
/*++
Routine Description:
Release everything and go away.
Results:
None.
--*/
{
DBGOUT(SEM, "Performing writerLeave\n");
PSemWriterBlock.Leave(); // this order "levels the playing field"
PCSReaderBlock.Leave(); // between readers and writers for entry
}
#endif // __MUTEX_HXX__