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.
568 lines
16 KiB
568 lines
16 KiB
title "Critical Section Support"
|
|
;++
|
|
;
|
|
; Copyright (c) 1991 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; critsect.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements functions to support user mode interlocked operations.
|
|
;
|
|
; Author:
|
|
;
|
|
; Bryan M. Willman (bryanwi) 2-Oct-91
|
|
;
|
|
; Environment:
|
|
;
|
|
; Any mode.
|
|
;
|
|
; Revision History:
|
|
;
|
|
;
|
|
; WARNING!!!!!!!!!! Some of this code is duplicated in
|
|
; ntos\dll\i386\critsect.asm
|
|
;
|
|
; Some day we should put it in a .inc file that both include.
|
|
;
|
|
;--
|
|
|
|
.486p
|
|
.xlist
|
|
include ks386.inc
|
|
include callconv.inc
|
|
.list
|
|
|
|
_DATA SEGMENT DWORD PUBLIC 'DATA'
|
|
public _BasepLockPrefixTable
|
|
_BasepLockPrefixTable label dword
|
|
dd offset FLAT:Lock1
|
|
dd offset FLAT:Lock2
|
|
dd offset FLAT:Lock3
|
|
dd offset FLAT:Lock4
|
|
dd offset FLAT:Lock5
|
|
dd 0
|
|
_DATA ENDS
|
|
|
|
|
|
_TEXT SEGMENT PARA PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
|
|
Addend equ [esp + 4]
|
|
FlagMask equ 0c0000000H
|
|
FlagShift equ 24
|
|
FlagSelect equ 30
|
|
|
|
page , 132
|
|
subttl "InterlockedIncrement"
|
|
|
|
;++
|
|
;
|
|
; 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 - Supplies a pointer to a variable whose value is to be
|
|
; incremented by one.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; (eax) - the incremented value.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _InterlockedIncrement,1
|
|
cPublicFpo 1,0
|
|
mov ecx,Addend ; get pointer to addend variable
|
|
mov eax,1 ; set increment value
|
|
Lock1:
|
|
lock xadd [ecx],eax ; interlocked increment
|
|
inc eax ; adjust return value
|
|
stdRET _InterlockedIncrement ;
|
|
|
|
stdENDP _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 - Supplies a pointer to a variable whose value is to be
|
|
; decremented by one.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; (eax) - The decremented value.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _InterlockedDecrement,1
|
|
cPublicFpo 1,0
|
|
|
|
mov ecx,Addend ; get pointer to addend variable
|
|
mov eax,-1 ; set decrement value
|
|
Lock2:
|
|
lock xadd [ecx],eax ; interlocked decrement
|
|
dec eax ; adjust return value
|
|
stdRET _InterlockedDecrement ;
|
|
|
|
stdENDP _InterlockedDecrement
|
|
|
|
page , 132
|
|
subttl "Interlocked Exchange"
|
|
;++
|
|
;
|
|
; LONG
|
|
; InterlockedExchange(
|
|
; IN OUT LPLONG Target,
|
|
; IN LONG Value
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function atomically exchanges the Target and Value, returning
|
|
; the prior contents of Target
|
|
;
|
|
; Arguments:
|
|
;
|
|
; Target - Address of LONG to exchange
|
|
; Value - New value of LONG
|
|
;
|
|
; Return Value:
|
|
;
|
|
; (eax) - The prior value of target.
|
|
;--
|
|
|
|
cPublicProc _InterlockedExchange, 2
|
|
cPublicFpo 2,0
|
|
|
|
mov ecx, [esp+4] ; (ecx) = Target
|
|
mov edx, [esp+8] ; (edx) = Value
|
|
mov eax, [ecx] ; get comperand value
|
|
Ixchg:
|
|
Lock5:
|
|
lock cmpxchg [ecx], edx ; compare and swap
|
|
jnz Ixchg ; if nz, exchange failed
|
|
stdRET _InterlockedExchange
|
|
|
|
stdENDP _InterlockedExchange
|
|
|
|
page , 132
|
|
subttl "Interlocked Compare Exchange"
|
|
;++
|
|
;
|
|
; PVOID
|
|
; 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:
|
|
;
|
|
; Destination - Supplies a pointer to destination value.
|
|
;
|
|
; Exchange - Supplies the exchange value.
|
|
;
|
|
; Comperand - Supplies the comperand value.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; (eax) - The initial destination value.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _InterlockedCompareExchange, 3
|
|
cPublicFpo 3,0
|
|
|
|
mov ecx, [esp + 4] ; get destination address
|
|
mov edx, [esp + 8] ; get exchange value
|
|
mov eax, [esp + 12] ; get comperand value
|
|
Lock3:
|
|
lock cmpxchg [ecx], edx ; compare and exchange
|
|
|
|
stdRET _InterlockedCompareExchange
|
|
|
|
stdENDP _InterlockedCompareExchange
|
|
|
|
page , 132
|
|
subttl "Interlocked Exchange Add"
|
|
;++
|
|
;
|
|
; LONG
|
|
; 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:
|
|
;
|
|
; Addend - Supplies a pointer to a variable whose value is to be
|
|
; adjusted by the increment value.
|
|
;
|
|
; Increment - Supplies the increment value to be added to the
|
|
; addend variable.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; (eax) - The initial value of the addend.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _InterlockedExchangeAdd, 2
|
|
cPublicFpo 2,0
|
|
|
|
mov ecx, [esp + 4] ; get addend address
|
|
mov eax, [esp + 8] ; get increment value
|
|
Lock4:
|
|
lock xadd [ecx], eax ; exchange add
|
|
|
|
stdRET _InterlockedExchangeAdd
|
|
|
|
stdENDP _InterlockedExchangeAdd
|
|
|
|
page , 132
|
|
subttl "Multiply and Divide"
|
|
;++
|
|
;
|
|
; LONG
|
|
; MulDiv(
|
|
; IN LONG nNumber,
|
|
; IN LONG nNumerator,
|
|
; IN LONG nDenominator
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function multiples two 32-bit numbers forming a 64-bit product.
|
|
; The 64-bit product is rounded and then divided by a 32-bit divisor
|
|
; yielding a 32-bit result.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; nNumber - Supllies the multiplier.
|
|
;
|
|
; nNumerator - Supplies the multiplicand.
|
|
;
|
|
; nDenominator - Supplies the divisor.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; If the divisor is zero or an overflow occurs, then a value of -1 is
|
|
; returned as the function value. Otherwise, the rounded quotient is
|
|
; returned as the funtion value.
|
|
;
|
|
;--
|
|
|
|
nNumber equ [esp + 4]
|
|
nNumerator equ [esp + 8]
|
|
nDenominator equ DWORD PTR [esp + 12]
|
|
|
|
cPublicProc _MulDiv, 3
|
|
cPublicFpo 3,0
|
|
mov eax, nNumber ; get multiplier absolute value
|
|
or eax, eax ;
|
|
js short MD32_First ; if s, multiplier is negative
|
|
|
|
;
|
|
; The multiplier is positive.
|
|
;
|
|
|
|
mov edx, nNumerator ; get multiplicand absolute value
|
|
or edx, edx ;
|
|
js MD32_Second ; if s, multiplicand is negative
|
|
|
|
;
|
|
; The multiplicand is positive.
|
|
;
|
|
|
|
mul edx ; compute 64-bit product
|
|
mov ecx, nDenominator ; get denominator absolute value
|
|
or ecx, ecx ;
|
|
js MD32_Third ; if s, divisor is negative
|
|
|
|
;
|
|
; The divisor is positive.
|
|
;
|
|
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
cmp edx, nDenominator ; check for overflow
|
|
jae short MD32_error ; if ae, overflow or divide by 0
|
|
div nDenominator ; compute quotient
|
|
|
|
;
|
|
; The result is postive.
|
|
;
|
|
|
|
or eax, eax ; check for overflow
|
|
js short MD32_error ; if s, overlfow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
MD32_error:
|
|
xor eax, eax ; set return value to - 1
|
|
dec eax ;
|
|
|
|
stdRET _MulDiv
|
|
|
|
;
|
|
; The multiplier is negative.
|
|
;
|
|
|
|
MD32_First: ;
|
|
neg eax ; negate multiplier
|
|
mov edx, nNumerator ; get multiplicand absolute value
|
|
or edx, edx ;
|
|
js short MD32_First10 ; if s, multiplicand is negative
|
|
|
|
;
|
|
; The multiplicand is positive.
|
|
;
|
|
|
|
mul edx ; compute 64-bit product
|
|
mov ecx, nDenominator ; get denominator absolute value
|
|
or ecx, ecx ;
|
|
js short MD32_First20 ; if s, divisor is negative
|
|
|
|
;
|
|
; The divisor is positive.
|
|
;
|
|
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
cmp edx, nDenominator ; check for overflow
|
|
jae short MD32_error10 ; if ae, overflow or divide by 0
|
|
div nDenominator ; compute quotient
|
|
|
|
;
|
|
; The result is negative.
|
|
;
|
|
|
|
neg eax ; negate result
|
|
jg short MD32_error10 ; if g, overlfow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
;
|
|
; The multiplier is negative and the multiplicand is negative.
|
|
;
|
|
|
|
MD32_First10: ;
|
|
neg edx ; negate multiplicand
|
|
mul edx ; compute 64-bit product
|
|
mov ecx, nDenominator ; get denominator absolute value
|
|
or ecx, ecx ;
|
|
js short MD32_First30 ; if s, divisor is negative
|
|
|
|
;
|
|
; The divisor is positive.
|
|
;
|
|
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
cmp edx, nDenominator ; check for overflow
|
|
jae short MD32_error10 ; if ae, overflow or divide by 0
|
|
div nDenominator ; compute quotient
|
|
|
|
;
|
|
; The result is positive.
|
|
;
|
|
|
|
or eax, eax ; check for overflow
|
|
js short MD32_error10 ; if s, overlfow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
MD32_error10: ;
|
|
xor eax, eax ; set return value to - 1
|
|
dec eax ;
|
|
|
|
stdRET _MulDiv
|
|
|
|
|
|
;
|
|
; The multiplier is negative, the multiplicand is positive, and the
|
|
; divisor is negative.
|
|
;
|
|
|
|
MD32_First20: ;
|
|
neg ecx ; negate divisor
|
|
push ecx ; save absolute value of divisor
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
pop ecx ; restore divisor
|
|
cmp edx, ecx ; check for overflow
|
|
jae short MD32_error10 ; if ae, overflow or divide by 0
|
|
div ecx ; compute quotient
|
|
|
|
;
|
|
; The result is postive.
|
|
;
|
|
|
|
or eax, eax ; check for overflow
|
|
js short MD32_error10 ; if s, overlfow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
;
|
|
; The multiplier is negative, the multiplier is negative, and the divisor
|
|
; is negative.
|
|
;
|
|
|
|
MD32_First30: ;
|
|
neg ecx ; negate divisor
|
|
push ecx ; save absolute value of divisor
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
pop ecx ; restore divisor
|
|
cmp edx, ecx ; check for overflow
|
|
jae short MD32_error10 ; if ae, overflow or divide by 0
|
|
div ecx ; compute quotient
|
|
|
|
;
|
|
; The result is negative.
|
|
;
|
|
|
|
neg eax ; negate result
|
|
jg short MD32_error10 ; if g, overlfow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
;
|
|
; The multiplier is positive and the multiplicand is negative.
|
|
;
|
|
|
|
MD32_Second: ;
|
|
neg edx ; negate multiplicand
|
|
mul edx ; compute 64-bit product
|
|
mov ecx, nDenominator ; get denominator absolute value
|
|
or ecx, ecx ;
|
|
js short MD32_Second10 ; if s, divisor is negative
|
|
|
|
;
|
|
; The divisor is positive.
|
|
;
|
|
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
cmp edx, nDenominator ; check for overflow
|
|
jae short MD32_error20 ; if ae, overflow or divide by 0
|
|
div nDenominator ; compute quotient
|
|
|
|
;
|
|
; The result is negative.
|
|
;
|
|
|
|
neg eax ; check for overflow
|
|
jg short MD32_error20 ; if g, overlfow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
MD32_error20: ;
|
|
xor eax, eax ; set return value to - 1
|
|
dec eax ;
|
|
|
|
stdRET _MulDiv
|
|
|
|
;
|
|
; The multiplier is positive, the multiplicand is negative, and the divisor
|
|
; is negative.
|
|
;
|
|
|
|
MD32_Second10: ;
|
|
neg ecx ; negate divisor
|
|
push ecx ; save absolute value of divisor
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
pop ecx ; restore divisor
|
|
cmp edx, ecx ; check for overflow
|
|
jae short MD32_error20 ; if ae, overflow or divide by 0
|
|
div ecx ; compute quotient
|
|
|
|
;
|
|
; The result is positive.
|
|
;
|
|
|
|
or eax, eax ; check for overflow
|
|
js short MD32_error10 ; if s, overlfow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
;
|
|
; The multiplier is positive, the multiplicand is positive, the divisor
|
|
; is negative.
|
|
;
|
|
|
|
MD32_Third: ;
|
|
neg ecx ; negate divisor
|
|
push ecx ; save absolute value of divisor
|
|
sar ecx, 1 ; compute rounding value
|
|
add eax, ecx ; round the 64-bit produce by the
|
|
adc edx, 0 ; divisor / 2
|
|
pop ecx ; restore divisor
|
|
cmp edx, ecx ; check for overflow
|
|
jae short MD32_error20 ; if ae, overflow or divide by 0
|
|
div ecx ; compute quotient
|
|
|
|
;
|
|
; The result is negative.
|
|
;
|
|
|
|
neg eax ; negate result
|
|
jg short MD32_error20 ; if g, overflow has occured
|
|
|
|
stdRET _MulDiv
|
|
|
|
stdENDP _MulDiv
|
|
|
|
_TEXT ends
|
|
end
|