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.

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