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.

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