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.

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