Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

401 lines
9.9 KiB

// TITLE("Fast Mutex Support")
//++
//
// Module Name:
//
// fmutex.s
//
// Abstract:
//
// This module implements the code necessary to acquire and release fast
// mutxes.
//
//
// Author:
//
// William K. Cheung (wcheung) 02-Oct-1995
//
// Environment:
//
// Kernel mode only.
//
// Revision History:
//
// 08-Feb-96 Updated to EAS2.1
//
//--
#include "ksia64.h"
.file "fmutex.s"
PublicFunction(KeWaitForSingleObject)
PublicFunction(KeSetEventBoostPriority)
PublicFunction(KiCheckForSoftwareInterrupt)
//++
//
// VOID
// ExAcquireFastMutex (
// IN PFAST_MUTEX FastMutex
// )
//
// Routine Description:
//
// This function acquires ownership of a fast mutex and raises IRQL to
// APC Level. Must be called at IRQL < DISPATCH_LEVEL.
//
// Arguments:
//
// FastMutex (a0) - Supplies a pointer to a fast mutex.
//
// Return Value:
//
// None.
//
//--
//
// t0 -- Original value of Fmutex.FmCount
// t1 -- Address of Fmutex.FmCount
// t2 -- Address of Fmutex.FmOldIrql
// t3 -- Address of KiPcr
// t4 -- Address of Fmutex.FmContention
// t8 -- Address of KiPcr.PcCurrentThread
// r35 -- old IRQL
//
// t5 -- temp
//
NESTED_ENTRY(ExAcquireFastMutex)
.regstk 1, 4, 5, 0
.prologue 0xC, savedpfs
alloc savedpfs = ar.pfs, 1, 4, 5, 0
add loc3 = FmOwner, a0
mov savedbrp = brp
GET_IRQL (loc2) // Get old IRQL
PROLOGUE_END
mov t4 = APC_LEVEL
add t1 = FmCount, a0
add t2 = FmOldIrql, a0
;;
SET_IRQL (t4) // change IRQL to APC_LEVEL
;;
//
// synchronize subsequent reads
//
fetchadd4.acq t0 = [t1], -1 // decrement mutex count
add t4 = FmContention, a0
add out0 = FmEvent, a0
mov out1 = Executive // set reason for wait
mov out2 = KernelMode // set mode of wait
;;
cmp4.le pt7, pt8 = t0, zero // if le, mutex acq failed
mov out3 = FALSE // set nonalertable wait
mov out4 = zero // set NULL timeout pointer
;;
(pt7) ld4 t5 = [t4] // load contention count
(pt8) st8 [loc3] = sp // Save the SP so we can identify the owner.
(pt8) st4 [t2] = loc2 // save old IRQL
(pt8) br.ret.sptk.clr brp // return
;;
Eafm10:
(pt7) add t5 = 1, t5 // inc contention count
;;
st4 [t4] = t5 // save contention count
br.call.sptk.many brp = KeWaitForSingleObject
add t2 = FmOldIrql, a0
mov ar.pfs = savedpfs // restore pfs
mov brp = savedbrp // restore brp
;;
st4 [t2] = loc2 // save old IRQL
st8 [loc3] = sp // Save the SP so we can identify the owner.
br.ret.sptk.clr brp // return
NESTED_EXIT(ExAcquireFastMutex)
//++
//
// VOID
// ExReleaseFastMutex (
// IN PFAST_MUTEX FastMutex
// )
//
// Routine Description:
//
// This function releases ownership to a fast mutex and lowers IRQL to
// its previous level.
//
// Arguments:
//
// FastMutex (a0) - Supplies a pointer to a fast mutex.
//
// Return Value:
//
// None.
//
//--
NESTED_ENTRY(ExReleaseFastMutex)
NESTED_SETUP(1, 3, 2, 0)
add t1 = FmCount, a0
PROLOGUE_END
//
// Increment mutex count and release waiter if contention.
//
//
// use release semantics to synchronize all previous writes
//
add t2 = FmOldIrql, a0
;;
ld4 loc2 = [t2] // get old IRQL before releasing lock
fetchadd4.rel t9 = [t1], 1 // increment mutex count
add out0 = FmEvent, a0
;;
cmp4.eq pt1, pt0 = zero, t9 // if eq, no waiter
mov out1 = zero
(pt0) br.call.spnt.many brp = KeSetEventBoostPriority
;;
LOWER_IRQL (loc2)
NESTED_RETURN
NESTED_EXIT(ExReleaseFastMutex)
//++
//
// BOOLEAN
// ExTryToAcquireFastMutex (
// IN PFAST_MUTEX FastMutex
// )
//
// Routine Description:
//
// This function attempts to acquire ownership of a fast mutex, and if
// successful, raises IRQL to APC level.
//
// Arguments:
//
// FastMutex (a0) - Supplies a pointer to a fast mutex.
//
// Return Value:
//
// If the fast mutex was successfully acquired, then a value of TRUE
// is returned as the function value. Otherwise, a valye of FALSE is
// returned.
//
//--
LEAF_ENTRY(ExTryToAcquireFastMutex)
mov t4 = APC_LEVEL
add t1 = FmCount, a0
add t2 = FmOldIrql, a0
add t6 = FmOwner, a0
GET_IRQL (t0) // get old IRQL
SET_IRQL (t4) // change IRQL to APC_LEVEL
;;
ld4 t4 = [t1]
;;
mov ar.ccv = t4
cmp4.le pt8, pt7 = t4, zero // if le, mutex acq failed
add t5 = -1, t4
mov v0 = TRUE // return TRUE by default
(pt8) br.spnt.few Ettafm10
;;
//
// use acquire semantics to sychronize subsequent reads
//
cmpxchg4.acq t4 = [t1], t5, ar.ccv
;;
cmp4.le pt8, pt7 = t4, zero // if le, mutex acq failed
;;
Ettafm10:
PSET_IRQL (pt8, t0) // restore IRQL
(pt7) st4 [t2] = t0 // save old IRQL
(pt8) mov v0 = FALSE // return FALSE
(pt7) st8 [t6] = sp // Save the SP so we can identify the owner.
br.ret.sptk.clr brp // return
LEAF_EXIT(ExTryToAcquireFastMutex)
//++
//
// VOID
// ExAcquireFastMutexUnsafe (
// IN PFAST_MUTEX FastMutex
// )
//
// Routine Description:
//
// This function acquires ownership of a fast mutex, but does not raise
// IRQL to APC Level.
//
// Arguments:
//
// FastMutex (a0) - Supplies a pointer to a fast mutex.
//
// Return Value:
//
// None.
//
//--
NESTED_ENTRY(ExAcquireFastMutexUnsafe)
NESTED_SETUP(1, 3, 5, 0)
add t1 = FmCount, a0
;;
PROLOGUE_END
//
// Use acquire semantics to synchronize subsequent reads
//
fetchadd4.acq t0 = [t1], -1 // decrement mutex count
add out0 = FmEvent, a0
add t3 = FmContention, a0
add loc2 = FmOwner, a0
mov out1 = Executive // set reason for wait
mov out2 = KernelMode // set mode of wait
;;
cmp4.le p0, pt8 = t0, zero // if le, contention
mov out3 = FALSE // set nonalertable wait
;;
(pt8) st8 [loc2] = sp // Save the SP so we can identify the owner.
(pt8) br.ret.sptk.clr brp // return
//
// Increment the contention count and then call KeWaitForSingleObject().
// The outgoing arguments have been set up ahead of time.
//
ld4 t4 = [t3] // get contention count
;;
add t4 = 1, t4 // increment contention count
mov out4 = 0 // set NULL timeout pointer
;;
st4 [t3] = t4 // save contention count
br.call.sptk.many brp = KeWaitForSingleObject
mov ar.pfs = savedpfs // restore pfs
mov brp = savedbrp // restore return link
st8 [loc2] = sp // Save the sp of the owner
br.ret.sptk.clr brp // return
NESTED_EXIT(ExAcquireFastMutexUnsafe)
//++
//
// VOID
// ExReleaseFastMutexUnsafe (
// IN PFAST_MUTEX FastMutex
// )
//
// Routine Description:
//
// This function releases ownership to a fast mutex, and does not
// restore IRQL to its previous level.
//
// Arguments:
//
// FastMutex (a0) - Supplies a pointer to a fast mutex.
//
// Return Value:
//
// None.
//
//--
NESTED_ENTRY(ExReleaseFastMutexUnsafe)
NESTED_SETUP(1, 2, 2, 0)
add t1 = FmCount, a0
;;
PROLOGUE_END
//
// Increment mutex count and release waiter if contention.
//
//
// Use release semantics to syncrhonize all previous writes
// before the mutext is released.
//
fetchadd4.rel t9 = [t1], 1 // increment mutex count
;;
add out0 = FmEvent, a0
cmp4.eq pt7, pt8 = zero, t9 // if eq, no waiter
add out1 = zero, zero
(pt7) br.ret.sptk.clr brp // return
(pt8) br.call.spnt.many brp = KeSetEventBoostPriority
mov ar.pfs = savedpfs
mov brp = savedbrp
br.ret.sptk.clr brp // return
NESTED_EXIT(ExReleaseFastMutexUnsafe)
//++
//
// BOOLEAN
// ExTryToAcquireFastMutexUnsafe (
// IN PFAST_MUTEX FastMutex
// )
//
// Routine Description:
//
// This function attempts to acquire ownership of a fast mutex, and if
// successful, does not raise IRQL to APC level.
//
// Arguments:
//
// FastMutex (a0) - Supplies a pointer to a fast mutex.
//
// Return Value:
//
// If the fast mutex was successfully acquired, then a value of TRUE
// is returned as the function value. Otherwise, a valye of FALSE is
// returned.
//
//--
#if 0
LEAF_ENTRY(ExTryToAcquireFastMutexUnsafe)
LEAF_EXIT(ExTryToAcquireFastMutexUnsafe)
#endif