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.

279 lines
8.1 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. lock.h
  5. Abstract:
  6. Contains data structures and function prototypes for the Service
  7. Controller's database locking functions (lock.cxx).
  8. This file defines the following classes:
  9. CCountingResource
  10. CServiceRecordLock
  11. CServiceListLock
  12. CGroupListLock
  13. CServiceRecordExclusiveLock
  14. CServiceRecordSharedLock
  15. CServiceRecordTEMPORARYEXCLUSIVELOCK
  16. CServiceListExclusiveLock
  17. CServiceListSharedLock
  18. CGroupListExclusiveLock
  19. CGroupListSharedLock
  20. Author:
  21. Anirudh Sahni (anirudhs) 09-Jan-1997
  22. Environment:
  23. User Mode -Win32
  24. Revision History:
  25. 09-Jan-1997 AnirudhS
  26. Created, replacing the old locking functions in dataman.h.
  27. --*/
  28. #ifndef _LOCK_INCLUDED_
  29. #define _LOCK_INCLUDED_
  30. //+-------------------------------------------------------------------------
  31. //
  32. // Class: CCountingResource
  33. //
  34. // Purpose: This is an RTL_RESOURCE that, in the checked build, knows
  35. // its locking level for the current thread. The locking
  36. // level is stored in a TLS (thread local storage) slot. A
  37. // positive value indicates a shared lock on the resource and
  38. // a negative value indicates an exclusive lock, with the
  39. // absolute value indicating the number of recursive
  40. // acquisitions of the lock.
  41. //
  42. // History: 09-Jan-97 AnirudhS Created.
  43. //
  44. //--------------------------------------------------------------------------
  45. class CCountingResource
  46. {
  47. public:
  48. void Initialize(LPCSTR ShortName, LPCSTR Name)
  49. {
  50. RtlInitializeResource(&_Lock);
  51. #if DBG
  52. _TlsIndex = TlsAlloc();
  53. SC_ASSERT(_TlsIndex != 0xFFFFFFFF);
  54. _ShortName = ShortName;
  55. _Name = Name;
  56. #endif
  57. }
  58. void Delete() { RtlDeleteResource(&_Lock); }
  59. #if DBG
  60. void GetShared();
  61. void GetExclusive();
  62. void MakeShared();
  63. void Release();
  64. BOOL Have() const { return (CurrentLevel() != 0); }
  65. BOOL HaveExclusive() const
  66. { return (CurrentLevel() < 0); }
  67. #else
  68. void GetShared() { RtlAcquireResourceShared(&_Lock, TRUE); }
  69. void GetExclusive() { RtlAcquireResourceExclusive(&_Lock, TRUE); }
  70. void MakeShared() { RtlConvertExclusiveToShared(&_Lock); }
  71. void Release() { RtlReleaseResource(&_Lock); }
  72. #endif
  73. protected:
  74. #if DBG
  75. void MakeExclusive();
  76. LONG CurrentLevel() const
  77. { return (LONG)(LONG_PTR)(TlsGetValue(_TlsIndex)); }
  78. void SetCurrentLevel(LONG Level)
  79. { SC_ASSERT(TlsSetValue(_TlsIndex, (PVOID)(LONG_PTR) Level) != 0); }
  80. #else
  81. void MakeExclusive()
  82. { RtlConvertSharedToExclusive(&_Lock); }
  83. #endif
  84. private:
  85. #if DBG
  86. DWORD _TlsIndex;
  87. LPCSTR _ShortName;
  88. LPCSTR _Name;
  89. #endif
  90. RTL_RESOURCE _Lock;
  91. };
  92. //+-------------------------------------------------------------------------
  93. //
  94. // Class: CServiceRecordLock, CServiceListLock, CGroupListLock
  95. //
  96. // Purpose: These three locks are used to synchronize multithreaded
  97. // access to the service controller's database. Each lock
  98. // allows single-writer/multiple-reader access to a particular
  99. // aspect of the database.
  100. //
  101. // These are implemented as three separate classes with one
  102. // instance each, rather than three instances of one class,
  103. // because their implementations in the debug build differ
  104. // substantially from one another.
  105. //
  106. // The Service List lock is used to synchronize access to the
  107. // linked list pointers (Prev and Next fields) of the
  108. // SERVICE_RECORDs in the database. While a thread holds this
  109. // lock, no other thread can add or delete SERVICE_RECORDs.
  110. //
  111. // The Service Record lock is used to synchronize access to
  112. // the "contents" (other fields) of the SERVICE_RECORDs.
  113. //
  114. // In order to delete a service record, both the service list
  115. // lock and the service record lock must be held exclusively.
  116. // Consequently if a thread is only working with a particular
  117. // service record (not walking the list of service records),
  118. // it is sufficient for that thread to hold the service record
  119. // lock in order to be assured that no other thread will
  120. // delete that service record.
  121. //
  122. // The Group List lock is used to synchronize access to the
  123. // LOAD_ORDER_GROUPs in the database (both contents and
  124. // pointers).
  125. //
  126. // To avoid deadlocks, the locks are always acquired in the
  127. // following order, if more than one is needed:
  128. // 1. Group List lock (if needed)
  129. // 2. Service List lock (if needed)
  130. // 3. Service Record lock (if needed)
  131. //
  132. // History: 09-Jan-97 AnirudhS Created.
  133. //
  134. //--------------------------------------------------------------------------
  135. class CServiceRecordLock : public CCountingResource
  136. {
  137. public:
  138. //
  139. // This method's name is capitalized to draw attention to its use,
  140. // because it is easily misunderstood and misused. It does not hold
  141. // on to the shared lock while converting it to exclusive. Instead,
  142. // it first releases the shared lock and then acquires the exclusive
  143. // lock.
  144. //
  145. void MAKEEXCLUSIVE() { CCountingResource::MakeExclusive(); }
  146. };
  147. class CServiceListLock : public CCountingResource
  148. {
  149. public:
  150. #if DBG
  151. void GetShared();
  152. void GetExclusive();
  153. void Release();
  154. #endif
  155. };
  156. class CGroupListLock : public CCountingResource
  157. {
  158. public:
  159. #if DBG
  160. void GetShared();
  161. void GetExclusive();
  162. void Release();
  163. #endif
  164. };
  165. //
  166. // Globals
  167. //
  168. extern CServiceRecordLock ScServiceRecordLock;
  169. extern CServiceListLock ScServiceListLock;
  170. extern CGroupListLock ScGroupListLock;
  171. //+-------------------------------------------------------------------------
  172. //
  173. // Safe wrapper classes that ensure that the Release method is called
  174. //
  175. // Use of these classes ensures proper, disciplined access to the locks.
  176. // In general, the locks should be acquired and released through these
  177. // safe classes only. Any direct access to the locks should be viewed
  178. // with suspicion.
  179. //
  180. //--------------------------------------------------------------------------
  181. class CServiceRecordExclusiveLock
  182. {
  183. public:
  184. CServiceRecordExclusiveLock() { ScServiceRecordLock.GetExclusive(); }
  185. ~CServiceRecordExclusiveLock() { ScServiceRecordLock.Release(); }
  186. };
  187. class CServiceRecordSharedLock
  188. {
  189. public:
  190. CServiceRecordSharedLock() { ScServiceRecordLock.GetShared(); }
  191. ~CServiceRecordSharedLock() { ScServiceRecordLock.Release(); }
  192. };
  193. //
  194. // Use this one with caution -- see the note above about MAKEEXCLUSIVE.
  195. //
  196. class CServiceRecordTEMPORARYEXCLUSIVELOCK
  197. {
  198. public:
  199. CServiceRecordTEMPORARYEXCLUSIVELOCK()
  200. { ScServiceRecordLock.MAKEEXCLUSIVE(); }
  201. ~CServiceRecordTEMPORARYEXCLUSIVELOCK()
  202. { ScServiceRecordLock.MakeShared(); }
  203. };
  204. class CServiceListExclusiveLock
  205. {
  206. public:
  207. CServiceListExclusiveLock() { ScServiceListLock.GetExclusive(); }
  208. ~CServiceListExclusiveLock() { ScServiceListLock.Release(); }
  209. };
  210. class CServiceListSharedLock
  211. {
  212. public:
  213. CServiceListSharedLock() { ScServiceListLock.GetShared(); }
  214. ~CServiceListSharedLock() { ScServiceListLock.Release(); }
  215. };
  216. class CGroupListExclusiveLock
  217. {
  218. public:
  219. CGroupListExclusiveLock() { ScGroupListLock.GetExclusive(); }
  220. ~CGroupListExclusiveLock() { ScGroupListLock.Release(); }
  221. };
  222. class CGroupListSharedLock
  223. {
  224. public:
  225. CGroupListSharedLock() { ScGroupListLock.GetShared(); }
  226. ~CGroupListSharedLock() { ScGroupListLock.Release(); }
  227. };
  228. #endif // ifndef _LOCK_INCLUDED_