281 lines
8.4 KiB
ArmAsm
281 lines
8.4 KiB
ArmAsm
// TITLE("Interlocked Increment and Decrement Support")
|
||
//++
|
||
//
|
||
// Copyright (c) 1991 Microsoft Corporation
|
||
// Copyright (c) 1992 Digital Equipment Corporation
|
||
//
|
||
// Module Name:
|
||
//
|
||
// critsect.s
|
||
//
|
||
// Abstract:
|
||
//
|
||
// This module implements functions to support user mode critical sections.
|
||
// It contains some code from ntos\dll\alpha\critsect.s but without the Rtl
|
||
// prefix.
|
||
//
|
||
// Author:
|
||
//
|
||
// David N. Cutler 29-Apr-1992
|
||
//
|
||
// Environment:
|
||
//
|
||
// Any mode.
|
||
//
|
||
// Revision History:
|
||
//
|
||
// Thomas Van Baak (tvb) 22-Jul-1992
|
||
//
|
||
// Adapted for Alpha AXP.
|
||
//
|
||
//--
|
||
|
||
#include "ksalpha.h"
|
||
|
||
SBTTL("Interlocked Increment")
|
||
//++
|
||
//
|
||
// LONG
|
||
// InterlockedIncrement(
|
||
// IN PLONG Addend
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function performs an interlocked increment on the addend variable.
|
||
//
|
||
// This function and its companion are assuming that the count will never
|
||
// be incremented past 2**31 - 1.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Addend (a0) - Supplies a pointer to a variable whose value is to be
|
||
// incremented.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// A negative value is returned if the updated value is less than zero,
|
||
// a zero value is returned if the updated value is zero, and a nonzero
|
||
// positive value is returned if the updated value is greater than zero.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(InterlockedIncrement)
|
||
|
||
10: mb // synchronize memory access
|
||
ldl_l v0, 0(a0) // get addend value - locked
|
||
addl v0, 1, v0 // increment addend value
|
||
mov v0, t0 // copy updated value to t0 for store
|
||
stl_c t0, 0(a0) // store conditionally
|
||
beq t0, 20f // if eq, conditional store failed
|
||
mb // synchronize memory access
|
||
ret zero, (ra) // return
|
||
|
||
//
|
||
// We expect the store conditional will usually succeed the first time so it
|
||
// is faster to branch forward (predicted not taken) to here and then branch
|
||
// backward (predicted taken) to where we wanted to go.
|
||
//
|
||
|
||
20: br zero, 10b // go try load again
|
||
|
||
.end InterlockedIncrement
|
||
|
||
SBTTL("InterlockedDecrement")
|
||
//++
|
||
//
|
||
// LONG
|
||
// InterlockedDecrement(
|
||
// IN PLONG Addend
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function performs an interlocked decrement on the addend variable.
|
||
//
|
||
// This function and its companion are assuming that the count will never
|
||
// be decremented past 2**31 - 1.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Addend (a0) - Supplies a pointer to a variable whose value is to be
|
||
// decremented.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// A negative value is returned if the updated value is less than zero,
|
||
// a zero value is returned if the updated value is zero, and a nonzero
|
||
// positive value is returned if the updated value is greater than zero.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(InterlockedDecrement)
|
||
|
||
10: mb // synchronize memory access
|
||
ldl_l v0, 0(a0) // get addend value - locked
|
||
subl v0, 1, v0 // decrement addend value
|
||
mov v0, t0 // copy updated value to t0 for store
|
||
stl_c t0, 0(a0) // store conditionally
|
||
beq t0, 20f // if eq, conditional store failed
|
||
mb // synchronize memory access
|
||
ret zero, (ra) // return
|
||
|
||
//
|
||
// We expect the store conditional will usually succeed the first time so it
|
||
// is faster to branch forward (predicted not taken) to here and then branch
|
||
// backward (predicted taken) to where we wanted to go.
|
||
//
|
||
|
||
20: br zero, 10b // go try load again
|
||
|
||
.end InterlockedDecrement
|
||
|
||
SBTTL("Interlocked Exchange")
|
||
//++
|
||
//
|
||
// ULONG
|
||
// InterlockedExchange (
|
||
// IN PULONG Source,
|
||
// IN ULONG Value
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function performs an interlocked exchange of a longword value with
|
||
// a longword in memory and returns the memory value.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Source (a0) - Supplies a pointer to a variable whose value is to be
|
||
// exchanged.
|
||
//
|
||
// Value (a1) - Supplies the value to exchange with the source value.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The source value is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(InterlockedExchange)
|
||
|
||
10: mb // synchronize memory access
|
||
ldl_l v0,0(a0) // get current source value
|
||
xor a1,zero,t0 // set exchange value
|
||
stl_c t0,0(a0) // replace source value
|
||
beq t0,20f // if eq, conditional store failed
|
||
mb // synchronize memory access
|
||
ret zero,(ra) // else/ return old value to caller
|
||
|
||
//
|
||
// We expect the store conditional will usually succeed the first time so it
|
||
// is faster to branch forward (predicted not taken) to here and then branch
|
||
// backward (predicted taken) to where we wanted to go.
|
||
//
|
||
|
||
20: br zero,10b // go try spin lock again
|
||
|
||
.end InterlockedExchange
|
||
|
||
SBTTL("Interlocked Compare Exchange")
|
||
//++
|
||
//
|
||
// LONG
|
||
// InterlockedCompareExchange (
|
||
// IN OUT PLONG *Destination,
|
||
// IN LONG Exchange,
|
||
// IN LONG 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 opeation is performed.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Destination (a0) - Supplies a pointer to the destination value.
|
||
//
|
||
// Exchange (a1) - Supplies the exchange.
|
||
//
|
||
// Comperand (a2) - Supplies the comperand value.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The initial destination value is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(InterlockedCompareExchange)
|
||
|
||
10: mb // synchronize memory accesss
|
||
ldl_l v0, 0(a0) // get current addend value
|
||
bis a1, zero, t0 // copy exchange value for store
|
||
cmpeq v0, a2, t1 // check if operands match
|
||
beq t1, 20f // if eq, operands mismatch
|
||
stl_c t0, 0(a0) // store updated addend value
|
||
beq t0,25f // if eq, store conditional failed
|
||
mb // synchronize memory access
|
||
20: ret zero, (ra) // return
|
||
|
||
//
|
||
// We expect the store conditional will usually succeed the first time so it
|
||
// is faster to branch forward (predicted not taken) to here and then branch
|
||
// backward (predicted taken) to where we wanted to go.
|
||
//
|
||
|
||
25: br zero, 10b // go try spin lock again
|
||
|
||
.end InterlockedCompareExchange
|
||
|
||
SBTTL("Interlocked Exchange Add")
|
||
//++
|
||
//
|
||
// LONG
|
||
// InterlockedExchangeAdd (
|
||
// IN PLONG Addend,
|
||
// IN ULONG Increment
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function performs an interlocked add of an increment value to an
|
||
// addend variable of type unsigned long. The initial value of the addend
|
||
// variable is returned as the function value.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Addend (a0) - Supplies a pointer to a variable whose value is to be
|
||
// adjusted by the increment value.
|
||
//
|
||
// Increment (a1) - Supplies the increment value to be added to the
|
||
// addend variable.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The initial value of the addend variable.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(InterlockedExchangeAdd)
|
||
|
||
10: mb // synchronize memory access
|
||
ldl_l v0, 0(a0) // get current addend value - locked
|
||
addl v0, a1, t0 // increment addend value
|
||
stl_c t0, 0(a0) // store updated value - conditionally
|
||
beq t0, 20f // if eq, conditional store failed
|
||
mb // synchronize memory access
|
||
ret zero, (ra) // return
|
||
|
||
//
|
||
// We expect the store conditional will usually succeed the first time so it
|
||
// is faster to branch forward (predicted not taken) to here and then branch
|
||
// backward (predicted taken) to where we wanted to go.
|
||
//
|
||
|
||
20: br zero, 10b // go try spin lock again
|
||
|
||
.end InterlockedExchangeAdd
|