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.

973 lines
26 KiB

  1. //++
  2. //
  3. // Module Name:
  4. //
  5. // intrlock.s
  6. //
  7. // Abstract:
  8. //
  9. // This module implements the functions to support interlocked
  10. // operations. Interlocked operations can only operate on
  11. // nonpaged data and the specified spinlock cannot be used for
  12. // any other purpose.
  13. //
  14. // Author:
  15. //
  16. // William K. Cheung (wcheung) 27-Sep-95
  17. //
  18. // Revision History:
  19. //
  20. // 07-Jul-97 bl Updated to EAS2.3
  21. //
  22. // 02-Feb-96 Updated to EAS2.1
  23. //
  24. //--
  25. #include "ksia64.h"
  26. .file "intrlock.s"
  27. //++
  28. //
  29. // LARGE_INTEGER
  30. // ExInterlockedAddLargeInteger (
  31. // IN PLARGE_INTEGER Addend,
  32. // IN LARGE_INTEGER Increment,
  33. // IN PKSPIN_LOCK Lock
  34. // )
  35. //
  36. // Routine Description:
  37. //
  38. // This function performs an interlocked add of an increment value to an
  39. // addend variable of type large integer. The initial value of the addend
  40. // variable is returned as the function value.
  41. //
  42. // Arguments:
  43. //
  44. // Addend (a0) - Supplies a pointer to a variable whose value is to be
  45. // adjusted by the increment value.
  46. //
  47. // Increment (a1) - Supplies the increment value to be added to the
  48. // addend variable.
  49. //
  50. // Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  51. // access to the addend variable.
  52. //
  53. // Return Value:
  54. //
  55. // The initial value of the addend variable is stored at the address
  56. // supplied by v0.
  57. //
  58. //--
  59. #if !defined(NT_UP)
  60. LEAF_ENTRY(ExInterlockedAddLargeInteger)
  61. //
  62. // disable interrupt and then acquire the spinlock
  63. //
  64. rsm 1 << PSR_I // disable interrupt
  65. cmp.eq pt0, pt1 = zero, zero
  66. cmp.eq pt2 = zero, zero
  67. ;;
  68. Eiali10:
  69. .pred.rel "mutex",pt0,pt1
  70. (pt0) xchg8 t0 = [a2], a2
  71. (pt1) ld8.nt1 t0 = [a2]
  72. ;;
  73. (pt0) cmp.ne pt2 = zero, t0
  74. cmp.eq pt0, pt1 = zero, t0
  75. ;;
  76. (pt1) ssm 1 << PSR_I // enable interrupt
  77. (pt0) rsm 1 << PSR_I // disable interrupt
  78. (pt2) br.dpnt Eiali10
  79. ;;
  80. ld8 v0 = [a0]
  81. ;;
  82. add t1 = a1, v0 // do the add
  83. ;;
  84. st8 [a0] = t1 // save result
  85. st8.rel.nta [a2] = zero // release spinlock
  86. ssm 1 << PSR_I // enable interrupt
  87. br.ret.sptk.clr brp // return
  88. ;;
  89. LEAF_EXIT(ExInterlockedAddLargeInteger)
  90. #else
  91. LEAF_ENTRY(ExInterlockedAddLargeInteger)
  92. rsm 1 << PSR_I // disable interrupt
  93. ;;
  94. ld8.acq v0 = [a0]
  95. ;;
  96. add t0 = a1, v0
  97. ;;
  98. st8.rel [a0] = t0
  99. ssm 1 << PSR_I // enable interrupt
  100. br.ret.sptk brp
  101. ;;
  102. LEAF_EXIT(ExInterlockedAddLargeInteger)
  103. #endif // !defined(NT_UP)
  104. //++
  105. //
  106. // VOID
  107. // ExInterlockedAddLargeStatistic (
  108. // IN PLARGE_INTEGER Addend,
  109. // IN ULONG Increment
  110. // )
  111. //
  112. // Routine Description:
  113. //
  114. // This function performs an interlocked add of an increment value to an
  115. // addend variable of type large integer.
  116. //
  117. // Arguments:
  118. //
  119. // Addend (a0) - Supplies a pointer to a variable whose value is to be
  120. // adjusted by the increment value.
  121. //
  122. // Increment (a1) - Supplies the increment value to be added to the
  123. // addend variable.
  124. //
  125. // Return Value:
  126. //
  127. // None.
  128. //
  129. //--
  130. LEAF_ENTRY(ExInterlockedAddLargeStatistic)
  131. ld8.nt1 v0 = [a0]
  132. extr.u a1 = a1, 0, 32 // sanitize the top 32 bits
  133. ;;
  134. Eials10:
  135. nop.m 0
  136. mov ar.ccv = v0
  137. add t0 = a1, v0
  138. ;;
  139. //
  140. // If the addend has been modified since the last load, pt8 will be set
  141. // to TRUE and need to branch back to Eiali10 to retry the operation again.
  142. //
  143. cmpxchg8.rel t1 = [a0], t0, ar.ccv
  144. ;;
  145. cmp.ne pt8, pt7 = v0, t1
  146. mov v0 = t1
  147. ;;
  148. nop.m 0
  149. (pt8) br.cond.spnt Eials10 // if failed, then try again
  150. (pt7) br.ret.sptk.clr brp // otherwise, return
  151. ;;
  152. LEAF_EXIT(ExInterlockedAddLargeStatistic)
  153. //++
  154. //
  155. // ULONG
  156. // ExInterlockedAddUlong (
  157. // IN PULONG Addend,
  158. // IN ULONG Increment,
  159. // IN PKSPIN_LOCK Lock
  160. // )
  161. //
  162. // Routine Description:
  163. //
  164. // This function performs an interlocked add of an increment value to an
  165. // addend variable of type unsigned long. The initial value of the addend
  166. // variable is returned as the function value.
  167. //
  168. // Arguments:
  169. //
  170. // Addend (a0) - Supplies a pointer to a variable whose value is to be
  171. // adjusted by the increment value.
  172. //
  173. // Increment (a1) - Supplies the increment value to be added to the
  174. // addend variable.
  175. //
  176. // Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  177. // access to the addend variable.
  178. //
  179. // Return Value:
  180. //
  181. // The initial value of the addend variable.
  182. //
  183. //--
  184. #if !defined(NT_UP)
  185. LEAF_ENTRY(ExInterlockedAddUlong)
  186. //
  187. // disable interrupt and then acquire the spinlock
  188. //
  189. rsm 1 << PSR_I // disable interrupt
  190. zxt4 a1 = a1 // sanitize the top 32 bits
  191. cmp.eq pt0, pt1 = zero, zero
  192. cmp.eq pt2 = zero, zero
  193. ;;
  194. Eiau10:
  195. .pred.rel "mutex",pt0,pt1
  196. (pt0) xchg8 t0 = [a2], a2
  197. (pt1) ld8.nt1 t0 = [a2]
  198. ;;
  199. (pt0) cmp.ne pt2 = zero, t0
  200. cmp.eq pt0, pt1 = zero, t0
  201. ;;
  202. (pt1) ssm 1 << PSR_I // enable interrupt
  203. (pt0) rsm 1 << PSR_I // disable interrupt
  204. (pt2) br.dpnt Eiau10
  205. ;;
  206. //
  207. // lock acquired; load the addend, perform the addition and write it back.
  208. // then release the lock and enable interrupts.
  209. //
  210. ld4 v0 = [a0]
  211. ;;
  212. add t0 = a1, v0 // do the add
  213. ;;
  214. st4 [a0] = t0 // save result
  215. st8.rel.nta [a2] = zero // release spinlock
  216. ssm 1 << PSR_I // enable interrupt
  217. br.ret.sptk.clr brp // return
  218. LEAF_EXIT(ExInterlockedAddUlong)
  219. #else
  220. LEAF_ENTRY(ExInterlockedAddUlong)
  221. rsm 1 << PSR_I // disable interrupt
  222. ;;
  223. ld4.acq v0 = [a0]
  224. zxt4 a1 = a1 // sanitize the top 32 bits
  225. ;;
  226. add t0 = a1, v0
  227. ;;
  228. st4.rel [a0] = t0
  229. ssm 1 << PSR_I // enable interrupt
  230. br.ret.sptk brp
  231. ;;
  232. LEAF_EXIT(ExInterlockedAddUlong)
  233. #endif // !defined(NT_UP)
  234. //++
  235. //
  236. // ULONG
  237. // ExInterlockedExchangeUlong (
  238. // IN PULONG Source,
  239. // IN ULONG Value,
  240. // IN PKSPIN_LOCK Lock
  241. // )
  242. //
  243. // Routine Description:
  244. //
  245. // This function performs an interlocked exchange of a longword value with
  246. // a longword in memory and returns the memory value.
  247. //
  248. // N.B. There is an alternate entry point provided for this routine which
  249. // is IA64 target specific and whose prototype does not include the
  250. // spinlock parameter. Since the routine never refers to the spinlock
  251. // parameter, no additional code is required.
  252. //
  253. // Arguments:
  254. //
  255. // Source (a0) - Supplies a pointer to a variable whose value is to be
  256. // exchanged.
  257. //
  258. // Value (a1) - Supplies the value to exchange with the source value.
  259. //
  260. // Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  261. // access to the source variable.
  262. //
  263. // Return Value:
  264. //
  265. // The source value is returned as the function value.
  266. //
  267. // Implementation Note:
  268. //
  269. // The specification of this function does not require that the given lock
  270. // be used to synchronize the update as long as the update is synchronized
  271. // somehow. On Alpha a single load locked-store conditional does the job.
  272. //
  273. //--
  274. LEAF_ENTRY(ExInterlockedExchangeUlong)
  275. ALTERNATE_ENTRY(ExIa64InterlockedExchangeUlong)
  276. mf
  277. zxt4 a1 = a1 // sanitize the upper 32 bits
  278. ;;
  279. xchg4 v0 = [a0], a1
  280. br.ret.sptk.clr brp
  281. LEAF_EXIT(ExInterlockedExchangeUlong)
  282. //++
  283. //
  284. // LONG
  285. // InterlockedExchangeAdd (
  286. // IN OUT PLONG Addend,
  287. // IN LONG Increment
  288. // )
  289. //
  290. // Routine Description:
  291. //
  292. // This function performs an interlocked add of an increment value to an
  293. // addend variable of type unsinged long. The initial value of the addend
  294. // variable is returned as the function value.
  295. //
  296. // It is NOT possible to mix ExInterlockedDecrementLong and
  297. // ExInterlockedIncrementong with ExInterlockedAddUlong.
  298. //
  299. //
  300. // Arguments:
  301. //
  302. // Addend - Supplies a pointer to a variable whose value is to be
  303. // adjusted by the increment value.
  304. //
  305. // Increment - Supplies the increment value to be added to the
  306. // addend variable.
  307. //
  308. // Return Value:
  309. //
  310. // (r8) - The initial value of the addend.
  311. //
  312. //--
  313. LEAF_ENTRY(InterlockedExchangeAdd)
  314. ld4.nt1 v0 = [a0]
  315. ;;
  316. Iea10:
  317. mov ar.ccv = v0
  318. add t1 = a1, v0
  319. mov t0 = v0
  320. ;;
  321. cmpxchg4.acq v0 = [a0], t1, ar.ccv
  322. nop.m 0
  323. nop.i 0
  324. ;;
  325. cmp.ne pt7, pt8 = v0, t0
  326. (pt7) br.cond.spnt Iea10
  327. (pt8) br.ret.sptk.clr brp
  328. ;;
  329. LEAF_EXIT(InterlockedExchangeAdd)
  330. //++
  331. //
  332. // PVOID
  333. // InterlockedCompareExchange (
  334. // IN OUT PVOID *Destination,
  335. // IN PVOID Exchange,
  336. // IN PVOID Comperand
  337. // )
  338. //
  339. // Routine Description:
  340. //
  341. // This function performs an interlocked compare of the destination
  342. // value with the comperand value. If the destination value is equal
  343. // to the comperand value, then the exchange value is stored in the
  344. // destination. Otherwise, no operation is performed.
  345. //
  346. // Arguments:
  347. //
  348. // Destination - Supplies a pointer to destination value.
  349. //
  350. // Exchange - Supplies the exchange value.
  351. //
  352. // Comperand - Supplies the comperand value.
  353. //
  354. // Return Value:
  355. //
  356. // (r8) - The initial destination value.
  357. //
  358. //--
  359. LEAF_ENTRY(InterlockedCompareExchange)
  360. mf
  361. mov ar.ccv = a2
  362. ;;
  363. cmpxchg4.acq v0 = [a0], a1, ar.ccv
  364. br.ret.sptk.clr brp
  365. ;;
  366. LEAF_EXIT(InterlockedCompareExchange)
  367. //++
  368. //
  369. // INTERLOCKED_RESULT
  370. // ExInterlockedDecrementLong (
  371. // IN PLONG Addend,
  372. // IN PKSPIN_LOCK Lock
  373. // )
  374. //
  375. // Routine Description:
  376. //
  377. // This function performs an interlocked decrement on an addend variable
  378. // of type signed long. The sign and whether the result is zero is returned
  379. // as the function value.
  380. //
  381. // N.B. There is an alternate entry point provided for this routine which
  382. // is IA64 target specific and whose prototype does not include the
  383. // spinlock parameter. Since the routine never refers to the spinlock
  384. // parameter, no additional code is required.
  385. //
  386. // Arguments:
  387. //
  388. // Addend (a0) - Supplies a pointer to a variable whose value is to be
  389. // decremented.
  390. //
  391. // Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  392. // access to the addend variable.
  393. //
  394. // Return Value:
  395. //
  396. // RESULT_NEGATIVE is returned if the resultant addend value is negative.
  397. // RESULT_ZERO is returned if the resultant addend value is zero.
  398. // RESULT_POSITIVE is returned if the resultant addend value is positive.
  399. //
  400. // RESULT_ZERO = 0
  401. // RESULT_NEGATIVE = 1
  402. // RESULT_POSITIVE = 2
  403. //
  404. // Implementation Notes:
  405. //
  406. // The specification of this function does not require that the given lock
  407. // be used to synchronize the update as long as the update is synchronized
  408. // somehow. On Alpha a single load locked-store conditional does the job.
  409. //
  410. //--
  411. LEAF_ENTRY(ExInterlockedDecrementLong)
  412. ALTERNATE_ENTRY(ExIa64InterlockedDecrementLong)
  413. fetchadd4.acq t1 = [a0], -1
  414. mov v0 = 0 // assume result is zero
  415. ;;
  416. cmp4.le pt7, p0 = 2, t1
  417. cmp4.ge pt8, p0 = 0, t1
  418. ;;
  419. .pred.rel "mutex",pt7,pt8
  420. (pt8) mov v0 = 1 // negative result
  421. (pt7) mov v0 = 2 // positive result
  422. br.ret.sptk.clr brp // return
  423. ;;
  424. LEAF_EXIT(ExInterlockedDecrementLong)
  425. //++
  426. //
  427. // INTERLOCKED_RESULT
  428. // ExInterlockedIncrementLong (
  429. // IN PLONG Addend,
  430. // IN PKSPIN_LOCK Lock
  431. // )
  432. //
  433. // Routine Description:
  434. //
  435. // This function performs an interlocked increment on an addend variable
  436. // of type signed long. The sign and whether the result is zero is returned
  437. // as the function value.
  438. //
  439. // N.B. There is an alternate entry point provided for this routine which
  440. // is IA64 target specific and whose prototype does not include the
  441. // spinlock parameter. Since the routine never refers to the spinlock
  442. // parameter, no additional code is required.
  443. //
  444. // Arguments:
  445. //
  446. // Addend (a0) - Supplies a pointer to a variable whose value is to be
  447. // incremented.
  448. //
  449. // Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  450. // access to the addend variable.
  451. //
  452. // Return Value:
  453. //
  454. // RESULT_NEGATIVE is returned if the resultant addend value is negative.
  455. // RESULT_ZERO is returned if the resultant addend value is zero.
  456. // RESULT_POSITIVE is returned if the resultant addend value is positive.
  457. //
  458. // Implementation Notes:
  459. //
  460. // The specification of this function does not require that the given lock
  461. // be used to synchronize the update as long as the update is synchronized
  462. // somehow. On Alpha a single load locked-store conditional does the job.
  463. //
  464. //--
  465. LEAF_ENTRY(ExInterlockedIncrementLong)
  466. ALTERNATE_ENTRY(ExIa64InterlockedIncrementLong)
  467. fetchadd4.acq t1 = [a0], 1
  468. mov v0 = 0 // assume result is zero
  469. ;;
  470. cmp4.le pt7, p0 = 0, t1
  471. cmp4.ge pt8, p0 = -2, t1
  472. ;;
  473. .pred.rel "mutex",pt7,pt8
  474. (pt8) mov v0 = 1 // negative result
  475. (pt7) mov v0 = 2 // positive result
  476. br.ret.sptk.clr brp // return
  477. ;;
  478. LEAF_EXIT(ExInterlockedIncrementLong)
  479. //++
  480. //
  481. // PLIST_ENTRY
  482. // ExInterlockedInsertHeadList (
  483. // IN PLIST_ENTRY ListHead,
  484. // IN PLIST_ENTRY ListEntry,
  485. // IN PKSPIN_LOCK Lock
  486. // )
  487. //
  488. // Routine Description:
  489. //
  490. // This function inserts an entry at the head of a doubly linked list
  491. // so that access to the list is synchronized in a multiprocessor system.
  492. //
  493. // Arguments:
  494. //
  495. // ListHead (a0) - Supplies a pointer to the head of the doubly linked
  496. // list into which an entry is to be inserted.
  497. //
  498. // ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  499. // head of the list.
  500. //
  501. // Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  502. // access to the list.
  503. //
  504. // Return Value:
  505. //
  506. // Pointer to entry that was at the head of the list or NULL if the list
  507. // was empty.
  508. //
  509. //--
  510. LEAF_ENTRY(ExInterlockedInsertHeadList)
  511. //
  512. // disable interrupt and then try to acquire the spinlock
  513. //
  514. add t3 = LsFlink, a0
  515. add t5 = LsBlink, a1
  516. add t4 = LsFlink, a1
  517. rsm 1 << PSR_I // disable interrupt
  518. #if !defined(NT_UP)
  519. cmp.eq pt0, pt1 = zero, zero
  520. cmp.eq pt2 = zero, zero
  521. ;;
  522. Eiihl10:
  523. .pred.rel "mutex",pt0,pt1
  524. (pt0) xchg8 t0 = [a2], a2
  525. (pt1) ld8.nt1 t0 = [a2]
  526. ;;
  527. (pt0) cmp.ne pt2 = zero, t0
  528. cmp.eq pt0, pt1 = zero, t0
  529. ;;
  530. (pt1) ssm 1 << PSR_I // enable interrupt
  531. (pt0) rsm 1 << PSR_I // disable interrupt
  532. (pt2) br.dpnt Eiihl10
  533. #endif // !defined(NT_UP)
  534. ;;
  535. LDPTR(v0, t3) // get address of next entry
  536. STPTR(t5, a0) // store previous link in next
  537. STPTR(t3, a1) // store next link in head
  538. ;;
  539. STPTR(t4, v0) // store next link in entry
  540. add t6 = LsBlink, v0
  541. ;;
  542. STPTR(t6, a1) // store previous link in next
  543. #if !defined(NT_UP)
  544. st8.rel.nta [a2] = zero // release the spinlock
  545. #endif // !defined(NT_UP)
  546. cmp.eq pt4, p0 = v0, a0 // if v0 == a0, list empty
  547. ;;
  548. ssm 1 << PSR_I // enable interrupt
  549. (pt4) mov v0 = zero
  550. br.ret.sptk.clr brp // return
  551. ;;
  552. LEAF_EXIT(ExInterlockedInsertHeadList)
  553. //++
  554. //
  555. // PLIST_ENTRY
  556. // ExInterlockedInsertTailList (
  557. // IN PLIST_ENTRY ListHead,
  558. // IN PLIST_ENTRY ListEntry,
  559. // IN PKSPIN_LOCK Lock
  560. // )
  561. //
  562. // Routine Description:
  563. //
  564. // This function inserts an entry at the tail of a doubly linked list
  565. // so that access to the list is synchronized in a multiprocessor system.
  566. //
  567. // Arguments:
  568. //
  569. // ListHead (a0) - Supplies a pointer to the head of the doubly linked
  570. // list into which an entry is to be inserted.
  571. //
  572. // ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  573. // tail of the list.
  574. //
  575. // Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  576. // access to the list.
  577. //
  578. // Return Value:
  579. //
  580. // Pointer to entry that was at the tail of the list or NULL if the list
  581. // was empty.
  582. //
  583. //--
  584. LEAF_ENTRY(ExInterlockedInsertTailList)
  585. //
  586. // disable interrupt and then try to acquire the spinlock
  587. //
  588. add t3 = LsBlink, a0
  589. add t4 = LsFlink, a1
  590. add t5 = LsBlink, a1
  591. rsm 1 << PSR_I // disable interrupt
  592. #if !defined(NT_UP)
  593. cmp.eq pt0, pt1 = zero, zero
  594. cmp.eq pt2 = zero, zero
  595. ;;
  596. Eiitl10:
  597. .pred.rel "mutex",pt0,pt1
  598. (pt0) xchg8 t0 = [a2], a2
  599. (pt1) ld8.nt1 t0 = [a2]
  600. ;;
  601. (pt0) cmp.ne pt2 = zero, t0
  602. cmp.eq pt0, pt1 = zero, t0
  603. ;;
  604. (pt1) ssm 1 << PSR_I // enable interrupt
  605. (pt0) rsm 1 << PSR_I // disable interrupt
  606. (pt2) br.dpnt Eiitl10
  607. #endif // !defined(NT_UP)
  608. ;;
  609. LDPTR(v0, t3) // get address of previous entry
  610. STPTR(t4, a0) // store next link in entry
  611. STPTR(t3, a1) // store previous link in head
  612. ;;
  613. STPTR(t5, v0) // store previous link in entry
  614. add t6 = LsFlink, v0
  615. ;;
  616. STPTR(t6, a1) // store next in previous entry
  617. #if !defined(NT_UP)
  618. st8.rel.nta [a2] = zero // release the spinlock
  619. #endif // !defined(NT_UP)
  620. cmp.eq pt4, p0 = v0, a0 // if v0 == a0, list empty
  621. ;;
  622. ssm 1 << PSR_I // enable interrupt
  623. (pt4) mov v0 = zero
  624. br.ret.sptk.clr brp // return
  625. ;;
  626. LEAF_EXIT(ExInterlockedInsertTailList)
  627. //++
  628. //
  629. // PLIST_ENTRY
  630. // ExInterlockedRemoveHeadList (
  631. // IN PLIST_ENTRY ListHead,
  632. // IN PKSPIN_LOCK Lock
  633. // )
  634. //
  635. // Routine Description:
  636. //
  637. // This function removes an entry from the head of a doubly linked list
  638. // so that access to the list is synchronized in a multiprocessor system.
  639. // If there are no entries in the list, then a value of NULL is returned.
  640. // Otherwise, the address of the entry that is removed is returned as the
  641. // function value.
  642. //
  643. // Arguments:
  644. //
  645. // ListHead (a0) - Supplies a pointer to the head of the doubly linked
  646. // list from which an entry is to be removed.
  647. //
  648. // Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  649. // access to the list.
  650. //
  651. // Return Value:
  652. //
  653. // The address of the entry removed from the list, or NULL if the list is
  654. // empty.
  655. //
  656. //--
  657. LEAF_ENTRY(ExInterlockedRemoveHeadList)
  658. //
  659. // disable interrupt and then acquire the spinlock
  660. //
  661. rsm 1 << PSR_I // disable interrupt
  662. add t3 = LsFlink, a0
  663. #if !defined(NT_UP)
  664. cmp.eq pt0, pt1 = zero, zero
  665. cmp.eq pt2 = zero, zero
  666. ;;
  667. Eirhl10:
  668. .pred.rel "mutex",pt0,pt1
  669. (pt0) xchg8 t0 = [a1], a1
  670. (pt1) ld8.nt1 t0 = [a1]
  671. ;;
  672. (pt0) cmp.ne pt2 = zero, t0
  673. cmp.eq pt0, pt1 = zero, t0
  674. ;;
  675. (pt1) ssm 1 << PSR_I // enable interrupt
  676. (pt0) rsm 1 << PSR_I // disable interrupt
  677. (pt2) br.dpnt Eirhl10
  678. #endif // !defined(NT_UP)
  679. ;;
  680. LDPTR(v0, t3) // get address of next entry
  681. ;;
  682. cmp.eq pt4, pt3 = v0, a0 // if v0 == a0, list is empty
  683. add t5 = LsFlink, v0
  684. ;;
  685. PLDPTR(pt3, t6, t5) // get address of next in next
  686. ;;
  687. PSTPTR(pt3, t3, t6) // store address of next in head
  688. (pt3) add t7 = LsBlink, t6
  689. ;;
  690. PSTPTR(pt3, t7, a0) // store addr of prev in next
  691. #if !defined(NT_UP)
  692. st8.rel.nta [a1] = zero // release the spinlock
  693. #endif // !defined(NT_UP)
  694. ssm 1 << PSR_I // enable interrupt
  695. (pt4) mov v0 = zero
  696. br.ret.sptk.clr brp // return
  697. ;;
  698. LEAF_EXIT(ExInterlockedRemoveHeadList)
  699. //++
  700. //
  701. // PSINGLE_LIST_ENTRY
  702. // ExInterlockedPopEntryList (
  703. // IN PSINGLE_LIST_ENTRY ListHead,
  704. // IN PKSPIN_LOCK Lock
  705. // )
  706. //
  707. // Routine Description:
  708. //
  709. // This function removes an entry from the head of a singly linked list
  710. // so that access to the list is synchronized in a multiprocessor system.
  711. // If there are no entries in the list, then a value of NULL is returned.
  712. // Otherwise, the address of the entry that is removed is returned as the
  713. // function value.
  714. //
  715. // Arguments:
  716. //
  717. // ListHead (a0) - Supplies a pointer to the head of the singly linked
  718. // list from which an entry is to be removed.
  719. //
  720. // Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  721. // access to the list.
  722. //
  723. // Return Value:
  724. //
  725. // The address of the entry removed from the list, or NULL if the list is
  726. // empty.
  727. //
  728. //--
  729. LEAF_ENTRY(ExInterlockedPopEntryList)
  730. //
  731. // disable interrupt and then acquire the spinlock
  732. //
  733. rsm 1 << PSR_I // disable interrupt
  734. #if !defined(NT_UP)
  735. cmp.eq pt0, pt1 = zero, zero
  736. cmp.eq pt2 = zero, zero
  737. ;;
  738. Eipopel10:
  739. .pred.rel "mutex",pt0,pt1
  740. (pt0) xchg8 t0 = [a1], a1
  741. (pt1) ld8.nt1 t0 = [a1]
  742. ;;
  743. (pt0) cmp.ne pt2 = zero, t0
  744. cmp.eq pt0, pt1 = zero, t0
  745. ;;
  746. (pt1) ssm 1 << PSR_I // enable interrupt
  747. (pt0) rsm 1 << PSR_I // disable interrupt
  748. (pt2) br.dpnt Eipopel10
  749. #endif // !defined(NT_UP)
  750. ;;
  751. LDPTR(v0, a0) // get address of next entry
  752. ;;
  753. cmp.ne pt4, p0 = zero, v0 // if v0 == NULL, list is empty
  754. ;;
  755. PLDPTR(pt4, t6, v0) // get address of next entry
  756. ;;
  757. PSTPTR(pt4, a0, t6) // store address of next in head
  758. #if !defined(NT_UP)
  759. st8.rel.nta [a1] = zero // release the spinlock
  760. #endif // !defined(NT_UP)
  761. ssm 1 << PSR_I // enable interrupt
  762. br.ret.sptk.clr brp // return
  763. ;;
  764. LEAF_EXIT(ExInterlockedPopEntryList)
  765. //++
  766. //
  767. // PSINGLE_LIST_ENTRY
  768. // ExInterlockedPushEntryList (
  769. // IN PSINGLE_LIST_ENTRY ListHead,
  770. // IN PSINGLE_LIST_ENTRY ListEntry,
  771. // IN PKSPIN_LOCK Lock
  772. // )
  773. //
  774. // Routine Description:
  775. //
  776. // This function inserts an entry at the head of a singly linked list
  777. // so that access to the list is synchronized in a multiprocessor system.
  778. //
  779. // Arguments:
  780. //
  781. // ListHead (a0) - Supplies a pointer to the head of the singly linked
  782. // list into which an entry is to be inserted.
  783. //
  784. // ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  785. // head of the list.
  786. //
  787. // Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  788. // access to the list.
  789. //
  790. // Return Value:
  791. //
  792. // Previous contents of ListHead. NULL implies list went from empty
  793. // to not empty.
  794. //
  795. //--
  796. LEAF_ENTRY(ExInterlockedPushEntryList)
  797. //
  798. // disable interrupt and then acquire the spinlock
  799. //
  800. rsm 1 << PSR_I // disable interrupt
  801. #if !defined(NT_UP)
  802. cmp.eq pt0, pt1 = zero, zero
  803. cmp.eq pt2 = zero, zero
  804. ;;
  805. Eipushel10:
  806. .pred.rel "mutex",pt0,pt1
  807. (pt0) xchg8 t0 = [a2], a2
  808. (pt1) ld8.nt1 t0 = [a2]
  809. ;;
  810. (pt0) cmp.ne pt2 = zero, t0
  811. cmp.eq pt0, pt1 = zero, t0
  812. ;;
  813. (pt1) ssm 1 << PSR_I // enable interrupt
  814. (pt0) rsm 1 << PSR_I // disable interrupt
  815. (pt2) br.dpnt Eipushel10
  816. #endif // !defined(NT_UP)
  817. ;;
  818. LDPTR(v0, a0) // get address of next entry
  819. STPTR(a0, a1) // set address of first entry
  820. ;;
  821. STPTR(a1, v0) // set addr of next in new entry
  822. #if !defined(NT_UP)
  823. st8.rel.nta [a2] = zero // release the spinlock
  824. #endif // !defined(NT_UP)
  825. ssm 1 << PSR_I // enable interrupt
  826. br.ret.sptk brp // return
  827. ;;
  828. LEAF_EXIT(ExInterlockedPushEntryList)