166 lines
3.6 KiB
NASM
166 lines
3.6 KiB
NASM
if NT_INST
|
|
else
|
|
TITLE "Spin Locks"
|
|
;++
|
|
;
|
|
; Copyright (c) 1989 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; spindbg.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; Author:
|
|
;
|
|
; Bryan Willman (bryanwi) 13 Dec 89
|
|
;
|
|
; Environment:
|
|
;
|
|
; Kernel mode only.
|
|
;
|
|
; Revision History:
|
|
;
|
|
;--
|
|
|
|
PAGE
|
|
|
|
.386p
|
|
|
|
include ks386.inc
|
|
include callconv.inc ; calling convention macros
|
|
include mac386.inc
|
|
|
|
|
|
if DBG
|
|
EXTRNP _KeBugCheckEx,5
|
|
EXTRNP _KeGetCurrentIrql,0,IMPORT
|
|
ifdef DBGMP
|
|
EXTRNP _KiPollDebugger,0
|
|
endif
|
|
extrn _KeTickCount:DWORD
|
|
extrn _KiSpinlockTimeout:DWORD
|
|
endif
|
|
|
|
|
|
_TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; Kii386SpinOnSpinLock (
|
|
; IN PKSPIN_LOCK SpinLock
|
|
; IN ULONG Flag
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function is called on a debug build to spin on a spinlock.
|
|
; It is invoked by the DEBUG version of SPIN_ON_SPINLOCK macro.
|
|
;
|
|
; Warning:
|
|
;
|
|
; Not called with C calling conventions
|
|
; Does not destroy any register
|
|
;
|
|
;--
|
|
|
|
cPublicProc Kii386SpinOnSpinLock,2
|
|
|
|
if DBG
|
|
cPublicFpo 2,2
|
|
push eax
|
|
push ebx
|
|
|
|
mov eax, [esp+12] ; (eax) = LockAddress
|
|
|
|
mov ebx, PCR[PcPrcbData.PbCurrentThread]
|
|
or ebx, 1 ; or on busy bit
|
|
cmp ebx, [eax] ; current thread the owner?
|
|
je short ssl_sameid ; Yes, go abort
|
|
|
|
ssl_10:
|
|
mov ebx, _KeTickCount ; Current time
|
|
add ebx, _KiSpinlockTimeout ; wait n ticks
|
|
|
|
ifdef DBGMP
|
|
test byte ptr [esp+16], 2 ; poll debugger while waiting?
|
|
jnz short ssl_30
|
|
endif
|
|
|
|
;
|
|
; Spin while watching KeTickCount
|
|
;
|
|
|
|
ssl_20: YIELD
|
|
cmp _KeTickCount, ebx ; check current time
|
|
jnc short ssl_timeout ; NC, too many ticks have gone by
|
|
|
|
test dword ptr [eax], 1
|
|
jnz short ssl_20
|
|
|
|
ssl_exit:
|
|
pop ebx ; Spinlock is not busy, return
|
|
pop eax
|
|
stdRET Kii386SpinOnSpinLock
|
|
|
|
ifdef DBGMP
|
|
;
|
|
; Spin while watching KeTickCount & poll debugger
|
|
;
|
|
|
|
ssl_30: YIELD
|
|
cmp _KeTickCount, ebx ; check current time
|
|
jnc short ssl_timeout ; overflowed
|
|
|
|
stdCall _KiPollDebugger
|
|
|
|
test dword ptr [eax], 1
|
|
jnz short ssl_30
|
|
|
|
pop ebx ; Spinlock is not busy, return
|
|
pop eax
|
|
stdRET Kii386SpinOnSpinLock
|
|
endif
|
|
|
|
;
|
|
; Out of line expection conditions
|
|
;
|
|
|
|
ssl_sameid:
|
|
test byte ptr [esp+16], 1 ; ID check enabled?
|
|
jz short ssl_10 ; no, continue
|
|
|
|
; recursed on lock, abort
|
|
|
|
stdCall _KeBugCheckEx,<SPIN_LOCK_ALREADY_OWNED,eax,0,0,0>
|
|
|
|
ssl_timeout:
|
|
test byte ptr [esp+16], 4 ; Timeout check enabled?
|
|
jz short ssl_10 ; no, continue
|
|
|
|
stdCall _KeGetCurrentIrql ; Check to see what level we're spinning at
|
|
cmp al, DISPATCH_LEVEL
|
|
mov eax, [esp+12] ; restore eax
|
|
jc short ssl_10 ; if < dispatch_level, don't timeout
|
|
|
|
test dword ptr [eax], 1 ; Check to see if spinlock was freed
|
|
jz short ssl_exit
|
|
|
|
public SpinLockSpinningForTooLong
|
|
SpinLockSpinningForTooLong:
|
|
|
|
int 3 ; Stop here
|
|
jmp short ssl_10 ; re-wait
|
|
|
|
else ; DBG
|
|
stdRET Kii386SpinOnSpinLock
|
|
endif
|
|
stdENDP Kii386SpinOnSpinLock,2
|
|
|
|
_TEXT$00 ends
|
|
|
|
endif ; NT_INST
|
|
end
|