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.

394 lines
11 KiB

  1. title "Critical Section Support"
  2. ;++
  3. ;
  4. ; Copyright (c) 1991 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; critsect.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements functions to support user mode critical sections.
  13. ;
  14. ; Author:
  15. ;
  16. ; Bryan M. Willman (bryanwi) 2-Oct-91
  17. ;
  18. ; Environment:
  19. ;
  20. ; Any mode.
  21. ;
  22. ; Revision History:
  23. ;
  24. ;--
  25. .486p
  26. .xlist
  27. include ks386.inc
  28. include callconv.inc ; calling convention macros
  29. include mac386.inc
  30. .list
  31. _DATA SEGMENT DWORD PUBLIC 'DATA'
  32. public _LdrpLockPrefixTable
  33. _LdrpLockPrefixTable label dword
  34. dd offset FLAT:Lock1
  35. dd offset FLAT:Lock2
  36. dd offset FLAT:Lock3
  37. dd offset FLAT:Lock4
  38. dd offset FLAT:Lock5
  39. dd offset FLAT:Lock6
  40. dd offset FLAT:Lock7
  41. dd 0
  42. _DATA ENDS
  43. _TEXT SEGMENT PARA PUBLIC 'CODE'
  44. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  45. EXTRNP _RtlpWaitForCriticalSection,1
  46. EXTRNP _RtlpUnWaitCriticalSection,1
  47. if DEVL
  48. EXTRNP _RtlpNotOwnerCriticalSection,1
  49. endif
  50. if DBG
  51. EXTRNP _RtlpCriticalSectionIsOwned,1
  52. endif
  53. CriticalSection equ [esp + 4]
  54. page , 132
  55. subttl "RtlEnterCriticalSection"
  56. ;++
  57. ;
  58. ; NTSTATUS
  59. ; RtlEnterCriticalSection(
  60. ; IN PRTL_CRITICAL_SECTION CriticalSection
  61. ; )
  62. ;
  63. ; Routine Description:
  64. ;
  65. ; This function enters a critical section.
  66. ;
  67. ; Arguments:
  68. ;
  69. ; CriticalSection - supplies a pointer to a critical section.
  70. ;
  71. ; Return Value:
  72. ;
  73. ; STATUS_SUCCESS or raises an exception if an error occured.
  74. ;
  75. ;--
  76. align 16
  77. cPublicProc _RtlEnterCriticalSection,1
  78. cPublicFpo 1,0
  79. mov ecx,fs:PcTeb ; get current TEB address
  80. mov edx,CriticalSection ; get address of critical section
  81. cmp CsSpinCount[edx],0 ; check if spin count is zero
  82. jne short Ent40 ; if ne, spin count specified
  83. ;
  84. ; Attempt to acquire critical section.
  85. ;
  86. Lock1: ;
  87. lock inc dword ptr CsLockCount[edx] ; increment lock count
  88. jnz short Ent20 ; if nz, already owned
  89. ;
  90. ; Set critical section owner and initialize recursion count.
  91. ;
  92. Ent10:
  93. if DBG
  94. cmp CsOwningThread[edx],0
  95. je @F
  96. stdCall _RtlpCriticalSectionIsOwned, <edx>
  97. mov ecx,fs:PcTeb ; get current TEB address
  98. mov edx,CriticalSection ; get address of critical section
  99. @@:
  100. endif ; DBG
  101. mov eax,TbClientId + 4[ecx] ; get current client ID
  102. mov CsOwningThread[edx],eax ; set critical section owner
  103. mov dword ptr CsRecursionCount[edx],1 ; set recursion count
  104. if DBG
  105. inc dword ptr TbCountOfOwnedCriticalSections[ecx] ; increment owned count
  106. mov eax,CsDebugInfo[edx] ; get debug information address
  107. inc dword ptr CsEntryCount[eax] ; increment entry count
  108. endif ; DBG
  109. xor eax,eax ; set success status
  110. stdRET _RtlEnterCriticalSection
  111. ;
  112. ; The critical section is already owned, but may be owned by the current thread.
  113. ;
  114. align 16
  115. Ent20: mov eax,TbClientId + 4[ecx] ; get current client ID
  116. cmp CsOwningThread[edx],eax ; check if current thread is owner
  117. jne short Ent30 ; if ne, current thread not owner
  118. inc dword ptr CsRecursionCount[edx] ; increment recursion count
  119. if DBG
  120. mov eax,CsDebugInfo[edx] ; get debug information address
  121. inc dword ptr CsEntryCount[eax] ; increment entry count
  122. endif ; DBG
  123. xor eax,eax ; set success status
  124. stdRET _RtlEnterCriticalSection
  125. ;
  126. ; The critcal section is owned by another thread and the current thread must
  127. ; wait for ownership.
  128. ;
  129. Ent30: stdCall _RtlpWaitForCriticalSection, <edx> ; wait for ownership
  130. mov ecx,fs:PcTeb ; get current TEB address
  131. mov edx,CriticalSection ; get address of critical section
  132. jmp Ent10 ; set owner and recursion count
  133. ;
  134. ; A nonzero spin count is specified.
  135. ;
  136. align 16
  137. Ent40: mov eax,TbClientId + 4[ecx] ; get current client ID
  138. cmp CsOwningThread[edx],eax ; check if current thread is owner
  139. jne short Ent50 ; if ne, current thread not owner
  140. ;
  141. ; The critical section is owned by the current thread. Increment the lock
  142. ; count and the recursion count.
  143. ;
  144. Lock6: ;
  145. lock inc dword ptr CsLockCount[edx] ; increment lock count
  146. inc dword ptr CsRecursionCount[edx] ; increment recursion count
  147. if DBG
  148. mov eax,CsDebugInfo[edx] ; get debug information address
  149. inc dword ptr CsEntryCount[eax] ; increment entry count
  150. endif ; DBG
  151. xor eax,eax ; set success status
  152. stdRET _RtlEnterCriticalSection
  153. ;
  154. ; A nonzero spin count is specified and the current thread is not the owner.
  155. ;
  156. align 16
  157. Ent50: push CsSpinCount[edx] ; get spin count value
  158. Ent60: mov eax,-1 ; set comparand value
  159. mov ecx,0 ; set exchange value
  160. Lock7:
  161. lock cmpxchg dword ptr CsLockCount[edx],ecx ; attempt to acquire critical section
  162. jnz short Ent70 ; if nz, critical section not acquired
  163. ;
  164. ; The critical section has been acquired. Set the owning thread and the initial
  165. ; recursion count.
  166. ;
  167. add esp,4 ; remove spin count from stack
  168. mov ecx,fs:PcTeb ; get current TEB address
  169. mov eax,TbClientId + 4[ecx] ; get current client ID
  170. mov CsOwningThread[edx],eax ; set critical section owner
  171. mov dword ptr CsRecursionCount[edx],1 ; set recursion count
  172. if DBG
  173. inc dword ptr TbCountOfOwnedCriticalSections[ecx] ; increment owned count
  174. mov eax,CsDebugInfo[edx] ; get debug information address
  175. inc dword ptr CsEntryCount[eax] ; increment entry count
  176. endif ; DBG
  177. xor eax,eax ; set success status
  178. stdRET _RtlEnterCriticalSection
  179. ;
  180. ; The critical section is currently owned. Spin until it is either unowned
  181. ; or the spin count has reached zero.
  182. ;
  183. ; If waiters are present, don't spin on the lock since we will never see it go free
  184. ;
  185. Ent70: cmp CsLockCount[edx],1 ; check if waiters are present,
  186. jge short Ent76 ; if ge 1, then do not spin
  187. Ent75: YIELD
  188. cmp CsLockCount[edx],-1 ; check if lock is owned
  189. je short Ent60 ; if e, lock is not owned
  190. dec dword ptr [esp] ; decrement spin count
  191. jnz short Ent75 ; if nz, continue spinning
  192. Ent76: add esp,4 ; remove spin count from stack
  193. mov ecx,fs:PcTeb ; get current TEB address
  194. jmp Lock1 ;
  195. stdENDP _RtlEnterCriticalSection
  196. page , 132
  197. subttl "RtlLeaveCriticalSection"
  198. ;++
  199. ;
  200. ; NTSTATUS
  201. ; RtlLeaveCriticalSection(
  202. ; IN PRTL_CRITICAL_SECTION CriticalSection
  203. ; )
  204. ;
  205. ; Routine Description:
  206. ;
  207. ; This function leaves a critical section.
  208. ;
  209. ; Arguments:
  210. ;
  211. ; CriticalSection - supplies a pointer to a critical section.
  212. ;
  213. ; Return Value:
  214. ;
  215. ; STATUS_SUCCESS or raises an exception if an error occured.
  216. ;
  217. ;--
  218. align 16
  219. cPublicProc _RtlLeaveCriticalSection,1
  220. cPublicFpo 1,0
  221. mov edx,CriticalSection
  222. if DBG
  223. mov ecx,fs:PcTeb ; (ecx) == NtCurrentTeb()
  224. mov eax,TbClientId+4[ecx] ; (eax) == NtCurrentTeb()->ClientId.UniqueThread
  225. cmp eax,CsOwningThread[edx]
  226. je @F
  227. stdCall _RtlpNotOwnerCriticalSection, <edx>
  228. mov eax,STATUS_INVALID_OWNER
  229. stdRET _RtlLeaveCriticalSection
  230. @@:
  231. endif ; DBG
  232. xor eax,eax ; Assume STATUS_SUCCESS
  233. dec dword ptr CsRecursionCount[edx]
  234. jnz leave_recurs ; skip if only leaving recursion
  235. mov CsOwningThread[edx],eax ; clear owning thread id
  236. if DBG
  237. mov ecx,fs:PcTeb ; (ecx) == NtCurrentTeb()
  238. dec dword ptr TbCountOfOwnedCriticalSections[ecx]
  239. endif ; DBG
  240. Lock2:
  241. lock dec dword ptr CsLockCount[edx] ; interlocked dec of
  242. ; ... CriticalSection->LockCount
  243. jge @F
  244. stdRET _RtlLeaveCriticalSection
  245. @@:
  246. stdCall _RtlpUnWaitCriticalSection, <edx>
  247. xor eax,eax ; return STATUS_SUCCESS
  248. stdRET _RtlLeaveCriticalSection
  249. align 16
  250. leave_recurs:
  251. Lock3:
  252. lock dec dword ptr CsLockCount[edx] ; interlocked dec of
  253. ; ... CriticalSection->LockCount
  254. stdRET _RtlLeaveCriticalSection
  255. _RtlLeaveCriticalSection endp
  256. page ,132
  257. subttl "RtlTryEnterCriticalSection"
  258. ;++
  259. ;
  260. ; BOOL
  261. ; RtlTryEnterCriticalSection(
  262. ; IN PRTL_CRITICAL_SECTION CriticalSection
  263. ; )
  264. ;
  265. ; Routine Description:
  266. ;
  267. ; This function attempts to enter a critical section without blocking.
  268. ;
  269. ; Arguments:
  270. ;
  271. ; CriticalSection (a0) - Supplies a pointer to a critical section.
  272. ;
  273. ; Return Value:
  274. ;
  275. ; If the critical section was successfully entered, then a value of TRUE
  276. ; is returned as the function value. Otherwise, a value of FALSE is returned.
  277. ;
  278. ;--
  279. CriticalSection equ [esp + 4]
  280. cPublicProc _RtlTryEnterCriticalSection,1
  281. cPublicFpo 1,0
  282. mov ecx,CriticalSection ; interlocked inc of
  283. mov eax, -1 ; set value to compare against
  284. mov edx, 0 ; set value to set
  285. Lock4:
  286. lock cmpxchg dword ptr CsLockCount[ecx],edx ; Attempt to acquire critsect
  287. jnz short tec10 ; if nz, critsect already owned
  288. mov eax,fs:TbClientId+4 ; (eax) == NtCurrentTeb()->ClientId.UniqueThread
  289. mov CsOwningThread[ecx],eax
  290. mov dword ptr CsRecursionCount[ecx],1
  291. if DBG
  292. mov eax,fs:PcTeb ; (ecx) == NtCurrentTeb()
  293. inc dword ptr TbCountOfOwnedCriticalSections[eax]
  294. endif ; DBG
  295. mov eax, 1 ; set successful status
  296. stdRET _RtlTryEnterCriticalSection
  297. tec10:
  298. ;
  299. ; The critical section is already owned. If it is owned by another thread,
  300. ; return FALSE immediately. If it is owned by this thread, we must increment
  301. ; the lock count here.
  302. ;
  303. mov eax, fs:TbClientId+4 ; (eax) == NtCurrentTeb()->ClientId.UniqueThread
  304. cmp CsOwningThread[ecx], eax
  305. jz tec20 ; if eq, this thread is already the owner
  306. xor eax, eax ; set failure status
  307. YIELD
  308. stdRET _RtlTryEnterCriticalSection
  309. tec20:
  310. ;
  311. ; This thread is already the owner of the critical section. Perform an atomic
  312. ; increment of the LockCount and a normal increment of the RecursionCount and
  313. ; return success.
  314. ;
  315. Lock5:
  316. lock inc dword ptr CsLockCount[ecx]
  317. inc dword ptr CsRecursionCount[ecx]
  318. mov eax, 1
  319. stdRET _RtlTryEnterCriticalSection
  320. stdENDP _RtlTryEnterCriticalSection
  321. _TEXT ends
  322. end