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.

194 lines
5.3 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. mprlock.hxx
  5. Abstract:
  6. Contains data structures and function prototypes for the MPR's
  7. locking functions (converted from the Service Controller's).
  8. This file defines the following classes:
  9. CCountingResource
  10. CProviderLock
  11. CProviderExclusiveLock
  12. CProviderSharedLock
  13. Author:
  14. Jonathan Schwartz (jschwart) 19-May-1999
  15. Environment:
  16. User Mode -Win32
  17. Revision History:
  18. 19-May-1999 jschwart
  19. Created, converted from \nt\private\windows\screg\sc\server\lock.cxx.
  20. --*/
  21. #ifndef _MPRLOCK_INCLUDED_
  22. #define _MPRLOCK_INCLUDED_
  23. //+-------------------------------------------------------------------------
  24. //
  25. // Class: CCountingResource
  26. //
  27. // Purpose: This is an RTL_RESOURCE that, in the checked build, knows
  28. // its locking level for the current thread. The locking
  29. // level is stored in a TLS (thread local storage) slot. A
  30. // positive value indicates a shared lock on the resource and
  31. // a negative value indicates an exclusive lock, with the
  32. // absolute value indicating the number of recursive
  33. // acquisitions of the lock.
  34. //
  35. // History: 19-May-99 jschwart Created.
  36. //
  37. //--------------------------------------------------------------------------
  38. class CCountingResource
  39. {
  40. public:
  41. void Initialize(LPCSTR ShortName, LPCSTR Name)
  42. {
  43. RtlInitializeResource(&_Lock);
  44. #if DBG
  45. _TlsIndex = TlsAlloc();
  46. ASSERT(_TlsIndex != 0xFFFFFFFF);
  47. _ShortName = ShortName;
  48. _Name = Name;
  49. #endif
  50. }
  51. void Delete() {
  52. RtlDeleteResource(&_Lock);
  53. #if DBG
  54. TlsFree(_TlsIndex);
  55. #endif
  56. }
  57. #if DBG
  58. void GetShared();
  59. void GetExclusive();
  60. void Release();
  61. BOOL Have() const { return (CurrentLevel() != 0); }
  62. BOOL HaveExclusive() const
  63. { return (CurrentLevel() < 0); }
  64. #else
  65. void GetShared() { RtlAcquireResourceShared(&_Lock, TRUE); }
  66. void GetExclusive() { RtlAcquireResourceExclusive(&_Lock, TRUE); }
  67. void Release() { RtlReleaseResource(&_Lock); }
  68. #endif
  69. protected:
  70. #if DBG
  71. LONG CurrentLevel() const
  72. { return (LONG)(LONG_PTR)(TlsGetValue(_TlsIndex)); }
  73. void SetCurrentLevel(LONG Level)
  74. { ASSERT(TlsSetValue(_TlsIndex, LongToPtr(Level)) != 0); }
  75. #endif
  76. private:
  77. #if DBG
  78. DWORD _TlsIndex;
  79. LPCSTR _ShortName;
  80. LPCSTR _Name;
  81. #endif
  82. RTL_RESOURCE _Lock;
  83. };
  84. //+-------------------------------------------------------------------------
  85. //
  86. // Class: CProviderLock
  87. //
  88. // Purpose: This lock is used to synchronize multithreaded
  89. // access to the provider database.
  90. //
  91. // History: 19-May-99 jschwart Created.
  92. //
  93. //--------------------------------------------------------------------------
  94. class CProviderLock : public CCountingResource
  95. {
  96. };
  97. //
  98. // Globals
  99. //
  100. extern CProviderLock MPRProviderLock;
  101. //+-------------------------------------------------------------------------
  102. //
  103. // Safe wrapper classes that ensure that the Release method is called
  104. //
  105. // Use of these classes ensures proper, disciplined access to the locks.
  106. // In general, the locks should be acquired and released through these
  107. // safe classes only. Any direct access to the locks should be viewed
  108. // with suspicion.
  109. //
  110. // In order to avoid deadlock in the MPR, every MPR API must make the
  111. // following three calls IN ORDER:
  112. //
  113. // 1. MprCheckProviders -- acquires the exclusive lock and flushes
  114. // the providers if necessary
  115. //
  116. // 2. Acquire the shared lock (to prevent another API from flushing
  117. // the providers)
  118. //
  119. // 3. INIT_IF_NECESSARY
  120. //
  121. // INIT_IF_NECESSARY must come last to avoid the following race condition:
  122. //
  123. // 1. Thread 1 calls INIT_IF_NECESSARY and all is initialized
  124. //
  125. // 2. Providers change -- thread 2 catches it in MprCheckProviders and
  126. // flushes providers
  127. //
  128. // 3. Thread 1 acquires the read lock and finds no providers (though
  129. // they should be there -- fails or faults)
  130. //
  131. // In addition, the logic in MprCheckProviders requires APIs that use
  132. // INIT_IF_NECESSARY to call it after acquiring the read lock, as
  133. // MprCheckProviders does not acquire the MprInitCritSec.
  134. //
  135. // Note that this system assumes no WNet API calls are either made
  136. // recursively or re-entrant. This requires special care with the functions
  137. // in mprui.cxx as they ultimately call other WNet APIs in mprui.dll or
  138. // netplwiz.dll.
  139. //
  140. //--------------------------------------------------------------------------
  141. class CProviderSharedLock
  142. {
  143. public:
  144. CProviderSharedLock() { MPRProviderLock.GetShared(); }
  145. ~CProviderSharedLock() { MPRProviderLock.Release(); }
  146. };
  147. class CProviderExclusiveLock
  148. {
  149. public:
  150. CProviderExclusiveLock() { MPRProviderLock.GetExclusive(); }
  151. ~CProviderExclusiveLock() { MPRProviderLock.Release(); }
  152. };
  153. #endif // ifndef _MPRLOCK_INCLUDED_