473 lines
9.4 KiB
C++
473 lines
9.4 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1990 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
mutex.hxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains the system independent mutex classes. A mutex is an
|
|||
|
object which is used to serialize access to a resource. Besides
|
|||
|
construction and destruction, a mutex can have two operations performed on
|
|||
|
it: Clear and Request. Request is a request for exclusive access to the
|
|||
|
mutex; the method will not complete until the calling thread has exclusive
|
|||
|
access to the mutex. Clear indicates that the thread with exclusive
|
|||
|
access to the mutex is done.
|
|||
|
|
|||
|
Three MUTEX classes exist here, each for a particular purpose:
|
|||
|
|
|||
|
MUTEX - a simple wrapper around WIN32 critical sections
|
|||
|
- fastest
|
|||
|
- better MP behavior
|
|||
|
- optimized for each platform
|
|||
|
- general purpose
|
|||
|
- recursive Request() calls allowed
|
|||
|
- good debugger support, !locks, critical section timeouts, etc
|
|||
|
|
|||
|
MUTEX2 - basic lock used only for context handle dispatch serialization.
|
|||
|
- specific purpose.
|
|||
|
- may not be recursivly Request()'ed.
|
|||
|
- allows any thread to release the lock.
|
|||
|
- harder to debug
|
|||
|
|
|||
|
MUTEX3 - basic lock used around connection oriented bind requests
|
|||
|
- behavior similar to MUTEX
|
|||
|
- slower
|
|||
|
- will not timeout
|
|||
|
- harder to debug
|
|||
|
|
|||
|
Helper classes:
|
|||
|
|
|||
|
CLAIM_MUTEX - designed as a local class wrapping a MUTEX
|
|||
|
Usage:
|
|||
|
|
|||
|
MUTEX GlobalMutex;
|
|||
|
|
|||
|
foo() {
|
|||
|
CLAIM_MUTEX lockit(GlobalMutex);
|
|||
|
// GlobalMutex is now held
|
|||
|
if (blah)
|
|||
|
return;
|
|||
|
bleh;
|
|||
|
return;
|
|||
|
} // GlobalMutex is released when "lockit" goes out of scope.
|
|||
|
|
|||
|
EVENT - simple wrapper around a WIN32 event object
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
MikeMon
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
mikemon ??-??-?? The starting line.
|
|||
|
mikemon 12-31-90 Upgraded the comments.
|
|||
|
MazharM 9/1998 MUTEX2
|
|||
|
MarioGo 11/1/1998 MUTEX3
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#ifndef __MUTEX_HXX__
|
|||
|
#define __MUTEX_HXX__
|
|||
|
|
|||
|
#include "util.hxx"
|
|||
|
|
|||
|
#ifdef DEBUGRPC
|
|||
|
#define INCREMENT_CRITSECT_COUNT
|
|||
|
#endif
|
|||
|
|
|||
|
class MUTEX
|
|||
|
{
|
|||
|
BOOL IsSuccessfullyInitialized(void)
|
|||
|
{
|
|||
|
return (CriticalSection.DebugInfo != 0);
|
|||
|
}
|
|||
|
CRITICAL_SECTION CriticalSection;
|
|||
|
|
|||
|
void EnumOwnedCriticalSections();
|
|||
|
|
|||
|
void CommonConstructor(
|
|||
|
IN OUT RPC_STATUS PAPI * RpcStatus,
|
|||
|
IN DWORD dwSpinCount
|
|||
|
);
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
MUTEX (
|
|||
|
IN OUT RPC_STATUS PAPI * RpcStatus,
|
|||
|
IN DWORD dwSpinCount = 0
|
|||
|
)
|
|||
|
{
|
|||
|
CommonConstructor(RpcStatus, dwSpinCount);
|
|||
|
}
|
|||
|
|
|||
|
MUTEX (
|
|||
|
IN OUT RPC_STATUS PAPI * RpcStatus,
|
|||
|
IN BOOL fPreallocateSemaphore,
|
|||
|
IN DWORD dwSpinCount = 0
|
|||
|
)
|
|||
|
{
|
|||
|
CommonConstructor(RpcStatus,
|
|||
|
fPreallocateSemaphore ? (dwSpinCount | PREALLOCATE_EVENT_MASK) :
|
|||
|
dwSpinCount);
|
|||
|
}
|
|||
|
|
|||
|
inline ~MUTEX ()
|
|||
|
{
|
|||
|
Free();
|
|||
|
}
|
|||
|
|
|||
|
void Free(void);
|
|||
|
|
|||
|
BOOL
|
|||
|
TryRequest()
|
|||
|
{
|
|||
|
BOOL Result = RtlTryEnterCriticalSection(&CriticalSection);
|
|||
|
|
|||
|
#ifdef CHECK_MUTEX_INVERSION
|
|||
|
if (Result)
|
|||
|
{
|
|||
|
LogEvent(SU_MUTEX, EV_INC, this);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
void Request ()
|
|||
|
{
|
|||
|
#if 0
|
|||
|
EnumOwnedCriticalSections();
|
|||
|
#endif
|
|||
|
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
status = RtlEnterCriticalSection(&CriticalSection);
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
|
|||
|
#ifdef CHECK_MUTEX_INVERSION
|
|||
|
LogEvent(SU_MUTEX, EV_INC, this);
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef DEBUGRPC
|
|||
|
if (CriticalSection.RecursionCount > 100)
|
|||
|
{
|
|||
|
DbgPrint("thread %x has recursively taken mutex %x %d times\n",
|
|||
|
GetCurrentThreadId(), &CriticalSection, CriticalSection.RecursionCount);
|
|||
|
RpcpBreakPoint();
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS RequestSafe (void)
|
|||
|
{
|
|||
|
RPC_STATUS RetVal = RPC_S_OK;
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
Request();
|
|||
|
}
|
|||
|
RpcExcept((RpcExceptionCode() == STATUS_INSUFFICIENT_RESOURCES)
|
|||
|
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH )
|
|||
|
{
|
|||
|
RetVal = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
return RetVal;
|
|||
|
}
|
|||
|
|
|||
|
void Clear ()
|
|||
|
{
|
|||
|
#ifdef CHECK_MUTEX_INVERSION
|
|||
|
LogEvent(SU_MUTEX, EV_DEC, this);
|
|||
|
#endif
|
|||
|
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
VerifyOwned();
|
|||
|
|
|||
|
status = RtlLeaveCriticalSection(&CriticalSection);
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
}
|
|||
|
|
|||
|
inline void
|
|||
|
VerifyOwned()
|
|||
|
{
|
|||
|
ASSERT(CriticalSection.OwningThread == ULongToPtr(GetCurrentThreadId()));
|
|||
|
}
|
|||
|
|
|||
|
inline BOOL OwnedByMe()
|
|||
|
{
|
|||
|
if (CriticalSection.OwningThread == ULongToPtr(GetCurrentThreadId()) &&
|
|||
|
CriticalSection.RecursionCount != -1)
|
|||
|
{
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
inline void
|
|||
|
VerifyNotOwned()
|
|||
|
{
|
|||
|
ASSERT(CriticalSection.OwningThread != ULongToPtr(GetCurrentThreadId()) ||
|
|||
|
CriticalSection.RecursionCount == -1);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
SetSpinCount(
|
|||
|
unsigned long Count
|
|||
|
)
|
|||
|
{
|
|||
|
return SetCriticalSectionSpinCount(&CriticalSection, Count);
|
|||
|
}
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
extern RTL_CRITICAL_SECTION GlobalMutex;
|
|||
|
|
|||
|
#ifdef NO_RECURSIVE_MUTEXES
|
|||
|
extern unsigned int RecursionCount;
|
|||
|
#endif // NO_RECURSIVE_MUTEXES
|
|||
|
|
|||
|
#ifdef DBG
|
|||
|
extern long lGlobalMutexCount;
|
|||
|
#endif
|
|||
|
|
|||
|
inline void GlobalMutexRequest(void)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Request the global mutex.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifdef DBG
|
|||
|
InterlockedIncrement(&lGlobalMutexCount);
|
|||
|
#endif
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
Status = RtlEnterCriticalSection(&GlobalMutex);
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
|
|||
|
#ifdef NO_RECURSIVE_MUTEXES
|
|||
|
ASSERT(RecursionCount == 0);
|
|||
|
RecursionCount += 1;
|
|||
|
#endif // NO_RECURSIVE_MUTEXES
|
|||
|
}
|
|||
|
|
|||
|
inline void GlobalMutexClear(void)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Clear the global mutex.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifdef DBG
|
|||
|
InterlockedDecrement(&lGlobalMutexCount);
|
|||
|
#endif
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
Status = RtlLeaveCriticalSection(&GlobalMutex);
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
|
|||
|
#ifdef NO_RECURSIVE_MUTEXES
|
|||
|
RecursionCount -= 1;
|
|||
|
#endif // NO_RECURSIVE_MUTEXES
|
|||
|
}
|
|||
|
|
|||
|
inline BOOL GlobalMutexTryRequest(void)
|
|||
|
{
|
|||
|
BOOL Result = RtlTryEnterCriticalSection(&GlobalMutex);
|
|||
|
|
|||
|
if (Result)
|
|||
|
{
|
|||
|
#ifdef DBG
|
|||
|
InterlockedIncrement(&lGlobalMutexCount);
|
|||
|
#endif
|
|||
|
#ifdef NO_RECURSIVE_MUTEXES
|
|||
|
ASSERT(RecursionCount == 0);
|
|||
|
RecursionCount += 1;
|
|||
|
#endif // NO_RECURSIVE_MUTEXES
|
|||
|
}
|
|||
|
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
inline void GlobalMutexVerifyOwned(void)
|
|||
|
{
|
|||
|
ASSERT(GlobalMutex.OwningThread == ULongToPtr(GetCurrentThreadId()));
|
|||
|
}
|
|||
|
|
|||
|
inline void GlobalMutexVerifyNotOwned(void)
|
|||
|
{
|
|||
|
ASSERT(GlobalMutex.OwningThread != ULongToPtr(GetCurrentThreadId()) ||
|
|||
|
GlobalMutex.RecursionCount == -1);
|
|||
|
}
|
|||
|
|
|||
|
inline DWORD GlobalMutexSetSpinCount(unsigned long Count)
|
|||
|
{
|
|||
|
return SetCriticalSectionSpinCount(&GlobalMutex, Count);
|
|||
|
}
|
|||
|
|
|||
|
class EVENT
|
|||
|
{
|
|||
|
public:
|
|||
|
|
|||
|
HANDLE EventHandle;
|
|||
|
|
|||
|
EVENT (
|
|||
|
IN OUT RPC_STATUS PAPI * RpcStatus,
|
|||
|
IN int ManualReset = 1,
|
|||
|
IN BOOL fDelayInit = FALSE
|
|||
|
);
|
|||
|
|
|||
|
~EVENT ( // Destructor.
|
|||
|
);
|
|||
|
|
|||
|
void
|
|||
|
Raise ( // Raise the event.
|
|||
|
)
|
|||
|
{
|
|||
|
BOOL status;
|
|||
|
|
|||
|
if (NULL == EventHandle)
|
|||
|
{
|
|||
|
InitializeEvent();
|
|||
|
}
|
|||
|
|
|||
|
status = SetEvent(EventHandle);
|
|||
|
ASSERT(status == TRUE);
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
Lower ( // Lower the event.
|
|||
|
)
|
|||
|
{
|
|||
|
BOOL status;
|
|||
|
|
|||
|
status = ResetEvent(EventHandle);
|
|||
|
ASSERT(status == TRUE);
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
Wait ( // Wait until the event is raised.
|
|||
|
IN long timeout = -1
|
|||
|
);
|
|||
|
|
|||
|
void
|
|||
|
Request (
|
|||
|
) {Wait(-1);}
|
|||
|
|
|||
|
int
|
|||
|
RequestWithTimeout (
|
|||
|
IN long timeout = -1
|
|||
|
) {return(Wait(timeout));}
|
|||
|
|
|||
|
void
|
|||
|
Clear (
|
|||
|
) {Raise();}
|
|||
|
|
|||
|
private:
|
|||
|
|
|||
|
void InitializeEvent();
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
class CLAIM_MUTEX {
|
|||
|
|
|||
|
private:
|
|||
|
|
|||
|
MUTEX & Resource;
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
CLAIM_MUTEX(
|
|||
|
MUTEX & ClaimedResource
|
|||
|
)
|
|||
|
: Resource(ClaimedResource)
|
|||
|
{
|
|||
|
Resource.Request();
|
|||
|
}
|
|||
|
|
|||
|
~CLAIM_MUTEX(
|
|||
|
)
|
|||
|
{
|
|||
|
Resource.Clear();
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
class MUTEX2
|
|||
|
{
|
|||
|
EVENT mutexEvent;
|
|||
|
INTERLOCKED_INTEGER guard;
|
|||
|
DWORD OwningThread;
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
MUTEX2 (
|
|||
|
IN OUT RPC_STATUS PAPI * RpcStatus
|
|||
|
) : mutexEvent(RpcStatus, FALSE, TRUE), guard(0)
|
|||
|
{
|
|||
|
OwningThread = 0;
|
|||
|
|
|||
|
// Don't set *RpcStatus to RPC_S_OK
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
Request ()
|
|||
|
{
|
|||
|
if (guard.Increment() > 1)
|
|||
|
{
|
|||
|
mutexEvent.Wait();
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(OwningThread == 0);
|
|||
|
OwningThread = GetCurrentThreadId();
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
Clear ()
|
|||
|
{
|
|||
|
OwningThread = 0;
|
|||
|
|
|||
|
if (guard.Decrement() > 0)
|
|||
|
{
|
|||
|
mutexEvent.Raise();
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
class MUTEX3
|
|||
|
{
|
|||
|
private:
|
|||
|
EVENT event;
|
|||
|
INTERLOCKED_INTEGER guard;
|
|||
|
DWORD owner;
|
|||
|
DWORD recursion;
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
MUTEX3(RPC_STATUS *RpcStatus) : event(RpcStatus, FALSE, TRUE), guard(-1)
|
|||
|
{
|
|||
|
owner = 0;
|
|||
|
recursion = 0;
|
|||
|
|
|||
|
// Don't set *RpcStatus to RPC_S_OK
|
|||
|
}
|
|||
|
|
|||
|
void Request();
|
|||
|
void Clear();
|
|||
|
BOOL TryRequest();
|
|||
|
};
|
|||
|
|
|||
|
#endif // __MUTEX_HXX__
|