mirror of https://github.com/lianthony/NT4.0
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.
178 lines
5.3 KiB
178 lines
5.3 KiB
// TITLE("Interlocked Increment and Decrement Support")
|
|
//++
|
|
//
|
|
// Copyright (c) 1995 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// critsect.s
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module implements functions to support trying to acquire
|
|
// user mode critical sections.
|
|
//
|
|
// These are private copies of the new NT4.0 Win32 apis
|
|
// TryEnterCriticalSection and InterlockedCompareExchange. This
|
|
// allows the MP heap package to run on NT3.51 systems.
|
|
//
|
|
// Author:
|
|
//
|
|
// John Vert (jvert) 12-Jul-1995
|
|
//
|
|
// Revision History:
|
|
//
|
|
//--
|
|
|
|
#include "ksalpha.h"
|
|
|
|
SBTTL("Try to Enter Critical Section")
|
|
//++
|
|
//
|
|
// BOOL
|
|
// TryEnterCriticalSection(
|
|
// IN PRTL_CRITICAL_SECTION CriticalSection
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function attempts to enter a critical section without blocking.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// CriticalSection (a0) - Supplies a pointer to a critical section.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// If the critical section was successfully entered, then a value of TRUE
|
|
// is returned as the function value. Otherwise, a value of FALSE is returned.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(MpHeapTryEnterCriticalSection)
|
|
|
|
GET_THREAD_ENVIRONMENT_BLOCK // (PALcode) get TEB address in v0
|
|
ldl a1, TeClientId+4(v0) // get current thread unique id
|
|
//
|
|
// Attempt to enter the critical section.
|
|
//
|
|
|
|
10: ldl_l t0, CsLockCount(a0) // get addend value - locked
|
|
addl t0, 1, t1 // increment addend value
|
|
bne t1, 20f // critical section owned
|
|
stl_c t1, CsLockCount(a0) // store conditionally
|
|
beq t1, 40f // if lock-flag eq zero, store failed
|
|
mb // synchronize all future fetches
|
|
// after obtaining the lock
|
|
//
|
|
// The critical section is now owned by this thread. Initialize the owner
|
|
// thread id and return a successful status.
|
|
//
|
|
stl a1, CsOwningThread(a0) // set critical section owner
|
|
ldil v0, TRUE // set success status
|
|
ret zero, (ra)
|
|
|
|
20:
|
|
//
|
|
// The critical section is already owned. If it is owned by another thread,
|
|
// return FALSE immediately. If it is owned by this thread, we must increment
|
|
// the lock count here.
|
|
//
|
|
ldl t2, CsOwningThread(a0) // get current owner
|
|
cmpeq t2, a1, t3 // compare equality
|
|
bne t3, 30f // if ne, this thread is already the owner
|
|
bis zero,zero,v0 // set failure status
|
|
ret zero, (ra) // return
|
|
|
|
//
|
|
// This thread is already the owner of the critical section. Perform an atomic
|
|
// increment of the LockCount and a normal increment of the RecursionCount and
|
|
// return success.
|
|
//
|
|
30:
|
|
ldl_l t0, CsLockCount(a0) // get addend value - locked
|
|
addl t0, 1, t1 // increment addend value
|
|
stl_c t1, CsLockCount(a0) // store conditionally
|
|
beq t1, 50f // if eqz, store failed
|
|
|
|
//
|
|
// normally you need a MB here, but in this case we already own the lock
|
|
// so it is not necessary.
|
|
//
|
|
|
|
//
|
|
// Increment the recursion count
|
|
//
|
|
ldl t0, CsRecursionCount(a0)
|
|
addl t0, 1, t1
|
|
stl t1, CsRecursionCount(a1)
|
|
|
|
ldil v0, TRUE // set success status
|
|
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.
|
|
//
|
|
|
|
40: br zero, 10b // go try lock again
|
|
|
|
50: br zero, 30b // retry lock
|
|
|
|
.end MpHeapTryEnterCriticalSection
|
|
|
|
|
|
SBTTL("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 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(MpHeapInterlockedCompareExchange)
|
|
|
|
10:
|
|
mb
|
|
ldl_l v0, 0(a0) // get current addend value
|
|
bis a1, zero, t0 // copy exchange value for store
|
|
cmpeq v0, a2, t1 // if ne, operands mismatch
|
|
beq t1, 20f
|
|
stl_c t0, 0(a0) // store updated addend value
|
|
beq t0,25f // if eq, store conditional failed
|
|
mb
|
|
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 MpHeapInterlockedCompareExchange
|