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.

1137 lines
28 KiB

  1. title "Interlocked Support"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; intrlfst.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements functions to support interlocked operations.
  13. ; Interlocked operations can only operate on nonpaged data.
  14. ;
  15. ; This module implements the fast call version of the interlocked
  16. ; fuctions.
  17. ;
  18. ; Author:
  19. ;
  20. ; Ken Reneris (kenr) 5-May-1994
  21. ;
  22. ; Environment:
  23. ;
  24. ; Any mode.
  25. ;
  26. ; Revision History:
  27. ;
  28. ;--
  29. .386p
  30. .xlist
  31. include ks386.inc
  32. include callconv.inc ; calling convention macros
  33. include mac386.inc
  34. .list
  35. _TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
  36. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  37. ;++
  38. ;
  39. ; General Notes on Interlocked Procedures:
  40. ;
  41. ; These procedures assume that neither their code, nor any of
  42. ; the data they touch, will cause a page fault.
  43. ;
  44. ; They use spinlocks to achieve MP atomicity, iff it's an MP machine.
  45. ; (The spinlock macros generate zilch if NT_UP = 1, and
  46. ; we if out some aux code here as well.)
  47. ;
  48. ; They turn off interrupts so that they can be used for synchronization
  49. ; between ISRs and driver code. Flags are preserved so they can
  50. ; be called in special code (Like IPC interrupt handlers) that
  51. ; may have interrupts off.
  52. ;
  53. ;--
  54. ;; align 512
  55. page ,132
  56. subttl "ExInterlockedAddLargeStatistic"
  57. ;++
  58. ;
  59. ; VOID
  60. ; FASTCALL
  61. ; ExInterlockedAddLargeStatistic (
  62. ; IN PLARGE_INTEGER Addend,
  63. ; IN ULONG Increment
  64. ; )
  65. ;
  66. ; Routine Description:
  67. ;
  68. ; This function performs an interlocked add of an increment value to an
  69. ; addend variable of type unsigned large integer.
  70. ;
  71. ; Arguments:
  72. ;
  73. ; (ecx) Addend - Supplies a pointer to the variable whose value is
  74. ; adjusted by the increment value.
  75. ;
  76. ; (edx) Increment - Supplies the increment value that is added to the
  77. ; addend variable.
  78. ;
  79. ; Return Value:
  80. ;
  81. ; None.
  82. ;
  83. ;--
  84. cPublicFastCall ExInterlockedAddLargeStatistic, 2
  85. cPublicFpo 0,0
  86. ifdef NT_UP
  87. add dword ptr [ecx], edx ; add low part of large statistic
  88. adc dword ptr [ecx+4], 0 ; add carry to high part
  89. else
  90. lock add dword ptr [ecx], edx ; add low part of large statistic
  91. jc short Eils10 ; if c, add generated a carry
  92. fstRET ExInterlockedAddLargeStatistic ; return
  93. Eils10: lock adc dword ptr [ecx+4], 0 ; add carry to high part
  94. endif
  95. fstRET ExInterlockedAddLargeStatistic ; return
  96. fstENDP ExInterlockedAddLargeStatistic
  97. page , 132
  98. subttl "Interlocked Add Unsigned Long"
  99. ;++
  100. ;
  101. ; ULONG
  102. ; FASTCALL
  103. ; ExfInterlockedAddUlong (
  104. ; IN PULONG Addend,
  105. ; IN ULONG Increment,
  106. ; IN PKSPIN_LOCK Lock
  107. ; )
  108. ;
  109. ; Routine Description:
  110. ;
  111. ; This function performs an interlocked add of an increment value to an
  112. ; addend variable of type unsinged long. The initial value of the addend
  113. ; variable is returned as the function value.
  114. ;
  115. ; It is NOT possible to mix ExInterlockedDecrementLong and
  116. ; ExInterlockedIncrementong with ExInterlockedAddUlong.
  117. ;
  118. ;
  119. ; Arguments:
  120. ;
  121. ; (ecx) Addend - Supplies a pointer to a variable whose value is to be
  122. ; adjusted by the increment value.
  123. ;
  124. ; (edx) Increment - Supplies the increment value to be added to the
  125. ; addend variable.
  126. ;
  127. ; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
  128. ; access to the addend variable.
  129. ;
  130. ; Return Value:
  131. ;
  132. ; The initial value of the addend variable.
  133. ;
  134. ;--
  135. cPublicFastCall ExfInterlockedAddUlong, 3
  136. cPublicFpo 1, 1
  137. ifdef NT_UP
  138. ;
  139. ; UP version of ExInterlockedAddUlong
  140. ;
  141. pushfd
  142. cli ; disable interrupts
  143. mov eax, [ecx] ; (eax)= initial addend value
  144. add [ecx], edx ; [ecx]=adjusted value
  145. popfd ; restore flags including ints
  146. fstRET ExfInterlockedAddUlong
  147. else
  148. ;
  149. ; MP version of ExInterlockedAddUlong
  150. ;
  151. pushfd
  152. mov eax, [esp+8] ; (eax) = SpinLock
  153. Eial10: cli ; disable interrupts
  154. ACQUIRE_SPINLOCK eax, <short Eial20>
  155. mov eax, [ecx] ; (eax)=initial addend value
  156. add [ecx], edx ; [ecx]=adjusted value
  157. mov edx, [esp+8] ; (edx) = SpinLock
  158. RELEASE_SPINLOCK edx
  159. popfd
  160. fstRET ExfInterlockedAddUlong
  161. Eial20: popfd
  162. pushfd
  163. SPIN_ON_SPINLOCK eax, <short Eial10>
  164. endif
  165. fstENDP ExfInterlockedAddUlong
  166. page , 132
  167. subttl "Interlocked Insert Head List"
  168. ;++
  169. ;
  170. ; PLIST_ENTRY
  171. ; ExfInterlockedInsertHeadList (
  172. ; IN PLIST_ENTRY ListHead,
  173. ; IN PLIST_ENTRY ListEntry,
  174. ; IN PKSPIN_LOCK Lock
  175. ; )
  176. ;
  177. ; Routine Description:
  178. ;
  179. ; This function inserts an entry at the head of a doubly linked list
  180. ; so that access to the list is synchronized in a multiprocessor system.
  181. ;
  182. ; N.B. The pages of data which this routine operates on MUST be
  183. ; present. No page fault is allowed in this routine.
  184. ;
  185. ; Arguments:
  186. ;
  187. ; (ecx) = ListHead - Supplies a pointer to the head of the doubly linked
  188. ; list into which an entry is to be inserted.
  189. ;
  190. ; (edx) = ListEntry - Supplies a pointer to the entry to be inserted at the
  191. ; head of the list.
  192. ;
  193. ; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
  194. ; access to the list.
  195. ;
  196. ; Return Value:
  197. ;
  198. ; Pointer to entry that was at the head of the list or NULL if the list
  199. ; was empty.
  200. ;
  201. ;--
  202. cPublicFastCall ExfInterlockedInsertHeadList , 3
  203. cPublicFpo 1, 1
  204. ifndef NT_UP
  205. cPublicFpo 1, 2
  206. push esi
  207. mov esi, [esp+8] ; Address of spinlock
  208. endif
  209. pushfd
  210. Eiih10: cli
  211. ACQUIRE_SPINLOCK esi,<short Eiih20>
  212. mov eax, LsFlink[ecx] ; (eax)->next entry in the list
  213. mov [edx]+LsFlink, eax ; store next link in entry
  214. mov [edx]+LsBlink, ecx ; store previous link in entry
  215. mov [ecx]+LsFlink, edx ; store next link in head
  216. mov [eax]+LsBlink, edx ; store previous link in next
  217. RELEASE_SPINLOCK esi
  218. popfd
  219. ifndef NT_UP
  220. pop esi
  221. endif
  222. xor eax, ecx ; return null if list was empty
  223. jz short Eiih15
  224. xor eax, ecx
  225. Eiih15: fstRET ExfInterlockedInsertHeadList
  226. ifndef NT_UP
  227. Eiih20: popfd
  228. pushfd
  229. SPIN_ON_SPINLOCK esi, <short Eiih10>
  230. endif
  231. fstENDP ExfInterlockedInsertHeadList
  232. page , 132
  233. subttl "Interlocked Insert Tail List"
  234. ;++
  235. ;
  236. ; PLIST_ENTRY
  237. ; FASTCALL
  238. ; ExfInterlockedInsertTailList (
  239. ; IN PLIST_ENTRY ListHead,
  240. ; IN PLIST_ENTRY ListEntry,
  241. ; IN PKSPIN_LOCK Lock
  242. ; )
  243. ;
  244. ; Routine Description:
  245. ;
  246. ; This function inserts an entry at the tail of a doubly linked list
  247. ; so that access to the list is synchronized in a multiprocessor system.
  248. ;
  249. ; N.B. The pages of data which this routine operates on MUST be
  250. ; present. No page fault is allowed in this routine.
  251. ;
  252. ; Arguments:
  253. ;
  254. ; (ecx) = ListHead - Supplies a pointer to the head of the doubly linked
  255. ; list into which an entry is to be inserted.
  256. ;
  257. ; (edx) = ListEntry - Supplies a pointer to the entry to be inserted at the
  258. ; tail of the list.
  259. ;
  260. ; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
  261. ; access to the list.
  262. ;
  263. ; Return Value:
  264. ;
  265. ; Pointer to entry that was at the tail of the list or NULL if the list
  266. ; was empty.
  267. ;
  268. ;--
  269. cPublicFastCall ExfInterlockedInsertTailList, 3
  270. cPublicFpo 1, 1
  271. ifndef NT_UP
  272. cPublicFpo 1, 2
  273. push esi
  274. mov esi, [esp+8] ; Address of spinlock
  275. endif
  276. pushfd
  277. Eiit10: cli
  278. ACQUIRE_SPINLOCK esi,<short Eiit20>
  279. mov eax, LsBlink[ecx] ; (eax)->prev entry in the list
  280. mov [edx]+LsFlink, ecx ; store next link in entry
  281. mov [edx]+LsBlink, eax ; store previous link in entry
  282. mov [ecx]+LsBlink, edx ; store next link in head
  283. mov [eax]+LsFlink, edx ; store previous link in next
  284. RELEASE_SPINLOCK esi
  285. popfd
  286. ifndef NT_UP
  287. pop esi
  288. endif
  289. xor eax, ecx ; return null if list was empty
  290. jz short Eiit15
  291. xor eax, ecx
  292. Eiit15: fstRET ExfInterlockedInsertTailList
  293. ifndef NT_UP
  294. Eiit20: popfd
  295. pushfd
  296. SPIN_ON_SPINLOCK esi, <short Eiit10>
  297. endif
  298. fstENDP ExfInterlockedInsertTailList
  299. page , 132
  300. subttl "Interlocked Remove Head List"
  301. ;++
  302. ;
  303. ; PLIST_ENTRY
  304. ; FASTCALL
  305. ; ExfInterlockedRemoveHeadList (
  306. ; IN PLIST_ENTRY ListHead,
  307. ; IN PKSPIN_LOCK Lock
  308. ; )
  309. ;
  310. ; Routine Description:
  311. ;
  312. ; This function removes an entry from the head of a doubly linked list
  313. ; so that access to the list is synchronized in a multiprocessor system.
  314. ; If there are no entries in the list, then a value of NULL is returned.
  315. ; Otherwise, the address of the entry that is removed is returned as the
  316. ; function value.
  317. ;
  318. ; N.B. The pages of data which this routine operates on MUST be
  319. ; present. No page fault is allowed in this routine.
  320. ;
  321. ; Arguments:
  322. ;
  323. ; (ecx) ListHead - Supplies a pointer to the head of the doubly linked
  324. ; list from which an entry is to be removed.
  325. ;
  326. ; (edx) Lock - Supplies a pointer to a spin lock to be used to synchronize
  327. ; access to the list.
  328. ;
  329. ; Return Value:
  330. ;
  331. ; The address of the entry removed from the list, or NULL if the list is
  332. ; empty.
  333. ;
  334. ;--
  335. cPublicFastCall ExfInterlockedRemoveHeadList , 2
  336. cPublicFpo 0, 1
  337. ifdef NT_UP
  338. ;
  339. ; UP version
  340. ;
  341. pushfd
  342. cli
  343. mov eax, [ecx]+LsFlink ; (eax)-> next entry
  344. cmp eax, ecx ; Is list empty?
  345. je short Eirh20 ; if e, list is empty, go Eirh20
  346. mov edx, [eax]+LsFlink ; (ecx)-> next entry(after deletion)
  347. mov [ecx]+LsFlink, edx ; store address of next in head
  348. mov [edx]+LsBlink, ecx ; store address of previous in next
  349. if DBG
  350. mov [eax]+LsFlink, 0baddd0ffh
  351. mov [eax]+LsBlink, 0baddd0ffh
  352. endif
  353. popfd ; restore flags including interrupts
  354. fstRET ExfInterlockedRemoveHeadList
  355. Eirh20: popfd
  356. xor eax,eax ; (eax) = null for empty list
  357. fstRET ExfInterlockedRemoveHeadList
  358. else
  359. ;
  360. ; MP version
  361. ;
  362. Eirh40: pushfd
  363. cli
  364. ACQUIRE_SPINLOCK edx, <short Eirh60>
  365. mov eax, [ecx]+LsFlink ; (eax)-> next entry
  366. cmp eax, ecx ; Is list empty?
  367. je short Eirh50 ; if e, list is empty, go Eirh50
  368. cPublicFpo 0,2
  369. push ebx
  370. mov ebx, [eax]+LsFlink ; (ecx)-> next entry(after deletion)
  371. mov [ecx]+LsFlink, ebx ; store address of next in head
  372. mov [ebx]+LsBlink, ecx ; store address of previous in next
  373. if DBG
  374. mov ebx, 0badd0ffh
  375. mov [eax]+LsFlink, ebx
  376. mov [eax]+LsBlink, ebx
  377. endif
  378. RELEASE_SPINLOCK edx
  379. cPublicFpo 0, 0
  380. pop ebx
  381. popfd ; restore flags including interrupts
  382. fstRET ExfInterlockedRemoveHeadList
  383. Eirh50: RELEASE_SPINLOCK edx
  384. popfd
  385. xor eax,eax ; (eax) = null for empty list
  386. fstRET ExfInterlockedRemoveHeadList
  387. cPublicFpo 0, 0
  388. Eirh60: popfd
  389. SPIN_ON_SPINLOCK edx, <Eirh40>
  390. fstRET ExfInterlockedRemoveHeadList
  391. endif ; nt_up
  392. fstENDP ExfInterlockedRemoveHeadList
  393. page , 132
  394. subttl "Interlocked Pop Entry List"
  395. ;++
  396. ;
  397. ; PSINGLE_LIST_ENTRY
  398. ; FASTCALL
  399. ; ExfInterlockedPopEntryList (
  400. ; IN PSINGLE_LIST_ENTRY ListHead,
  401. ; IN PKSPIN_LOCK Lock
  402. ; )
  403. ;
  404. ; Routine Description:
  405. ;
  406. ; This function removes an entry from the front of a singly linked list
  407. ; so that access to the list is synchronized in a multiprocessor system.
  408. ; If there are no entries in the list, then a value of NULL is returned.
  409. ; Otherwise, the address of the entry that is removed is returned as the
  410. ; function value.
  411. ;
  412. ; Arguments:
  413. ;
  414. ; (ecx) = ListHead - Supplies a pointer to the head of the singly linked
  415. ; list from which an entry is to be removed.
  416. ;
  417. ; (edx) = Lock - Supplies a pointer to a spin lock to be used to synchronize
  418. ; access to the list.
  419. ;
  420. ; Return Value:
  421. ;
  422. ; The address of the entry removed from the list, or NULL if the list is
  423. ; empty.
  424. ;
  425. ;--
  426. cPublicFastCall ExfInterlockedPopEntryList , 2
  427. ifdef NT_UP
  428. ;
  429. ; UP version
  430. ;
  431. cPublicFpo 0,1
  432. pushfd
  433. cli ; disable interrupts
  434. mov eax, [ecx] ; (eax)-> next entry
  435. or eax, eax ; Is it empty?
  436. je short Eipe05 ; if e, empty list, go Eipe05
  437. mov edx, [eax] ; (edx)->next entry (after deletion)
  438. mov [ecx], edx ; store address of next in head
  439. if DBG
  440. mov [eax], 0baddd0ffh
  441. endif
  442. cPublicFpo 0,0
  443. popfd ; restore flags including interrupts
  444. fstRET ExfInterlockedPopEntryList ; cReturn (eax)->removed entry
  445. Eipe05: popfd
  446. xor eax,eax
  447. fstRET ExfInterlockedPopEntryList ; cReturn (eax)=NULL
  448. else ; nt_up
  449. ;
  450. ; MP Version
  451. ;
  452. cPublicFpo 0,1
  453. Eipe10: pushfd
  454. cli ; disable interrupts
  455. ACQUIRE_SPINLOCK edx, <short Eipe30>
  456. mov eax, [ecx] ; (eax)-> next entry
  457. or eax, eax ; Is it empty?
  458. je short Eipe20 ; if e, empty list, go Eipe20
  459. cPublicFpo 0,2
  460. push edx ; Save SpinLock address
  461. mov edx, [eax] ; (edx)->next entry (after deletion)
  462. mov [ecx], edx ; store address of next in head
  463. pop edx ; Restore SpinLock address
  464. if DBG
  465. mov [eax], 0baddd0ffh
  466. endif
  467. RELEASE_SPINLOCK edx
  468. cPublicFpo 0,0
  469. popfd ; restore flags including interrupts
  470. fstRET ExfInterlockedPopEntryList
  471. Eipe20: RELEASE_SPINLOCK edx
  472. popfd
  473. xor eax,eax
  474. fstRET ExfInterlockedPopEntryList
  475. Eipe30: popfd
  476. SPIN_ON_SPINLOCK edx, Eipe10
  477. endif ; nt_up
  478. fstENDP ExfInterlockedPopEntryList
  479. page , 132
  480. subttl "Interlocked Push Entry List"
  481. ;++
  482. ;
  483. ; PSINGLE_LIST_ENTRY
  484. ; FASTCALL
  485. ; ExInterlockedPushEntryList (
  486. ; IN PSINGLE_LIST_ENTRY ListHead,
  487. ; IN PSINGLE_LIST_ENTRY ListEntry,
  488. ; IN PKSPIN_LOCK Lock
  489. ; )
  490. ;
  491. ; Routine Description:
  492. ;
  493. ; This function inserts an entry at the head of a singly linked list
  494. ; so that access to the list is synchronized in a multiprocessor system.
  495. ;
  496. ; Arguments:
  497. ;
  498. ; (ecx) ListHead - Supplies a pointer to the head of the singly linked
  499. ; list into which an entry is to be inserted.
  500. ;
  501. ; (edx) ListEntry - Supplies a pointer to the entry to be inserted at the
  502. ; head of the list.
  503. ;
  504. ; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
  505. ; access to the list.
  506. ;
  507. ; Return Value:
  508. ;
  509. ; Previous contents of ListHead. NULL implies list went from empty
  510. ; to not empty.
  511. ;
  512. ;--
  513. cPublicFastCall ExfInterlockedPushEntryList , 3
  514. ifdef NT_UP
  515. ;
  516. ; UP Version
  517. ;
  518. cPublicFpo 0,1
  519. pushfd
  520. cli
  521. mov eax, [ecx] ; (eax)-> next entry (return value also)
  522. mov [edx], eax ; store address of next in new entry
  523. mov [ecx], edx ; set address of next in head
  524. cPublicFpo 0,0
  525. popfd ; restore flags including interrupts
  526. fstRET ExfInterlockedPushEntryList
  527. else
  528. ;
  529. ; MP Version
  530. ;
  531. cPublicFpo 1,1
  532. pushfd
  533. push edx
  534. mov edx, [esp+12] ; (edx) = SpinLock
  535. Eipl10: cli
  536. ACQUIRE_SPINLOCK edx, <short Eipl20>
  537. pop edx ; (edx)-> Entry to be pushed
  538. mov eax, [ecx] ; (eax)-> next entry (return value also)
  539. mov [edx], eax ; store address of next in new entry
  540. mov [ecx], edx ; set address of next in head
  541. mov edx, [esp+8] ; (edx) = SpinLock
  542. RELEASE_SPINLOCK edx
  543. cPublicFpo 0,0
  544. popfd ; restore flags including interrupts
  545. fstRET ExfInterlockedPushEntryList
  546. cPublicFpo 1,2
  547. Eipl20: pop edx
  548. popfd ; Restore interrupt state
  549. pushfd
  550. push edx
  551. mov edx, [esp+12]
  552. SPIN_ON_SPINLOCK edx, <short Eipl10>
  553. endif
  554. fstENDP ExfInterlockedPushEntryList
  555. page , 132
  556. subttl "Interlocked i386 Increment Long"
  557. ;++
  558. ;
  559. ; INTERLOCKED_RESULT
  560. ; FASTCALL
  561. ; Exfi386InterlockedIncrementLong (
  562. ; IN PLONG Addend
  563. ; )
  564. ;
  565. ; Routine Description:
  566. ;
  567. ; This function atomically increments Addend, returning an ennumerated
  568. ; type which indicates what interesting transitions in the value of
  569. ; Addend occurred due the operation.
  570. ;
  571. ; See ExInterlockedIncrementLong. This function is the i386
  572. ; architectural specific version of ExInterlockedIncrementLong.
  573. ; No source directly calls this function, instead
  574. ; ExInterlockedIncrementLong is called and when built on x86 these
  575. ; calls are macroed to the i386 optimized version.
  576. ;
  577. ; Arguments:
  578. ;
  579. ; (ecx) Addend - Pointer to variable to increment.
  580. ;
  581. ; Return Value:
  582. ;
  583. ; An ennumerated type:
  584. ;
  585. ; ResultNegative if Addend is < 0 after increment.
  586. ; ResultZero if Addend is = 0 after increment.
  587. ; ResultPositive if Addend is > 0 after increment.
  588. ;
  589. ;--
  590. cPublicFastCall Exfi386InterlockedIncrementLong, 1
  591. cPublicFpo 0, 0
  592. ifdef NT_UP
  593. add dword ptr [ecx],1
  594. else
  595. lock add dword ptr [ecx],1
  596. endif
  597. lahf ; (ah) = flags
  598. and eax,EFLAG_SELECT ; clear all but sign and zero flags
  599. fstRET Exfi386InterlockedIncrementLong
  600. fstENDP Exfi386InterlockedIncrementLong
  601. page , 132
  602. subttl "Interlocked i386 Decrement Long"
  603. ;++
  604. ;
  605. ; INTERLOCKED_RESULT
  606. ; FASTCALL
  607. ; Exfi386InterlockedDecrementLong (
  608. ; IN PLONG Addend,
  609. ; IN PKSPIN_LOCK Lock
  610. ; )
  611. ;
  612. ; Routine Description:
  613. ;
  614. ; This function atomically decrements Addend, returning an ennumerated
  615. ; type which indicates what interesting transitions in the value of
  616. ; Addend occurred due the operation.
  617. ;
  618. ; See Exi386InterlockedDecrementLong. This function is the i386
  619. ; architectural specific version of ExInterlockedDecrementLong.
  620. ; No source directly calls this function, instead
  621. ; ExInterlockedDecrementLong is called and when built on x86 these
  622. ; calls are macroed to the i386 optimized version.
  623. ;
  624. ; Arguments:
  625. ;
  626. ; Addend (esp+4) - Pointer to variable to decrement.
  627. ;
  628. ; Lock (esp+8) - Spinlock used to implement atomicity.
  629. ; (not actually used on x86)
  630. ;
  631. ; Return Value:
  632. ;
  633. ; An ennumerated type:
  634. ;
  635. ; ResultNegative if Addend is < 0 after decrement.
  636. ; ResultZero if Addend is = 0 after decrement.
  637. ; ResultPositive if Addend is > 0 after decrement.
  638. ;
  639. ;--
  640. cPublicFastCall Exfi386InterlockedDecrementLong , 1
  641. cPublicFpo 0, 0
  642. ifdef NT_UP
  643. sub dword ptr [ecx], 1
  644. else
  645. lock sub dword ptr [ecx], 1
  646. endif
  647. lahf ; (ah) = flags
  648. and eax, EFLAG_SELECT ; clear all but sign and zero flags
  649. fstRET Exfi386InterlockedDecrementLong
  650. fstENDP Exfi386InterlockedDecrementLong
  651. page , 132
  652. subttl "Interlocked i386 Exchange Ulong"
  653. ;++
  654. ;
  655. ; ULONG
  656. ; FASTCALL
  657. ; Exfi386InterlockedExchangeUlong (
  658. ; IN PULONG Target,
  659. ; IN ULONG Value
  660. ; )
  661. ;
  662. ; Routine Description:
  663. ;
  664. ; This function atomically exchanges the Target and Value, returning
  665. ; the prior contents of Target
  666. ;
  667. ; See Exi386InterlockedExchangeUlong. This function is the i386
  668. ; architectural specific version of ExInterlockedDecrementLong.
  669. ; No source directly calls this function, instead
  670. ; ExInterlockedDecrementLong is called and when built on x86 these
  671. ; calls are macroed to the i386 optimized version.
  672. ;
  673. ; Arguments:
  674. ;
  675. ; (ecx) = Source - Address of ULONG to exchange
  676. ; (edx) = Value - New value of ULONG
  677. ;
  678. ; Return Value:
  679. ;
  680. ; The prior value of Source
  681. ;--
  682. cPublicFastCall Exfi386InterlockedExchangeUlong, 2
  683. cPublicFpo 0,0
  684. .486
  685. ifndef NT_UP
  686. xchg [ecx], edx ; make the exchange
  687. mov eax, edx
  688. else
  689. mov eax, [ecx] ; get comperand value
  690. Ixchg: cmpxchg [ecx], edx ; compare and swap
  691. jnz Ixchg ; if nz, exchange failed
  692. endif
  693. .386
  694. fstRET Exfi386InterlockedExchangeUlong
  695. fstENDP Exfi386InterlockedExchangeUlong
  696. ;++
  697. ;
  698. ; LONG
  699. ; InterlockedIncrement(
  700. ; IN PLONG Addend
  701. ; )
  702. ;
  703. ; Routine Description:
  704. ;
  705. ; This function performs an interlocked add of one to the addend variable.
  706. ;
  707. ; No checking is done for overflow.
  708. ;
  709. ; Arguments:
  710. ;
  711. ; Addend (ecx) - Supplies a pointer to a variable whose value is to be
  712. ; incremented by one.
  713. ;
  714. ; Return Value:
  715. ;
  716. ; (eax) - The incremented value.
  717. ;
  718. ;--
  719. cPublicFastCall __InterlockedIncrement,1
  720. cPublicFpo 0,0
  721. mov eax, 1 ; set increment value
  722. .486
  723. ifndef NT_UP
  724. lock xadd [ecx], eax ; interlocked increment
  725. else
  726. xadd [ecx], eax ; interlocked increment
  727. endif
  728. .386p
  729. inc eax ; adjust return value
  730. fstRET __InterlockedIncrement
  731. fstENDP __InterlockedIncrement
  732. page , 132
  733. subttl "InterlockedDecrment"
  734. ;++
  735. ;
  736. ; LONG
  737. ; InterlockedDecrement(
  738. ; IN PLONG Addend
  739. ; )
  740. ;
  741. ; Routine Description:
  742. ;
  743. ; This function performs an interlocked add of -1 to the addend variable.
  744. ;
  745. ; No checking is done for overflow
  746. ;
  747. ; Arguments:
  748. ;
  749. ; Addend (ecx) - Supplies a pointer to a variable whose value is to be
  750. ; decremented by one.
  751. ;
  752. ; Return Value:
  753. ;
  754. ; (eax) - The decremented value.
  755. ;
  756. ;--
  757. cPublicFastCall __InterlockedDecrement,1
  758. cPublicFpo 0,0
  759. mov eax, -1 ; set decrment value
  760. .486
  761. ifndef NT_UP
  762. lock xadd [ecx], eax ; interlocked decrement
  763. else
  764. xadd [ecx], eax ; interlocked decrement
  765. endif
  766. .386
  767. dec eax ; adjust return value
  768. fstRET __InterlockedDecrement
  769. fstENDP __InterlockedDecrement
  770. page , 132
  771. subttl "Interlocked Compare Exchange"
  772. ;++
  773. ;
  774. ; PVOID
  775. ; FASTCALL
  776. ; InterlockedCompareExchange (
  777. ; IN OUT PVOID *Destination,
  778. ; IN PVOID Exchange,
  779. ; IN PVOID Comperand
  780. ; )
  781. ;
  782. ; Routine Description:
  783. ;
  784. ; This function performs an interlocked compare of the destination
  785. ; value with the comperand value. If the destination value is equal
  786. ; to the comperand value, then the exchange value is stored in the
  787. ; destination. Otherwise, no operation is performed.
  788. ;
  789. ; Arguments:
  790. ;
  791. ; (ecx) Destination - Supplies a pointer to destination value.
  792. ;
  793. ; (edx) Exchange - Supplies the exchange value.
  794. ;
  795. ; [esp + 4] Comperand - Supplies the comperand value.
  796. ;
  797. ; Return Value:
  798. ;
  799. ; The initial destination value is returned as the function value.
  800. ;
  801. ;--
  802. cPublicFastCall __InterlockedCompareExchange, 3
  803. cPublicFpo 0,0
  804. mov eax, [esp + 4] ; set comperand value
  805. .486
  806. ifndef NT_UP
  807. lock cmpxchg [ecx], edx ; compare and exchange
  808. else
  809. cmpxchg [ecx], edx ; compare and exchange
  810. endif
  811. .386
  812. fstRET __InterlockedCompareExchange
  813. fstENDP __InterlockedCompareExchange
  814. subttl "Interlocked Compare Exchange 64-bit - without lock"
  815. ;++
  816. ;
  817. ; LONGLONG
  818. ; FASTCALL
  819. ; ExfInterlockedCompareExchange64 (
  820. ; IN OUT PLONGLONG Destination,
  821. ; IN PLONGLONG Exchange,
  822. ; IN PLONGLONG Comperand
  823. ; )
  824. ;
  825. ; Routine Description:
  826. ;
  827. ; This function performs a compare and exchange of 64-bits.
  828. ;
  829. ; Arguments:
  830. ;
  831. ; (ecx) Destination - Supplies a pointer to the destination variable.
  832. ;
  833. ; (edx) Exchange - Supplies a pointer to the exchange value.
  834. ;
  835. ; (esp+4) Comperand - Supplies a pointer to the comperand value.
  836. ;
  837. ; Return Value:
  838. ;
  839. ; The current destination value is returned as the function value.
  840. ;
  841. ;--
  842. cPublicFastCall ExfInterlockedCompareExchange64, 3
  843. cPublicFpo 0,2
  844. ;
  845. ; Save nonvolatile registers and read the exchange and comperand values.
  846. ;
  847. push ebx ; save nonvolatile registers
  848. push ebp ;
  849. mov ebp, ecx ; set destination address
  850. mov ebx, [edx] ; get exchange value
  851. mov ecx, [edx] + 4 ;
  852. mov edx, [esp] + 12 ; get comperand address
  853. mov eax, [edx] ; get comperand value
  854. mov edx, [edx] + 4 ;
  855. .586
  856. ifndef NT_UP
  857. lock cmpxchg8b qword ptr [ebp] ; compare and exchange
  858. else
  859. cmpxchg8b qword ptr[ebp] ; compare and exchange
  860. endif
  861. .386
  862. ;
  863. ; Restore nonvolatile registers and return result in edx:eax.
  864. ;
  865. cPublicFpo 0,0
  866. pop ebp ; restore nonvolatile registers
  867. pop ebx ;
  868. fstRET ExfInterlockedCompareExchange64
  869. fstENDP ExfInterlockedCompareExchange64
  870. page , 132
  871. subttl "Interlocked Compare Exchange 64-bits - with lock"
  872. ;++
  873. ;
  874. ; LONGLONG
  875. ; FASTCALL
  876. ; ExInterlockedCompareExchange64 (
  877. ; IN PLONGLONG Destination,
  878. ; IN PLONGLONG Exchange,
  879. ; IN PLONGLONG Comperand,
  880. ; IN PKSPIN_LOCK Lock
  881. ; )
  882. ;
  883. ; Routine Description:
  884. ;
  885. ; This function performs a compare and exchange of 64-bits.
  886. ;
  887. ; N.B. This routine is provided for backward compatibility only. The
  888. ; lock address is not used.
  889. ;
  890. ; Arguments:
  891. ;
  892. ; (ecx) Destination - Supplies a pointer to the destination variable.
  893. ;
  894. ; (edx) Exchange - Supplies a pointer to the exchange value.
  895. ;
  896. ; (esp+4) Comperand - Supplies a pointer to the comperand value.
  897. ;
  898. ; (esp+4) Lock - Supplies a pointer to a spin lock to use if the cmpxchg8b
  899. ; instruction is not available on the host system.
  900. ;
  901. ; Return Value:
  902. ;
  903. ; The current destination value is returned as the function value.
  904. ;
  905. ;--
  906. cPublicFastCall ExInterlockedCompareExchange64, 4
  907. cPublicFpo 0,2
  908. ;
  909. ; Save nonvolatile registers and read the exchange and comperand values.
  910. ;
  911. push ebx ; save nonvolatile registers
  912. push ebp ;
  913. mov ebp, ecx ; set destination address
  914. mov ebx, [edx] ; get exchange value
  915. mov ecx, [edx] + 4 ;
  916. mov edx, [esp] + 12 ; get comperand address
  917. mov eax, [edx] ; get comperand value
  918. mov edx, [edx] + 4 ;
  919. .586
  920. ifndef NT_UP
  921. lock cmpxchg8b qword ptr [ebp] ; compare and exchange
  922. else
  923. cmpxchg8b qword ptr[ebp] ; compare and exchange
  924. endif
  925. .386
  926. ;
  927. ; Restore nonvolatile registers and return result in edx:eax.
  928. ;
  929. cPublicFpo 0,0
  930. pop ebp ; restore nonvolatile registers
  931. pop ebx ;
  932. fstRET ExInterlockedCompareExchange64
  933. fstENDP ExInterlockedCompareExchange64
  934. subttl "Interlocked Exchange Add"
  935. ;++
  936. ;
  937. ; LONG
  938. ; FASTCALL
  939. ; InterlockedExchangeAdd (
  940. ; IN OUT PLONG Addend,
  941. ; IN LONG Increment
  942. ; )
  943. ;
  944. ; Routine Description:
  945. ;
  946. ; This function performs an interlocked add of an increment value to an
  947. ; addend variable of type unsinged long. The initial value of the addend
  948. ; variable is returned as the function value.
  949. ;
  950. ; It is NOT possible to mix ExInterlockedDecrementLong and
  951. ; ExInterlockedIncrementong with ExInterlockedAddUlong.
  952. ;
  953. ;
  954. ; Arguments:
  955. ;
  956. ; (ecx) Addend - Supplies a pointer to a variable whose value is to be
  957. ; adjusted by the increment value.
  958. ;
  959. ; (edx) Increment - Supplies the increment value to be added to the
  960. ; addend variable.
  961. ;
  962. ; Return Value:
  963. ;
  964. ; The initial value of the addend variable.
  965. ;
  966. ;--
  967. cPublicFastCall __InterlockedExchangeAdd, 2
  968. cPublicFpo 0,0
  969. .486
  970. ifndef NT_UP
  971. lock xadd [ecx], edx ; exchange add
  972. else
  973. xadd [ecx], edx ; exchange add
  974. endif
  975. .386
  976. mov eax, edx ; set initial value
  977. fstRET __InterlockedExchangeAdd
  978. fstENDP __InterlockedExchangeAdd
  979. _TEXT$00 ends
  980. end