Leaked source code of windows server 2003
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.

679 lines
13 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. spinlock.c
  5. Abstract:
  6. This module implements the platform specific functions for acquiring
  7. and releasing spin locks.
  8. Author:
  9. David N. Cutler (davec) 12-Jun-2000
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. __forceinline
  16. VOID
  17. KxAcquireQueuedSpinLock (
  18. IN PKSPIN_LOCK_QUEUE LockQueue
  19. )
  20. /*++
  21. Routine Description:
  22. This function acquires a queued spin lock at the current IRQL.
  23. Arguments:
  24. LockQueue - Supplies a pointer to a spin lock queue.
  25. Return Value:
  26. None.
  27. --*/
  28. {
  29. //
  30. // Insert the specified lock queue entry at the end of the lock queue
  31. // list. If the list was previously empty, then lock ownership is
  32. // immediately granted. Otherwise, wait for ownership of the lock to
  33. // be granted.
  34. //
  35. #if !defined(NT_UP)
  36. PKSPIN_LOCK_QUEUE TailQueue;
  37. TailQueue = InterlockedExchangePointer((PVOID *)LockQueue->Lock,
  38. LockQueue);
  39. if (TailQueue != NULL) {
  40. LockQueue->Lock = (PKSPIN_LOCK)((ULONG64)LockQueue->Lock | LOCK_QUEUE_WAIT);
  41. TailQueue->Next = LockQueue;
  42. do {
  43. } while (((ULONG64)LockQueue->Lock & LOCK_QUEUE_WAIT) != 0);
  44. }
  45. #else
  46. UNREFERENCED_PARAMETER(LockQueue);
  47. #endif
  48. return;
  49. }
  50. __forceinline
  51. LOGICAL
  52. KxTryToAcquireQueuedSpinLock (
  53. IN PKSPIN_LOCK_QUEUE LockQueue
  54. )
  55. /*++
  56. Routine Description:
  57. This function attempts to acquire the specified queued spin lock at
  58. the current IRQL.
  59. Arguments:
  60. LockQueue - Supplies a pointer to a spin lock queue.
  61. Return Value:
  62. A value of TRUE is returned is the specified queued spin lock is
  63. acquired. Otherwise, a value of FALSE is returned.
  64. --*/
  65. {
  66. //
  67. // Insert the specified lock queue entry at the end of the lock queue
  68. // list iff the lock queue list is currently empty. If the lock queue
  69. // was empty, then lock ownership is granted and TRUE is returned.
  70. // Otherwise, FALSE is returned.
  71. //
  72. #if !defined(NT_UP)
  73. if ((*LockQueue->Lock != 0) ||
  74. (InterlockedCompareExchangePointer((PVOID *)LockQueue->Lock,
  75. LockQueue,
  76. NULL) != NULL)) {
  77. return FALSE;
  78. }
  79. #else
  80. UNREFERENCED_PARAMETER(LockQueue);
  81. #endif
  82. return TRUE;
  83. }
  84. __forceinline
  85. VOID
  86. KxReleaseQueuedSpinLock (
  87. IN PKSPIN_LOCK_QUEUE LockQueue
  88. )
  89. /*++
  90. Routine Description:
  91. The function release a queued spin lock at the current IRQL.
  92. Arguments:
  93. LockQueue - Supplies a pointer to a spin lock queue.
  94. Return Value:
  95. None.
  96. --*/
  97. {
  98. //
  99. // Attempt to release the lock. If the lock queue is not empty, then wait
  100. // for the next entry to be written in the lock queue entry and then grant
  101. // ownership of the lock to the next lock queue entry.
  102. //
  103. #if !defined(NT_UP)
  104. PKSPIN_LOCK_QUEUE NextQueue;
  105. NextQueue = LockQueue->Next;
  106. if (NextQueue == NULL) {
  107. if (InterlockedCompareExchangePointer((PVOID *)LockQueue->Lock,
  108. NULL,
  109. LockQueue) == LockQueue) {
  110. return;
  111. }
  112. do {
  113. } while ((NextQueue = LockQueue->Next) == NULL);
  114. }
  115. ASSERT(((ULONG64)NextQueue->Lock & LOCK_QUEUE_WAIT) != 0);
  116. NextQueue->Lock = (PKSPIN_LOCK)((ULONG64)NextQueue->Lock ^ LOCK_QUEUE_WAIT);
  117. LockQueue->Next = NULL;
  118. #else
  119. UNREFERENCED_PARAMETER(LockQueue);
  120. #endif
  121. return;
  122. }
  123. #undef KeAcquireQueuedSpinLock
  124. KIRQL
  125. KeAcquireQueuedSpinLock (
  126. IN KSPIN_LOCK_QUEUE_NUMBER Number
  127. )
  128. /*++
  129. Routine Description:
  130. This function raises IRQL to DISPATCH_LEVEL and acquires the specified
  131. numbered queued spin lock.
  132. Arguments:
  133. Number - Supplies the queued spin lock number.
  134. Return Value:
  135. The previous IRQL is returned as the function value.
  136. --*/
  137. {
  138. KIRQL OldIrql;
  139. //
  140. // Raise IRQL to DISPATCH_LEVEL and acquire the specified queued spin
  141. // lock.
  142. //
  143. OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
  144. KxAcquireQueuedSpinLock(&KeGetCurrentPrcb()->LockQueue[Number]);
  145. return OldIrql;
  146. }
  147. #undef KeAcquireQueuedSpinLockRaiseToSynch
  148. KIRQL
  149. KeAcquireQueuedSpinLockRaiseToSynch (
  150. IN KSPIN_LOCK_QUEUE_NUMBER Number
  151. )
  152. /*++
  153. Routine Description:
  154. This function raises IRQL to SYNCH_LEVEL and acquires the specified
  155. numbered queued spin lock.
  156. Arguments:
  157. Number - Supplies the queued spinlock number.
  158. Return Value:
  159. The previous IRQL is returned as the function value.
  160. --*/
  161. {
  162. KIRQL OldIrql;
  163. //
  164. // Raise IRQL to SYNCH_LEVEL and acquire the specified queued spin
  165. // lock.
  166. //
  167. OldIrql = KfRaiseIrql(SYNCH_LEVEL);
  168. KxAcquireQueuedSpinLock(&KeGetCurrentPrcb()->LockQueue[Number]);
  169. return OldIrql;
  170. }
  171. #undef KeAcquireQueuedSpinLockAtDpcLevel
  172. VOID
  173. KeAcquireQueuedSpinLockAtDpcLevel (
  174. IN PKSPIN_LOCK_QUEUE LockQueue
  175. )
  176. /*++
  177. Routine Description:
  178. This function acquires the specified queued spin lock at the current IRQL.
  179. Arguments:
  180. LockQueue - Supplies a pointer to the lock queue entry for the specified
  181. queued spin lock.
  182. Return Value:
  183. None.
  184. --*/
  185. {
  186. //
  187. // Acquire the specified queued spin lock at the current IRQL.
  188. //
  189. KxAcquireQueuedSpinLock(LockQueue);
  190. return;
  191. }
  192. #undef KeTryToAcquireQueuedSpinLock
  193. LOGICAL
  194. KeTryToAcquireQueuedSpinLock (
  195. IN KSPIN_LOCK_QUEUE_NUMBER Number,
  196. OUT PKIRQL OldIrql
  197. )
  198. /*++
  199. Routine Description:
  200. This function raises IRQL to DISPATCH_LEVEL and attempts to acquire the
  201. specified numbered queued spin lock. If the spin lock is already owned,
  202. then IRQL is restored to its previous value and FALSE is returned.
  203. Otherwise, the spin lock is acquired and TRUE is returned.
  204. Arguments:
  205. Number - Supplies the queued spinlock number.
  206. OldIrql - Supplies a pointer to the variable to receive the old IRQL.
  207. Return Value:
  208. If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
  209. is returned as the function value.
  210. --*/
  211. {
  212. //
  213. // Try to acquire the specified queued spin lock at DISPATCH_LEVEL.
  214. //
  215. *OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
  216. if (KxTryToAcquireQueuedSpinLock(&KeGetCurrentPrcb()->LockQueue[Number]) == FALSE) {
  217. KeLowerIrql(*OldIrql);
  218. return FALSE;
  219. }
  220. return TRUE;
  221. }
  222. #undef KeTryToAcquireQueuedSpinLockRaiseToSynch
  223. LOGICAL
  224. KeTryToAcquireQueuedSpinLockRaiseToSynch (
  225. IN KSPIN_LOCK_QUEUE_NUMBER Number,
  226. OUT PKIRQL OldIrql
  227. )
  228. /*++
  229. Routine Description:
  230. This function raises IRQL to SYNCH_LEVEL and attempts to acquire the
  231. specified numbered queued spin lock. If the spin lock is already owned,
  232. then IRQL is restored to its previous value and FALSE is returned.
  233. Otherwise, the spin lock is acquired and TRUE is returned.
  234. Arguments:
  235. Number - Supplies the queued spinlock number.
  236. OldIrql - Supplies a pointer to the variable to receive the old IRQL.
  237. Return Value:
  238. If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
  239. is returned as the function value.
  240. --*/
  241. {
  242. //
  243. // Try to acquire the specified queued spin lock at SYNCH_LEVEL.
  244. //
  245. *OldIrql = KfRaiseIrql(SYNCH_LEVEL);
  246. if (KxTryToAcquireQueuedSpinLock(&KeGetCurrentPrcb()->LockQueue[Number]) == FALSE) {
  247. KeLowerIrql(*OldIrql);
  248. return FALSE;
  249. }
  250. return TRUE;
  251. }
  252. #undef KeTryToAcquireQueuedSpinLockAtRaisedIrql
  253. LOGICAL
  254. KeTryToAcquireQueuedSpinLockAtRaisedIrql (
  255. IN PKSPIN_LOCK_QUEUE LockQueue
  256. )
  257. /*++
  258. Routine Description:
  259. This function attempts to acquire the specified queued spin lock at the
  260. current IRQL.
  261. Arguments:
  262. LockQueue - Supplies a pointer to a lock queue entry.
  263. Return Value:
  264. If the spin lock is acquired a value TRUE is returned as the function
  265. value. Otherwise, FALSE is returned as the function value.
  266. --*/
  267. {
  268. //
  269. // Try to acquire the specified queued spin lock at the current IRQL.
  270. //
  271. return KxTryToAcquireQueuedSpinLock(LockQueue);
  272. }
  273. #undef KeReleaseQueuedSpinLock
  274. VOID
  275. KeReleaseQueuedSpinLock (
  276. IN KSPIN_LOCK_QUEUE_NUMBER Number,
  277. IN KIRQL OldIrql
  278. )
  279. /*++
  280. Routine Description:
  281. This function releases a numbered queued spin lock and lowers the IRQL to
  282. its previous value.
  283. Arguments:
  284. Number - Supplies the queued spinlock number.
  285. OldIrql - Supplies the previous IRQL value.
  286. Return Value:
  287. None.
  288. --*/
  289. {
  290. //
  291. // Release the specified queued spin lock and lower IRQL.
  292. //
  293. KxReleaseQueuedSpinLock(&KeGetCurrentPrcb()->LockQueue[Number]);
  294. KeLowerIrql(OldIrql);
  295. return;
  296. }
  297. #undef KeReleaseQueuedSpinLockFromDpcLevel
  298. VOID
  299. KeReleaseQueuedSpinLockFromDpcLevel (
  300. IN PKSPIN_LOCK_QUEUE LockQueue
  301. )
  302. /*
  303. Routine Description:
  304. This function releases a queued spinlock from the current IRQL.
  305. Arguments:
  306. LockQueue - Supplies a pointer to a lock queue entry.
  307. Return Value:
  308. None.
  309. --*/
  310. {
  311. //
  312. // Release the specified queued spin lock at the current IRQL.
  313. //
  314. KxReleaseQueuedSpinLock(LockQueue);
  315. return;
  316. }
  317. VOID
  318. KeAcquireInStackQueuedSpinLock (
  319. IN PKSPIN_LOCK SpinLock,
  320. IN PKLOCK_QUEUE_HANDLE LockHandle
  321. )
  322. /*++
  323. Routine Description:
  324. This function raises IRQL to DISPATCH_LEVEL and acquires the specified
  325. in stack queued spin lock.
  326. Arguments:
  327. SpinLock - Supplies the home address of the queued spin lock.
  328. LockHandle - Supplies the adress of a lock queue handle.
  329. Return Value:
  330. None.
  331. --*/
  332. {
  333. //
  334. // Raise IRQL to DISPATCH_LEVEL and acquire the specified in stack
  335. // queued spin lock.
  336. //
  337. LockHandle->OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
  338. LockHandle->LockQueue.Lock = SpinLock;
  339. LockHandle->LockQueue.Next = NULL;
  340. KxAcquireQueuedSpinLock(&LockHandle->LockQueue);
  341. return;
  342. }
  343. VOID
  344. KeAcquireInStackQueuedSpinLockRaiseToSynch (
  345. IN PKSPIN_LOCK SpinLock,
  346. IN PKLOCK_QUEUE_HANDLE LockHandle
  347. )
  348. /*++
  349. Routine Description:
  350. This funtions raises IRQL to SYNCH_LEVEL and acquires the specified
  351. in stack queued spin lock.
  352. Arguments:
  353. SpinLock - Supplies the home address of the queued spin lock.
  354. LockHandle - Supplies the address of a lock queue handle.
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. //
  360. // Raise IRQL to SYNCH_LEVEL and acquire the specified in stack
  361. // queued spin lock.
  362. //
  363. LockHandle->OldIrql = KfRaiseIrql(SYNCH_LEVEL);
  364. LockHandle->LockQueue.Lock = SpinLock;
  365. LockHandle->LockQueue.Next = NULL;
  366. KxAcquireQueuedSpinLock(&LockHandle->LockQueue);
  367. return;
  368. }
  369. VOID
  370. KeAcquireInStackQueuedSpinLockAtDpcLevel (
  371. IN PKSPIN_LOCK SpinLock,
  372. IN PKLOCK_QUEUE_HANDLE LockHandle
  373. )
  374. /*++
  375. Routine Description:
  376. This function acquires the specified in stack queued spin lock at the
  377. current IRQL.
  378. Arguments:
  379. SpinLock - Supplies a pointer to thehome address of a spin lock.
  380. LockHandle - Supplies the address of a lock queue handle.
  381. Return Value:
  382. None.
  383. --*/
  384. {
  385. //
  386. // Acquire the specified in stack queued spin lock at the current
  387. // IRQL.
  388. //
  389. LockHandle->LockQueue.Lock = SpinLock;
  390. LockHandle->LockQueue.Next = NULL;
  391. KxAcquireQueuedSpinLock(&LockHandle->LockQueue);
  392. return;
  393. }
  394. VOID
  395. KeReleaseInStackQueuedSpinLock (
  396. IN PKLOCK_QUEUE_HANDLE LockHandle
  397. )
  398. /*++
  399. Routine Description:
  400. This function releases an in stack queued spin lock and lowers the IRQL
  401. to its previous value.
  402. Arguments:
  403. LockHandle - Supplies the address of a lock queue handle.
  404. Return Value:
  405. None.
  406. --*/
  407. {
  408. //
  409. // Release the specified in stack queued spin lock and lower IRQL.
  410. //
  411. KxReleaseQueuedSpinLock(&LockHandle->LockQueue);
  412. KeLowerIrql(LockHandle->OldIrql);
  413. return;
  414. }
  415. VOID
  416. KeReleaseInStackQueuedSpinLockFromDpcLevel (
  417. IN PKLOCK_QUEUE_HANDLE LockHandle
  418. )
  419. /*++
  420. Routine Description:
  421. This function releases an in stack queued spinlock at the current IRQL.
  422. Arguments:
  423. LockHandle - Supplies a pointer to lock queue handle.
  424. Return Value:
  425. None.
  426. --*/
  427. {
  428. //
  429. // Release the specified in stack queued spin lock at the current IRQL.
  430. //
  431. KxReleaseQueuedSpinLock(&LockHandle->LockQueue);
  432. return;
  433. }