windows-nt/Source/XPSP1/NT/net/winnet/mprlock.hxx
2020-09-26 16:20:57 +08:00

195 lines
5.3 KiB
C++

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
mprlock.hxx
Abstract:
Contains data structures and function prototypes for the MPR's
locking functions (converted from the Service Controller's).
This file defines the following classes:
CCountingResource
CProviderLock
CProviderExclusiveLock
CProviderSharedLock
Author:
Jonathan Schwartz (jschwart) 19-May-1999
Environment:
User Mode -Win32
Revision History:
19-May-1999 jschwart
Created, converted from \nt\private\windows\screg\sc\server\lock.cxx.
--*/
#ifndef _MPRLOCK_INCLUDED_
#define _MPRLOCK_INCLUDED_
//+-------------------------------------------------------------------------
//
// Class: CCountingResource
//
// Purpose: This is an RTL_RESOURCE that, in the checked build, knows
// its locking level for the current thread. The locking
// level is stored in a TLS (thread local storage) slot. A
// positive value indicates a shared lock on the resource and
// a negative value indicates an exclusive lock, with the
// absolute value indicating the number of recursive
// acquisitions of the lock.
//
// History: 19-May-99 jschwart Created.
//
//--------------------------------------------------------------------------
class CCountingResource
{
public:
void Initialize(LPCSTR ShortName, LPCSTR Name)
{
RtlInitializeResource(&_Lock);
#if DBG
_TlsIndex = TlsAlloc();
ASSERT(_TlsIndex != 0xFFFFFFFF);
_ShortName = ShortName;
_Name = Name;
#endif
}
void Delete() {
RtlDeleteResource(&_Lock);
#if DBG
TlsFree(_TlsIndex);
#endif
}
#if DBG
void GetShared();
void GetExclusive();
void Release();
BOOL Have() const { return (CurrentLevel() != 0); }
BOOL HaveExclusive() const
{ return (CurrentLevel() < 0); }
#else
void GetShared() { RtlAcquireResourceShared(&_Lock, TRUE); }
void GetExclusive() { RtlAcquireResourceExclusive(&_Lock, TRUE); }
void Release() { RtlReleaseResource(&_Lock); }
#endif
protected:
#if DBG
LONG CurrentLevel() const
{ return (LONG)(LONG_PTR)(TlsGetValue(_TlsIndex)); }
void SetCurrentLevel(LONG Level)
{ ASSERT(TlsSetValue(_TlsIndex, LongToPtr(Level)) != 0); }
#endif
private:
#if DBG
DWORD _TlsIndex;
LPCSTR _ShortName;
LPCSTR _Name;
#endif
RTL_RESOURCE _Lock;
};
//+-------------------------------------------------------------------------
//
// Class: CProviderLock
//
// Purpose: This lock is used to synchronize multithreaded
// access to the provider database.
//
// History: 19-May-99 jschwart Created.
//
//--------------------------------------------------------------------------
class CProviderLock : public CCountingResource
{
};
//
// Globals
//
extern CProviderLock MPRProviderLock;
//+-------------------------------------------------------------------------
//
// Safe wrapper classes that ensure that the Release method is called
//
// Use of these classes ensures proper, disciplined access to the locks.
// In general, the locks should be acquired and released through these
// safe classes only. Any direct access to the locks should be viewed
// with suspicion.
//
// In order to avoid deadlock in the MPR, every MPR API must make the
// following three calls IN ORDER:
//
// 1. MprCheckProviders -- acquires the exclusive lock and flushes
// the providers if necessary
//
// 2. Acquire the shared lock (to prevent another API from flushing
// the providers)
//
// 3. INIT_IF_NECESSARY
//
// INIT_IF_NECESSARY must come last to avoid the following race condition:
//
// 1. Thread 1 calls INIT_IF_NECESSARY and all is initialized
//
// 2. Providers change -- thread 2 catches it in MprCheckProviders and
// flushes providers
//
// 3. Thread 1 acquires the read lock and finds no providers (though
// they should be there -- fails or faults)
//
// In addition, the logic in MprCheckProviders requires APIs that use
// INIT_IF_NECESSARY to call it after acquiring the read lock, as
// MprCheckProviders does not acquire the MprInitCritSec.
//
// Note that this system assumes no WNet API calls are either made
// recursively or re-entrant. This requires special care with the functions
// in mprui.cxx as they ultimately call other WNet APIs in mprui.dll or
// netplwiz.dll.
//
//--------------------------------------------------------------------------
class CProviderSharedLock
{
public:
CProviderSharedLock() { MPRProviderLock.GetShared(); }
~CProviderSharedLock() { MPRProviderLock.Release(); }
};
class CProviderExclusiveLock
{
public:
CProviderExclusiveLock() { MPRProviderLock.GetExclusive(); }
~CProviderExclusiveLock() { MPRProviderLock.Release(); }
};
#endif // ifndef _MPRLOCK_INCLUDED_