Windows2000/private/ntos/ex/i386/intrlfst.asm
2020-09-30 17:12:32 +02:00

1711 lines
44 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title "Interlocked Support"
; Copyright (c) 1989 Microsoft Corporation
; Module Name:
; intrlfst.asm
; Abstract:
; This module implements functions to support interlocked operations.
; Interlocked operations can only operate on nonpaged data.
; This module implements the fast call version of the interlocked
; fuctions.
; Author:
; Ken Reneris (kenr) 5-May-1994
; Environment:
; Any mode.
; Revision History:
.386p
.xlist
include ks386.inc
include callconv.inc ; calling convention macros
include mac386.inc
.list
extrn _Ki486CompatibilityLock:DWORD
_TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
; General Notes on Interlocked Procedures:
; These procedures assume that neither their code, nor any of
; the data they touch, will cause a page fault.
; They use spinlocks to achieve MP atomicity, iff it's an MP machine.
; (The spinlock macros generate zilch if NT_UP = 1, and
; we if out some aux code here as well.)
; They turn off interrupts so that they can be used for synchronization
; between ISRs and driver code. Flags are preserved so they can
; be called in special code (Like IPC interrupt handlers) that
; may have interrupts off.
;; align 512
page ,132
subttl "ExInterlockedAddLargeStatistic"
; VOID
; FASTCALL
; ExInterlockedAddLargeStatistic (
; IN PLARGE_INTEGER Addend,
; IN ULONG Increment
; )
; Routine Description:
; This function performs an interlocked add of an increment value to an
; addend variable of type unsigned large integer.
; Arguments:
; (ecx) Addend - Supplies a pointer to the variable whose value is
; adjusted by the increment value.
; (edx) Increment - Supplies the increment value that is added to the
; addend variable.
; Return Value:
; None.
cPublicFastCall ExInterlockedAddLargeStatistic, 2
cPublicFpo 0,0
ifdef NT_UP
add dword ptr [ecx], edx ; add low part of large statistic
adc dword ptr [ecx+4], 0 ; add carry to high part
else
lock add dword ptr [ecx], edx ; add low part of large statistic
jc short Eils10 ; if c, add generated a carry
fstRET ExInterlockedAddLargeStatistic ; return
Eils10: lock adc dword ptr [ecx+4], 0 ; add carry to high part
endif
fstRET ExInterlockedAddLargeStatistic ; return
fstENDP ExInterlockedAddLargeStatistic
page , 132
subttl "Interlocked Add Unsigned Long"
; ULONG
; FASTCALL
; ExfInterlockedAddUlong (
; IN PULONG Addend,
; IN ULONG Increment,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function performs an interlocked add of an increment value to an
; addend variable of type unsinged long. The initial value of the addend
; variable is returned as the function value.
; It is NOT possible to mix ExInterlockedDecrementLong and
; ExInterlockedIncrementong with ExInterlockedAddUlong.
; Arguments:
; (ecx) Addend - Supplies a pointer to a variable whose value is to be
; adjusted by the increment value.
; (edx) Increment - Supplies the increment value to be added to the
; addend variable.
; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the addend variable.
; Return Value:
; The initial value of the addend variable.
cPublicFastCall ExfInterlockedAddUlong, 3
cPublicFpo 1, 1
ifdef NT_UP
; UP version of ExInterlockedAddUlong
pushfd
cli ; disable interrupts
mov eax, [ecx] ; (eax)= initial addend value
add [ecx], edx ; [ecx]=adjusted value
popfd ; restore flags including ints
fstRET ExfInterlockedAddUlong
else
; MP version of ExInterlockedAddUlong
pushfd
mov eax, [esp+8] ; (eax) = SpinLock
Eial10: cli ; disable interrupts
ACQUIRE_SPINLOCK eax, <short Eial20>
mov eax, [ecx] ; (eax)=initial addend value
add [ecx], edx ; [ecx]=adjusted value
mov edx, [esp+8] ; (edx) = SpinLock
RELEASE_SPINLOCK edx
popfd
fstRET ExfInterlockedAddUlong
Eial20: popfd
pushfd
SPIN_ON_SPINLOCK eax, <short Eial10>
endif
fstENDP ExfInterlockedAddUlong
page , 132
subttl "Interlocked Insert Head List"
; PLIST_ENTRY
; ExfInterlockedInsertHeadList (
; IN PLIST_ENTRY ListHead,
; IN PLIST_ENTRY ListEntry,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function inserts an entry at the head of a doubly linked list
; so that access to the list is synchronized in a multiprocessor system.
; N.B. The pages of data which this routine operates on MUST be
; present. No page fault is allowed in this routine.
; Arguments:
; (ecx) = ListHead - Supplies a pointer to the head of the doubly linked
; list into which an entry is to be inserted.
; (edx) = ListEntry - Supplies a pointer to the entry to be inserted at the
; head of the list.
; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; Pointer to entry that was at the head of the list or NULL if the list
; was empty.
cPublicFastCall ExfInterlockedInsertHeadList , 3
cPublicFpo 1, 1
ifndef NT_UP
cPublicFpo 1, 2
push esi
mov esi, [esp+8] ; Address of spinlock
endif
pushfd
Eiih10: cli
ACQUIRE_SPINLOCK esi,<short Eiih20>
mov eax, LsFlink[ecx] ; (eax)->next entry in the list
mov [edx]+LsFlink, eax ; store next link in entry
mov [edx]+LsBlink, ecx ; store previous link in entry
mov [ecx]+LsFlink, edx ; store next link in head
mov [eax]+LsBlink, edx ; store previous link in next
RELEASE_SPINLOCK esi
popfd
ifndef NT_UP
pop esi
endif
xor eax, ecx ; return null if list was empty
jz short Eiih15
xor eax, ecx
Eiih15: fstRET ExfInterlockedInsertHeadList
ifndef NT_UP
Eiih20: popfd
pushfd
SPIN_ON_SPINLOCK esi, <short Eiih10>
endif
fstENDP ExfInterlockedInsertHeadList
page , 132
subttl "Interlocked Insert Tail List"
; PLIST_ENTRY
; FASTCALL
; ExfInterlockedInsertTailList (
; IN PLIST_ENTRY ListHead,
; IN PLIST_ENTRY ListEntry,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function inserts an entry at the tail of a doubly linked list
; so that access to the list is synchronized in a multiprocessor system.
; N.B. The pages of data which this routine operates on MUST be
; present. No page fault is allowed in this routine.
; Arguments:
; (ecx) = ListHead - Supplies a pointer to the head of the doubly linked
; list into which an entry is to be inserted.
; (edx) = ListEntry - Supplies a pointer to the entry to be inserted at the
; tail of the list.
; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; Pointer to entry that was at the tail of the list or NULL if the list
; was empty.
cPublicFastCall ExfInterlockedInsertTailList, 3
cPublicFpo 1, 1
ifndef NT_UP
cPublicFpo 1, 2
push esi
mov esi, [esp+8] ; Address of spinlock
endif
pushfd
Eiit10: cli
ACQUIRE_SPINLOCK esi,<short Eiit20>
mov eax, LsBlink[ecx] ; (eax)->prev entry in the list
mov [edx]+LsFlink, ecx ; store next link in entry
mov [edx]+LsBlink, eax ; store previous link in entry
mov [ecx]+LsBlink, edx ; store next link in head
mov [eax]+LsFlink, edx ; store previous link in next
RELEASE_SPINLOCK esi
popfd
ifndef NT_UP
pop esi
endif
xor eax, ecx ; return null if list was empty
jz short Eiit15
xor eax, ecx
Eiit15: fstRET ExfInterlockedInsertTailList
ifndef NT_UP
Eiit20: popfd
pushfd
SPIN_ON_SPINLOCK esi, <short Eiit10>
endif
fstENDP ExfInterlockedInsertTailList
page , 132
subttl "Interlocked Remove Head List"
; PLIST_ENTRY
; FASTCALL
; ExfInterlockedRemoveHeadList (
; IN PLIST_ENTRY ListHead,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function removes an entry from the head of a doubly linked list
; so that access to the list is synchronized in a multiprocessor system.
; If there are no entries in the list, then a value of NULL is returned.
; Otherwise, the address of the entry that is removed is returned as the
; function value.
; N.B. The pages of data which this routine operates on MUST be
; present. No page fault is allowed in this routine.
; Arguments:
; (ecx) ListHead - Supplies a pointer to the head of the doubly linked
; list from which an entry is to be removed.
; (edx) Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; The address of the entry removed from the list, or NULL if the list is
; empty.
cPublicFastCall ExfInterlockedRemoveHeadList , 2
cPublicFpo 0, 1
ifdef NT_UP
; UP version
pushfd
cli
mov eax, [ecx]+LsFlink ; (eax)-> next entry
cmp eax, ecx ; Is list empty?
je short Eirh20 ; if e, list is empty, go Eirh20
mov edx, [eax]+LsFlink ; (ecx)-> next entry(after deletion)
mov [ecx]+LsFlink, edx ; store address of next in head
mov [edx]+LsBlink, ecx ; store address of previous in next
if DBG
mov [eax]+LsFlink, 0baddd0ffh
mov [eax]+LsBlink, 0baddd0ffh
endif
popfd ; restore flags including interrupts
fstRET ExfInterlockedRemoveHeadList
Eirh20: popfd
xor eax,eax ; (eax) = null for empty list
fstRET ExfInterlockedRemoveHeadList
else
; MP version
Eirh40: pushfd
cli
ACQUIRE_SPINLOCK edx, <short Eirh60>
mov eax, [ecx]+LsFlink ; (eax)-> next entry
cmp eax, ecx ; Is list empty?
je short Eirh50 ; if e, list is empty, go Eirh50
cPublicFpo 0,2
push ebx
mov ebx, [eax]+LsFlink ; (ecx)-> next entry(after deletion)
mov [ecx]+LsFlink, ebx ; store address of next in head
mov [ebx]+LsBlink, ecx ; store address of previous in next
if DBG
mov ebx, 0badd0ffh
mov [eax]+LsFlink, ebx
mov [eax]+LsBlink, ebx
endif
RELEASE_SPINLOCK edx
cPublicFpo 0, 0
pop ebx
popfd ; restore flags including interrupts
fstRET ExfInterlockedRemoveHeadList
Eirh50: RELEASE_SPINLOCK edx
popfd
xor eax,eax ; (eax) = null for empty list
fstRET ExfInterlockedRemoveHeadList
cPublicFpo 0, 0
Eirh60: popfd
SPIN_ON_SPINLOCK edx, <Eirh40>
fstRET ExfInterlockedRemoveHeadList
endif ; nt_up
fstENDP ExfInterlockedRemoveHeadList
page , 132
subttl "Interlocked Pop Entry List"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExfInterlockedPopEntryList (
; IN PSINGLE_LIST_ENTRY ListHead,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function removes an entry from the front of a singly linked list
; so that access to the list is synchronized in a multiprocessor system.
; If there are no entries in the list, then a value of NULL is returned.
; Otherwise, the address of the entry that is removed is returned as the
; function value.
; Arguments:
; (ecx) = ListHead - Supplies a pointer to the head of the singly linked
; list from which an entry is to be removed.
; (edx) = Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; The address of the entry removed from the list, or NULL if the list is
; empty.
cPublicFastCall ExfInterlockedPopEntryList , 2
ifdef NT_UP
; UP version
cPublicFpo 0,1
pushfd
cli ; disable interrupts
mov eax, [ecx] ; (eax)-> next entry
or eax, eax ; Is it empty?
je short Eipe05 ; if e, empty list, go Eipe05
mov edx, [eax] ; (edx)->next entry (after deletion)
mov [ecx], edx ; store address of next in head
if DBG
mov [eax], 0baddd0ffh
endif
cPublicFpo 0,0
popfd ; restore flags including interrupts
fstRET ExfInterlockedPopEntryList ; cReturn (eax)->removed entry
Eipe05: popfd
xor eax,eax
fstRET ExfInterlockedPopEntryList ; cReturn (eax)=NULL
else ; nt_up
; MP Version
cPublicFpo 0,1
Eipe10: pushfd
cli ; disable interrupts
ACQUIRE_SPINLOCK edx, <short Eipe30>
mov eax, [ecx] ; (eax)-> next entry
or eax, eax ; Is it empty?
je short Eipe20 ; if e, empty list, go Eipe20
cPublicFpo 0,2
push edx ; Save SpinLock address
mov edx, [eax] ; (edx)->next entry (after deletion)
mov [ecx], edx ; store address of next in head
pop edx ; Restore SpinLock address
if DBG
mov [eax], 0baddd0ffh
endif
RELEASE_SPINLOCK edx
cPublicFpo 0,0
popfd ; restore flags including interrupts
fstRET ExfInterlockedPopEntryList
Eipe20: RELEASE_SPINLOCK edx
popfd
xor eax,eax
fstRET ExfInterlockedPopEntryList
Eipe30: popfd
SPIN_ON_SPINLOCK edx, Eipe10
endif ; nt_up
fstENDP ExfInterlockedPopEntryList
page , 132
subttl "Interlocked Push Entry List"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExInterlockedPushEntryList (
; IN PSINGLE_LIST_ENTRY ListHead,
; IN PSINGLE_LIST_ENTRY ListEntry,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function inserts an entry at the head of a singly linked list
; so that access to the list is synchronized in a multiprocessor system.
; Arguments:
; (ecx) ListHead - Supplies a pointer to the head of the singly linked
; list into which an entry is to be inserted.
; (edx) ListEntry - Supplies a pointer to the entry to be inserted at the
; head of the list.
; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; Previous contents of ListHead. NULL implies list went from empty
; to not empty.
cPublicFastCall ExfInterlockedPushEntryList , 3
ifdef NT_UP
; UP Version
cPublicFpo 0,1
pushfd
cli
mov eax, [ecx] ; (eax)-> next entry (return value also)
mov [edx], eax ; store address of next in new entry
mov [ecx], edx ; set address of next in head
cPublicFpo 0,0
popfd ; restore flags including interrupts
fstRET ExfInterlockedPushEntryList
else
; MP Version
cPublicFpo 1,1
pushfd
push edx
mov edx, [esp+12] ; (edx) = SpinLock
Eipl10: cli
ACQUIRE_SPINLOCK edx, <short Eipl20>
pop edx ; (edx)-> Entry to be pushed
mov eax, [ecx] ; (eax)-> next entry (return value also)
mov [edx], eax ; store address of next in new entry
mov [ecx], edx ; set address of next in head
mov edx, [esp+8] ; (edx) = SpinLock
RELEASE_SPINLOCK edx
cPublicFpo 0,0
popfd ; restore flags including interrupts
fstRET ExfInterlockedPushEntryList
cPublicFpo 1,2
Eipl20: pop edx
popfd ; Restore interrupt state
pushfd
push edx
mov edx, [esp+12]
SPIN_ON_SPINLOCK edx, <short Eipl10>
endif
fstENDP ExfInterlockedPushEntryList
page , 132
subttl "Interlocked Pop Entry Sequenced List"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExInterlockedPopEntrySList (
; IN PSINGLE_LIST_ENTRY ListHead,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function removes an entry from the front of a sequenced singly
; linked list so that access to the list is synchronized in an MP system.
; If there are no entries in the list, then a value of NULL is returned.
; Otherwise, the address of the entry that is removed is returned as the
; function value.
; N.B. The cmpxchg8b instruction is only supported on some processors.
; If the host processor does not support this instruction, then
; then following code is patched to contain a jump to the normal
; pop entry code which has a compatible calling sequence and data
; structure.
; Arguments:
; (ecx) = ListHead - Supplies a pointer to the sequenced listhead from
; which an entry is to be removed.
; (edx) = Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; The address of the entry removed from the list, or NULL if the list is
; empty.
cPublicFastCall ExInterlockedPopEntrySList, 2
cPublicFpo 0,2
; Save nonvolatile registers and read the listhead sequence number followed
; by the listhead next link.
; N.B. These two dwords MUST be read exactly in this order.
push ebx ; save nonvolatile registers
push ebp ;
mov ebp, ecx ; save listhead address
; N.B. The following code is the continuation address should a fault
; occur in the rare case described below.
public ExpInterlockedPopEntrySListResume
ExpInterlockedPopEntrySListResume: ;
mov edx, [ebp] + 4 ; get current sequence number
mov eax, [ebp] + 0 ; get current next link
; If the list is empty, then there is nothing that can be removed.
Epop10: or eax, eax ; check if list is empty
jz short Epop20 ; if z set, list is empty
mov ecx, edx ; copy sequence number and depth
add ecx, 0FFFFH ; adjust sequence number and depth
; N.B. It is possible for the following instruction to fault in the rare
; case where the first entry in the list is allocated on another
; processor and freed between the time the free pointer is read above
; and the following instruction. When this happens, the access fault
; code continues execution above at the resumption address and the
; entire operation is retried.
public ExpInterlockedPopEntrySListFault
ExpInterlockedPopEntrySListFault: ;
mov ebx, [eax] ; get address of successor entry
.586
ifndef NT_UP
lock cmpxchg8b qword ptr [ebp] ; compare and exchange
else
cmpxchg8b qword ptr [ebp] ; compare and exchange
endif
.386
jnz short Epop10 ; if z clear, exchange failed
; Restore nonvolatile registers and return result.
cPublicFpo 0,0
Epop20: pop ebp ; restore nonvolatile registers
pop ebx ;
fstRET ExInterlockedPopEntrySList
fstENDP ExInterlockedPopEntrySList
page , 132
subttl "Interlocked Push Entry Sequenced List"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExInterlockedPushEntrySList (
; IN PSINGLE_LIST_ENTRY ListHead,
; IN PSINGLE_LIST_ENTRY ListEntry,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function inserts an entry at the head of a sequenced singly linked
; list so that access to the list is synchronized in an MP system.
; N.B. The cmpxchg8b instruction is only supported on some processors.
; If the host processor does not support this instruction, then
; then following code is patched to contain a jump to the normal
; push entry code which has a compatible calling sequence and data
; structure.
; Arguments:
; (ecx) ListHead - Supplies a pointer to the sequenced listhead into which
; an entry is to be inserted.
; (edx) ListEntry - Supplies a pointer to the entry to be inserted at the
; head of the list.
; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; Previous contents of ListHead. NULL implies list went from empty
; to not empty.
cPublicFastCall ExInterlockedPushEntrySList, 3
cPublicFpo 0,2
; Save nonvolatile registers and read the listhead sequence number followed
; by the listhead next link.
; N.B. These two dwords MUST be read exactly in this order.
push ebx ; save nonvolatile registers
push ebp ;
mov ebp, ecx ; save listhead address
mov ebx, edx ; save list entry address
mov edx, [ebp] + 4 ; get current sequence number
mov eax, [ebp] + 0 ; get current next link
Epsh10: mov [ebx], eax ; set next link in new first entry
mov ecx, edx ; copy sequence number
add ecx, 010001H ; increment sequence number and depth
.586
ifndef NT_UP
lock cmpxchg8b qword ptr [ebp] ; compare and exchange
else
cmpxchg8b qword ptr[ebp] ; compare and exchange
endif
.386
jnz short Epsh10 ; if z clear, exchange failed
; Restore nonvolatile registers and return result.
cPublicFpo 0,0
pop ebp ; restore nonvolatile registers
pop ebx ;
fstRET ExInterlockedPushEntrySList
fstENDP ExInterlockedPushEntrySList
page , 132
subttl "Interlocked Flush Sequenced List"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExInterlockedFlushSList (
; IN PSINGLE_LIST_ENTRY ListHead
; )
; Routine Description:
; This function removes the entire list from a sequenced singly
; linked list so that access to the list is synchronized in an MP system.
; If there are no entries in the list, then a value of NULL is returned.
; Otherwise, the address of the entry at the top of the list is removed
; and returned as the function value and the list header is set to point
; to NULL.
; N.B. The cmpxchg8b instruction is only supported on some processors.
; If the host processor does not support this instruction, then
; then following code is patched to contain a jump to the normal
; pop entry code which has a compatible calling sequence and data
; structure.
; Arguments:
; (ecx) = ListHead - Supplies a pointer to the sequenced listhead from
; which the list is to be flushed.
; Return Value:
; The address of the entire current list, or NULL if the list is
; empty.
cPublicFastCall ExInterlockedFlushSList, 1
cPublicFpo 0,1
; Save nonvolatile registers and read the listhead sequence number followed
; by the listhead next link.
; N.B. These two dwords MUST be read exactly in this order.
push ebx ; save nonvolatile registers
push ebp ;
mov ebp, ecx ; save listhead address
mov edx, [ebp] + 4 ; get current sequence number
mov eax, [ebp] + 0 ; get current next link
; N.B. The following code is the retry code should the compare
; part of the compare exchange operation fail
; If the list is empty, then there is nothing that can be removed.
Efls10: or eax, eax ; check if list is empty
jz short Efls20 ; if z set, list is empty
mov ecx, 0 ; clear sequence number and depth
mov ebx, 0 ; clear successor entry pointer
.586
ifndef NT_UP
lock cmpxchg8b qword ptr [ebp] ; compare and exchange
else
cmpxchg8b qword ptr [ebp] ; compare and exchange
endif
.386
jnz short Efls10 ; if z clear, exchange failed
; Restore nonvolatile registers and return result.
cPublicFpo 0,0
Efls20: pop ebp ; restore nonvolatile registers
pop ebx ;
fstRET ExInterlockedFlushSList
fstENDP ExInterlockedFlushSList
page , 132
subttl "Interlocked Pop Entry SList - Alternate"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExfInterlockedPopEntrySList (
; IN PSINGLE_LIST_ENTRY ListHead,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function removes an entry from the front of a sequenced singly
; linked list so that access to the list is synchronized in an MP system.
; If there are no entries in the list, then a value of NULL is returned.
; Otherwise, the address of the entry that is removed is returned as the
; function value.
; N.B. The cmpxchg8b instruction is only supported on some processors.
; If the host processor does not support this instruction, then
; this function is used inplace of ExInterlockedPopEntrySList.
; Arguments:
; (ecx) = ListHead - Supplies a pointer to the sequenced listhead from
; which an entry is to be removed.
; (edx) = Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; The address of the entry removed from the list, or NULL if the list is
; empty.
cPublicFastCall ExfInterlockedPopEntrySList, 2
cPublicFpo 0,1
Efpo10: pushfd ; save flags
cli ; disable interrupts
ifndef NT_UP
ACQUIRE_SPINLOCK edx, <short Efpo30> ; acquire spinlock
endif
mov eax, [ecx] ; get current next link
or eax, eax ; check if list is empty
jz short Efpo20 ; if z set, list is empty
push [eax] ; get address of successor list
pop [ecx] ; store address of next in head
dec dword ptr [ecx] + 4 ; decrement list depth
Efpo20: ;
ifndef NT_UP
RELEASE_SPINLOCK edx ; release spinlock
endif
cPublicFpo 0,0
popfd ; restore flags
fstRET ExfInterlockedPopEntrySList
ifndef NT_UP
cPublicFpo 0,0
Efpo30: popfd ; restore flags
SPIN_ON_SPINLOCK edx, Efpo10 ; spin until lock is free
endif
fstENDP ExfInterlockedPopEntrySList
page , 132
subttl "Interlocked Push Entry SList - Alternate"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExInterlockedPushEntrySList (
; IN PSINGLE_LIST_ENTRY ListHead,
; IN PSINGLE_LIST_ENTRY ListEntry,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function inserts an entry at the head of a sequenced singly linked
; list so that access to the list is synchronized in an MP system.
; N.B. The cmpxchg8b instruction is only supported on some processors.
; If the host processor does not support this instruction, then
; this function is used inplace of ExInterlockedPushEntrySList.
; Arguments:
; (ecx) ListHead - Supplies a pointer to the sequenced listhead into which
; an entry is to be inserted.
; (edx) ListEntry - Supplies a pointer to the entry to be inserted at the
; head of the list.
; (esp+4) Lock - Supplies a pointer to a spin lock to be used to synchronize
; access to the list.
; Return Value:
; Previous contents of ListHead. NULL implies list went from empty
; to not empty.
cPublicFastCall ExfInterlockedPushEntrySList, 3
cPublicFpo 0,1
Efph10: pushfd ; save flags
cli ; disable interrupts
ifndef NT_UP
mov eax, [esp] + 8 ; get spinlock address
ACQUIRE_SPINLOCK eax, <short Efph20> ; acquire spinlock
endif
push [ecx] ; get current next link
pop [edx] ; store address of next in new entry
mov [ecx], edx ; set address of next in head
inc dword ptr [ecx] + 4 ; increment list depth
ifndef NT_UP
RELEASE_SPINLOCK eax ; release spinlock
endif
cPublicFpo 0,0
popfd ; restore flags
fstRET ExfInterlockedPushEntrySList
ifndef NT_UP
cPublicFpo 0,0
Efph20: popfd ; restore flags
SPIN_ON_SPINLOCK eax, <short Efph10> ; spin until lock is free
endif
fstENDP ExfInterlockedPushEntrySList
page , 132
subttl "Interlocked Flush SList - Alternate"
; PSINGLE_LIST_ENTRY
; FASTCALL
; ExfInterlockedFlushSList (
; IN PSINGLE_LIST_ENTRY ListHead
; )
; Routine Description:
; This function returns a pointer to the entire SLIST on the specified list.
; Access to the list is synchronized in an MP system.
; If there are no entries in the list, then a value of NULL is returned.
; Otherwise, the address of the entry at the beginning of the list is returned
; and the entire list is removed from the slist.
; N.B. The cmpxchg8b instruction is only supported on some processors.
; If the host processor does not support this instruction, then
; this function is used inplace of ExInterlockedFlushSList.
; Arguments:
; (ecx) = ListHead - Supplies a pointer to the sequenced listhead from
; which an entry is to be removed.
; Return Value:
; The address of the entries removed from the list, or NULL if the list is
; empty.
cPublicFastCall ExfInterlockedFlushSList, 1
cPublicFpo 0,1
ifndef NT_UP
lea edx, _Ki486CompatibilityLock ; get 486 compatiblity lock address
endif
Effl10: pushfd ; save flags
cli ; disable interrupts
ifndef NT_UP
ACQUIRE_SPINLOCK edx, <short Effl30> ; acquire spinlock
endif
mov eax, [ecx] ; get current next link
or eax, eax ; check if list is empty
jz short Effl20 ; if z set, list is empty
mov dword ptr [ecx], 0 ; clear the list pointer (empty list)
mov dword ptr [ecx] + 4, 0 ; clear the list depth (empty list)
Effl20: ;
ifndef NT_UP
RELEASE_SPINLOCK edx ; release spinlock
endif
cPublicFpo 0,0
popfd ; restore flags
fstRET ExfInterlockedFlushSList
ifndef NT_UP
cPublicFpo 0,0
Effl30: popfd ; restore flags
SPIN_ON_SPINLOCK edx, Effl10 ; spin until lock is free
endif
fstENDP ExfInterlockedFlushSList
page , 132
subttl "Interlocked i386 Increment Long"
; INTERLOCKED_RESULT
; FASTCALL
; Exfi386InterlockedIncrementLong (
; IN PLONG Addend
; )
; Routine Description:
; This function atomically increments Addend, returning an ennumerated
; type which indicates what interesting transitions in the value of
; Addend occurred due the operation.
; See ExInterlockedIncrementLong. This function is the i386
; architectural specific version of ExInterlockedIncrementLong.
; No source directly calls this function, instead
; ExInterlockedIncrementLong is called and when built on x86 these
; calls are macroed to the i386 optimized version.
; Arguments:
; (ecx) Addend - Pointer to variable to increment.
; Return Value:
; An ennumerated type:
; ResultNegative if Addend is < 0 after increment.
; ResultZero if Addend is = 0 after increment.
; ResultPositive if Addend is > 0 after increment.
cPublicFastCall Exfi386InterlockedIncrementLong, 1
cPublicFpo 0, 0
ifdef NT_UP
add dword ptr [ecx],1
else
lock add dword ptr [ecx],1
endif
lahf ; (ah) = flags
and eax,EFLAG_SELECT ; clear all but sign and zero flags
fstRET Exfi386InterlockedIncrementLong
fstENDP Exfi386InterlockedIncrementLong
page , 132
subttl "Interlocked i386 Decrement Long"
; INTERLOCKED_RESULT
; FASTCALL
; Exfi386InterlockedDecrementLong (
; IN PLONG Addend,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function atomically decrements Addend, returning an ennumerated
; type which indicates what interesting transitions in the value of
; Addend occurred due the operation.
; See Exi386InterlockedDecrementLong. This function is the i386
; architectural specific version of ExInterlockedDecrementLong.
; No source directly calls this function, instead
; ExInterlockedDecrementLong is called and when built on x86 these
; calls are macroed to the i386 optimized version.
; Arguments:
; Addend (esp+4) - Pointer to variable to decrement.
; Lock (esp+8) - Spinlock used to implement atomicity.
; (not actually used on x86)
; Return Value:
; An ennumerated type:
; ResultNegative if Addend is < 0 after decrement.
; ResultZero if Addend is = 0 after decrement.
; ResultPositive if Addend is > 0 after decrement.
cPublicFastCall Exfi386InterlockedDecrementLong , 1
cPublicFpo 0, 0
ifdef NT_UP
sub dword ptr [ecx], 1
else
lock sub dword ptr [ecx], 1
endif
lahf ; (ah) = flags
and eax, EFLAG_SELECT ; clear all but sign and zero flags
fstRET Exfi386InterlockedDecrementLong
fstENDP Exfi386InterlockedDecrementLong
page , 132
subttl "Interlocked i386 Exchange Ulong"
; ULONG
; FASTCALL
; Exfi386InterlockedExchangeUlong (
; IN PULONG Target,
; IN ULONG Value
; )
; Routine Description:
; This function atomically exchanges the Target and Value, returning
; the prior contents of Target
; See Exi386InterlockedExchangeUlong. This function is the i386
; architectural specific version of ExInterlockedDecrementLong.
; No source directly calls this function, instead
; ExInterlockedDecrementLong is called and when built on x86 these
; calls are macroed to the i386 optimized version.
; Arguments:
; (ecx) = Source - Address of ULONG to exchange
; (edx) = Value - New value of ULONG
; Return Value:
; The prior value of Source
cPublicFastCall Exfi386InterlockedExchangeUlong, 2
cPublicFpo 0,0
cPublicFastCall InterlockedExchange, 2
.486
ifndef NT_UP
xchg [ecx], edx ; make the exchange
mov eax, edx
else
mov eax, [ecx] ; get comperand value
Ixchg: cmpxchg [ecx], edx ; compare and swap
jnz Ixchg ; if nz, exchange failed
endif
.386
fstRET Exfi386InterlockedExchangeUlong
fstENDP InterlockedExchange
fstENDP Exfi386InterlockedExchangeUlong
; LONG
; InterlockedIncrement(
; IN PLONG Addend
; )
; Routine Description:
; This function performs an interlocked add of one to the addend variable.
; No checking is done for overflow.
; Arguments:
; Addend (ecx) - Supplies a pointer to a variable whose value is to be
; incremented by one.
; Return Value:
; (eax) - The incremented value.
cPublicFastCall InterlockedIncrement,1
cPublicFpo 0,0
mov eax, 1 ; set increment value
.486
ifndef NT_UP
lock xadd [ecx], eax ; interlocked increment
else
xadd [ecx], eax ; interlocked increment
endif
.386p
inc eax ; adjust return value
fstRET InterlockedIncrement
fstENDP InterlockedIncrement
page , 132
subttl "InterlockedDecrment"
; LONG
; InterlockedDecrement(
; IN PLONG Addend
; )
; Routine Description:
; This function performs an interlocked add of -1 to the addend variable.
; No checking is done for overflow
; Arguments:
; Addend (ecx) - Supplies a pointer to a variable whose value is to be
; decremented by one.
; Return Value:
; (eax) - The decremented value.
cPublicFastCall InterlockedDecrement,1
cPublicFpo 0,0
mov eax, -1 ; set decrment value
.486
ifndef NT_UP
lock xadd [ecx], eax ; interlocked decrement
else
xadd [ecx], eax ; interlocked decrement
endif
.386
dec eax ; adjust return value
fstRET InterlockedDecrement
fstENDP InterlockedDecrement
page , 132
subttl "Interlocked Compare Exchange"
; PVOID
; FASTCALL
; InterlockedCompareExchange (
; IN OUT PVOID *Destination,
; IN PVOID Exchange,
; IN PVOID Comperand
; )
; Routine Description:
; This function performs an interlocked compare of the destination
; value with the comperand value. If the destination value is equal
; to the comperand value, then the exchange value is stored in the
; destination. Otherwise, no operation is performed.
; Arguments:
; (ecx) Destination - Supplies a pointer to destination value.
; (edx) Exchange - Supplies the exchange value.
; [esp + 4] Comperand - Supplies the comperand value.
; Return Value:
; The initial destination value is returned as the function value.
cPublicFastCall InterlockedCompareExchange, 3
cPublicFpo 0,0
mov eax, [esp + 4] ; set comperand value
.486
ifndef NT_UP
lock cmpxchg [ecx], edx ; compare and exchange
else
cmpxchg [ecx], edx ; compare and exchange
endif
.386
fstRET InterlockedCompareExchange
fstENDP InterlockedCompareExchange
page , 132
subttl "Interlocked Compare Exchange 64-bits"
; LONGLONG
; FASTCALL
; ExInterlockedCompareExchange64 (
; IN PLONGLONG Destination,
; IN PLONGLONG Exchange,
; IN PLONGLONG Comperand,
; IN PKSPIN_LOCK Lock
; )
; Routine Description:
; This function performs a compare and exchange of 64-bits.
; N.B. The cmpxchg8b instruction is only supported on some processors.
; If the host processor does not support this instruction, then
; then following code is patched to contain a jump to the normal
; compare exchange 64-bit code which has a compatible calling
; sequence and data structure.
; Arguments:
; (ecx) Destination - Supplies a pointer to the destination variable.
; (edx) Exchange - Supplies a pointer to the exchange value.
; (esp+4) Comperand - Supplies a pointer to the comperand value.
; (esp+4) Lock - Supplies a pointer to a spin lock to use if the cmpxchg8b
; instruction is not available on the host system.
; Return Value:
; The current destination value is returned as the function value.
cPublicFastCall ExInterlockedCompareExchange64, 4
cPublicFpo 0,2
; Save nonvolatile registers and read the exchange and comperand values.
push ebx ; save nonvolatile registers
push ebp ;
mov ebp, ecx ; set destination address
mov ebx, [edx] ; get exchange value
mov ecx, [edx] + 4 ;
mov edx, [esp] + 12 ; get comperand address
mov eax, [edx] ; get comperand value
mov edx, [edx] + 4 ;
.586
ifndef NT_UP
lock cmpxchg8b qword ptr [ebp] ; compare and exchange
else
cmpxchg8b qword ptr[ebp] ; compare and exchange
endif
.386
; Restore nonvolatile registers and return result in edx:eax.
cPublicFpo 0,0
pop ebp ; restore nonvolatile registers
pop ebx ;
fstRET ExInterlockedCompareExchange64
fstENDP ExInterlockedCompareExchange64
; The following version of the compare exchange 64-bits function is used
; when the host processor does not support the cmpxchg8 instruction.
cPublicFastCall ExpInterlockedCompareExchange64, 4
cPublicFpo 0,2
; Save nonvolatile registers and read the exchange and comperand values.
push ebx ; save nonvolatile registers
push ebp ;
mov ebp, ecx ; set destination address
mov ebx, [edx] ; get exchange value
mov ecx, [edx] + 4 ;
mov edx, [esp] + 12 ; get comperand address
mov eax, [edx] ; get comperand value
mov edx, [edx] + 4 ;
ifndef NT_UP
cPublicFpo 0,4
push esi ; save register
pushfd ; save flags
mov esi, [esp] + 24 ; get address of lock
Eicx10: cli ; disable interrupts
ACQUIRE_SPINLOCK esi, <short Eicx40> ; acquire spinlock
else
cPublicFpo 0,3
pushfd ; save flags
cli ; disable interrupts
endif
cmp eax, [ebp] ; compare current with comperand
jne short Eicx30 ; if ne, low part mismatch
cmp edx, [ebp] + 4 ; compare current with comperand
jne short Eicx30 ; if ne, high part mismatch
mov [ebp], ebx ; store exchange value
mov [ebp] + 4, ecx ;
; Restore nonvolatile registers and return result in edx:eax.
cPublicFpo 0,0
ifndef NT_UP
Eicx20: RELEASE_SPINLOCK esi ; release spin lock
popfd ; restore flags
pop esi ; restore register
else
Eicx20: popfd ; restore flags
endif
pop ebp ; restore nonvolatile registers
pop ebx ;
fstRET ExpInterlockedCompareExchange64
; The current and comperand values mismatch. Return the current destination
; value.
Eicx30: mov eax, [ebp] ; get current destination value
mov edx, [ebp] + 4 ;
jmp short Eicx20 ;
; The spinlock is currently owned.
ifndef NT_UP
Eicx40: popfd ; restore flags
pushfd ; save flags
SPIN_ON_SPINLOCK esi, <short Eicx10> ; spin until lock free
endif
fstENDP ExpInterlockedCompareExchange64
page , 132
subttl "Interlocked Exchange Add"
; LONG
; FASTCALL
; InterlockedExchangeAdd (
; IN OUT PLONG Addend,
; IN LONG Increment
; )
; Routine Description:
; This function performs an interlocked add of an increment value to an
; addend variable of type unsinged long. The initial value of the addend
; variable is returned as the function value.
; It is NOT possible to mix ExInterlockedDecrementLong and
; ExInterlockedIncrementong with ExInterlockedAddUlong.
; Arguments:
; (ecx) Addend - Supplies a pointer to a variable whose value is to be
; adjusted by the increment value.
; (edx) Increment - Supplies the increment value to be added to the
; addend variable.
; Return Value:
; The initial value of the addend variable.
cPublicFastCall InterlockedExchangeAdd, 2
cPublicFpo 0,0
.486
ifndef NT_UP
lock xadd [ecx], edx ; exchange add
else
xadd [ecx], edx ; exchange add
endif
.386
mov eax, edx ; set initial value
fstRET InterlockedExchangeAdd
fstENDP InterlockedExchangeAdd
_TEXT$00 ends
end