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.

476 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name :
  4. kLocks.h
  5. Abstract:
  6. A collection of kernel-mode locks for multithreaded access to
  7. data structures that provide the same abstractions as <locks.h>
  8. Author:
  9. George V. Reilly (GeorgeRe) 24-Oct-2000
  10. Environment:
  11. Win32 - Kernel Mode
  12. Project:
  13. Internet Information Server Http.sys
  14. Revision History:
  15. --*/
  16. #ifndef __KLOCKS_H__
  17. #define __KLOCKS_H__
  18. #define LOCKS_KERNEL_MODE
  19. #ifdef __LOCKS_H__
  20. #error Do not #include <locks.h> before <klocks.h>
  21. #endif
  22. #include <locks.h>
  23. //--------------------------------------------------------------------
  24. // CKSpinLock is a mutex lock based on KSPIN_LOCK
  25. class IRTL_DLLEXP CKSpinLock :
  26. public CLockBase<LOCK_KSPINLOCK, LOCK_MUTEX,
  27. LOCK_NON_RECURSIVE, LOCK_WAIT_SPIN, LOCK_QUEUE_KERNEL,
  28. LOCK_CLASS_SPIN
  29. >
  30. {
  31. private:
  32. // BUGBUG: this data must live in non-paged memory
  33. mutable KSPIN_LOCK KSpinLock;
  34. LOCK_INSTRUMENTATION_DECL();
  35. public:
  36. #ifndef LOCK_INSTRUMENTATION
  37. CKSpinLock()
  38. {
  39. KeInitializeSpinLock(&KSpinLock);
  40. }
  41. #else // LOCK_INSTRUMENTATION
  42. CKSpinLock(
  43. const TCHAR* ptszName)
  44. {
  45. KeInitializeSpinLock(&KSpinLock);
  46. LOCK_INSTRUMENTATION_INIT(ptszName);
  47. }
  48. #endif // LOCK_INSTRUMENTATION
  49. #ifdef IRTLDEBUG
  50. ~CKSpinLock() {}
  51. #endif // IRTLDEBUG
  52. typedef KIRQL ResultType;
  53. // Acquire an exclusive lock for writing.
  54. // Blocks (if needed) until acquired.
  55. ResultType WriteLock()
  56. {
  57. ResultType OldIrql;
  58. KeAcquireSpinLock(&KSpinLock, &OldIrql);
  59. return OldIrql;
  60. }
  61. // Acquire a (possibly shared) lock for reading.
  62. // Blocks (if needed) until acquired.
  63. ResultType ReadLock()
  64. {
  65. return WriteLock();
  66. }
  67. // Try to acquire an exclusive lock for writing. Returns true
  68. // if successful. Non-blocking.
  69. bool TryWriteLock()
  70. {
  71. return false;
  72. }
  73. // Try to acquire a (possibly shared) lock for reading. Returns true
  74. // if successful. Non-blocking.
  75. bool TryReadLock()
  76. {
  77. return TryWriteLock();
  78. }
  79. // Unlock the lock after a successful call to {,Try}WriteLock().
  80. // Assumes caller owned the lock.
  81. void WriteUnlock(
  82. ResultType OldIrql)
  83. {
  84. KeReleaseSpinLock(&KSpinLock, OldIrql);
  85. }
  86. // Unlock the lock after a successful call to {,Try}ReadLock().
  87. // Assumes caller owned the lock.
  88. void ReadUnlock(
  89. ResultType OldIrql)
  90. {
  91. WriteUnlock(OldIrql);
  92. }
  93. // Is the lock already locked for writing by this thread?
  94. bool IsWriteLocked() const
  95. {
  96. return false; // no way of determining this w/o auxiliary info
  97. }
  98. // Is the lock already locked for reading?
  99. bool IsReadLocked() const
  100. {
  101. return IsWriteLocked();
  102. }
  103. // Is the lock unlocked for writing?
  104. bool IsWriteUnlocked() const
  105. {
  106. return !IsWriteLocked();
  107. }
  108. // Is the lock unlocked for reading?
  109. bool IsReadUnlocked() const
  110. {
  111. return IsWriteUnlocked();
  112. }
  113. // Convert a reader lock to a writer lock
  114. void ConvertSharedToExclusive()
  115. {
  116. // no-op
  117. }
  118. // Convert a writer lock to a reader lock
  119. void ConvertExclusiveToShared()
  120. {
  121. // no-op
  122. }
  123. #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION
  124. // Set the spin count for this lock.
  125. // Returns true if successfully set the per-lock spincount, false otherwise
  126. bool SetSpinCount(WORD wSpins)
  127. {
  128. IRTLASSERT((wSpins == LOCK_DONT_SPIN)
  129. || (wSpins == LOCK_USE_DEFAULT_SPINS)
  130. || (LOCK_MINIMUM_SPINS <= wSpins
  131. && wSpins <= LOCK_MAXIMUM_SPINS));
  132. return false;
  133. }
  134. // Return the spin count for this lock.
  135. WORD GetSpinCount() const
  136. {
  137. return sm_wDefaultSpinCount;
  138. }
  139. LOCK_DEFAULT_SPIN_IMPLEMENTATION();
  140. #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION
  141. static const TCHAR* ClassName() {return _TEXT("CKSpinLock");}
  142. }; // CKSpinLock
  143. //--------------------------------------------------------------------
  144. // CFastMutex is a mutex lock based on FAST_MUTEX
  145. class IRTL_DLLEXP CFastMutex :
  146. public CLockBase<LOCK_FASTMUTEX, LOCK_MUTEX,
  147. LOCK_NON_RECURSIVE, LOCK_WAIT_SPIN, LOCK_QUEUE_KERNEL,
  148. LOCK_CLASS_SPIN
  149. >
  150. {
  151. private:
  152. mutable FAST_MUTEX FastMutex;
  153. LOCK_INSTRUMENTATION_DECL();
  154. public:
  155. #ifndef LOCK_INSTRUMENTATION
  156. CFastMutex()
  157. {
  158. ExInitializeFastMutex(&FastMutex);
  159. }
  160. #else // LOCK_INSTRUMENTATION
  161. CFastMutex(
  162. const TCHAR* ptszName)
  163. {
  164. ExInitializeFastMutex(&FastMutex);
  165. LOCK_INSTRUMENTATION_INIT(ptszName);
  166. }
  167. #endif // LOCK_INSTRUMENTATION
  168. #ifdef IRTLDEBUG
  169. ~CFastMutex() {}
  170. #endif // IRTLDEBUG
  171. // Acquire an exclusive lock for writing.
  172. // Blocks (if needed) until acquired.
  173. void WriteLock()
  174. {
  175. ExAcquireFastMutex(&FastMutex);
  176. }
  177. // Acquire a (possibly shared) lock for reading.
  178. // Blocks (if needed) until acquired.
  179. void ReadLock()
  180. {
  181. WriteLock();
  182. }
  183. // Try to acquire an exclusive lock for writing. Returns true
  184. // if successful. Non-blocking.
  185. bool TryWriteLock()
  186. {
  187. return ExTryToAcquireFastMutex(&FastMutex) != FALSE;
  188. }
  189. // Try to acquire a (possibly shared) lock for reading. Returns true
  190. // if successful. Non-blocking.
  191. bool TryReadLock()
  192. {
  193. return TryWriteLock();
  194. }
  195. // Unlock the lock after a successful call to {,Try}WriteLock().
  196. // Assumes caller owned the lock.
  197. void WriteUnlock()
  198. {
  199. ExReleaseFastMutex(&FastMutex);
  200. }
  201. // Unlock the lock after a successful call to {,Try}ReadLock().
  202. // Assumes caller owned the lock.
  203. void ReadUnlock()
  204. {
  205. WriteUnlock();
  206. }
  207. // Is the lock already locked for writing by this thread?
  208. bool IsWriteLocked() const
  209. {
  210. return false; // no way of determining this w/o auxiliary info
  211. }
  212. // Is the lock already locked for reading?
  213. bool IsReadLocked() const
  214. {
  215. return IsWriteLocked();
  216. }
  217. // Is the lock unlocked for writing?
  218. bool IsWriteUnlocked() const
  219. {
  220. return !IsWriteLocked();
  221. }
  222. // Is the lock unlocked for reading?
  223. bool IsReadUnlocked() const
  224. {
  225. return IsWriteUnlocked();
  226. }
  227. // Convert a reader lock to a writer lock
  228. void ConvertSharedToExclusive()
  229. {
  230. // no-op
  231. }
  232. // Convert a writer lock to a reader lock
  233. void ConvertExclusiveToShared()
  234. {
  235. // no-op
  236. }
  237. #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION
  238. // Set the spin count for this lock.
  239. // Returns true if successfully set the per-lock spincount, false otherwise
  240. bool SetSpinCount(WORD wSpins)
  241. {
  242. IRTLASSERT((wSpins == LOCK_DONT_SPIN)
  243. || (wSpins == LOCK_USE_DEFAULT_SPINS)
  244. || (LOCK_MINIMUM_SPINS <= wSpins
  245. && wSpins <= LOCK_MAXIMUM_SPINS));
  246. return false;
  247. }
  248. // Return the spin count for this lock.
  249. WORD GetSpinCount() const
  250. {
  251. return sm_wDefaultSpinCount;
  252. }
  253. LOCK_DEFAULT_SPIN_IMPLEMENTATION();
  254. #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION
  255. static const TCHAR* ClassName() {return _TEXT("CFastMutex");}
  256. }; // CFastMutex
  257. //--------------------------------------------------------------------
  258. // CEResource is a multi-reader, single-writer lock based on ERESOURCE
  259. class IRTL_DLLEXP CEResource :
  260. public CLockBase<LOCK_ERESOURCE, LOCK_MRSW,
  261. LOCK_RECURSIVE, LOCK_WAIT_HANDLE, LOCK_QUEUE_KERNEL,
  262. LOCK_CLASS_SPIN
  263. >
  264. {
  265. private:
  266. mutable ERESOURCE Resource;
  267. public:
  268. CEResource()
  269. {
  270. ExInitializeResourceLite(&Resource);
  271. }
  272. #ifdef LOCK_INSTRUMENTATION
  273. CEResource(
  274. const TCHAR* ptszName)
  275. {
  276. ExInitializeResourceLite(&Resource);
  277. LOCK_INSTRUMENTATION_INIT(ptszName);
  278. }
  279. #endif // LOCK_INSTRUMENTATION
  280. ~CEResource()
  281. {
  282. ExDeleteResourceLite(&Resource);
  283. }
  284. inline void
  285. WriteLock()
  286. {
  287. KeEnterCriticalRegion();
  288. ExAcquireResourceExclusiveLite(&Resource, TRUE);
  289. }
  290. inline void
  291. ReadLock()
  292. {
  293. KeEnterCriticalRegion();
  294. ExAcquireResourceSharedLite(&Resource, TRUE);
  295. }
  296. bool ReadOrWriteLock();
  297. inline bool
  298. TryWriteLock()
  299. {
  300. KeEnterCriticalRegion();
  301. BOOLEAN fLocked = ExAcquireResourceExclusiveLite(&Resource, FALSE);
  302. if (! fLocked)
  303. KeLeaveCriticalRegion();
  304. return fLocked != FALSE;
  305. }
  306. inline bool
  307. TryReadLock()
  308. {
  309. KeEnterCriticalRegion();
  310. BOOLEAN fLocked = ExAcquireResourceSharedLite(&Resource, FALSE);
  311. if (! fLocked)
  312. KeLeaveCriticalRegion();
  313. return fLocked != FALSE;
  314. }
  315. inline void
  316. WriteUnlock()
  317. {
  318. ExReleaseResourceLite(&Resource);
  319. KeLeaveCriticalRegion();
  320. }
  321. inline void
  322. ReadUnlock()
  323. {
  324. WriteUnlock();
  325. }
  326. void ReadOrWriteUnlock(bool fIsReadLocked);
  327. // Does current thread hold a write lock?
  328. bool
  329. IsWriteLocked() const
  330. {
  331. return ExIsResourceAcquiredExclusiveLite(&Resource) != FALSE;
  332. }
  333. bool
  334. IsReadLocked() const
  335. {
  336. return ExIsResourceAcquiredSharedLite(&Resource) > 0;
  337. }
  338. bool
  339. IsWriteUnlocked() const
  340. { return !IsWriteLocked(); }
  341. bool
  342. IsReadUnlocked() const
  343. { return !IsReadLocked(); }
  344. void
  345. ConvertSharedToExclusive()
  346. {
  347. ReadUnlock();
  348. WriteLock();
  349. }
  350. // There is no such window when converting from a writelock to a readlock
  351. void
  352. ConvertExclusiveToShared()
  353. {
  354. #if 0
  355. ExConvertExclusiveToShared(&Resource);
  356. #else
  357. WriteUnlock();
  358. ReadLock();
  359. #endif
  360. }
  361. #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION
  362. bool
  363. SetSpinCount(WORD wSpins)
  364. {return false;}
  365. WORD
  366. GetSpinCount() const
  367. {return sm_wDefaultSpinCount;}
  368. LOCK_DEFAULT_SPIN_IMPLEMENTATION();
  369. #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION
  370. static const TCHAR*
  371. ClassName()
  372. {return _TEXT("CEResource");}
  373. }; // CEResource
  374. #endif // __KLOCKS_H__