Windows2000/private/ntos/dll/ppc/critsect.s
2020-09-30 17:12:32 +02:00

488 lines
16 KiB
ArmAsm
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("Eenter and Leave Critical Section")
//++
//
// Copyright (c) 1993 IBM Corporation
//
// Module Name:
//
// critsect.s
//
// Abstract:
//
// This module implements functions to support user mode critical sections.
//
// Author:
//
// Chuck Bauman 12-Aug-1993
//
// Environment:
//
// Any mode.
//
// Revision History:
//
// Port NT product1 source to PowerPC
//
//--
#include "ksppc.h"
.extern ..RtlpWaitForCriticalSection
.extern ..RtlpNotOwnerCriticalSection
.extern ..RtlpUnWaitCriticalSection
.extern ..DbgBreakPoint
// SBTTL("Enter Critical Section")
//++
//
// NTSTATUS
// RtlEnterCriticalSection(
// IN PRTL_CRITICAL_SECTION CriticalSection
// )
//
// Routine Description:
//
// This function enters a critical section.
//
// Arguments:
//
// CriticalSection (r.3) - Supplies a pointer to a critical section.
//
// Return Value:
//
// STATUS_SUCCESS is returned as the function value.
//
//--
.struct 0
.space StackFrameHeaderLength
EcAddr: .space 4 // saved critical section address
EcClient: .space 4 // saved client ID
.space 4 // room for LR save
.align 3 // ensure 8 byte alignment
EcFrameLength: // frame length
//
// RtlEnterCriticalSection has been performance optimized for the fast path
// making it a leaf entry. When the slow path must be performed to acquire
// a critical section a branch to a NESTED_ENTRY for unwinding purposes is
// performed.
//
LEAF_ENTRY(RtlEnterCriticalSection)
lwz r.7,CsSpinCount(r.3) // get spin count
li r.10,CsLockCount // constant for lwarx/stwcx. pairs
cmpwi r.7,0 // is spin count zero?
lwz r.4,TeClientId + 4(r.13) // get current thread client id
bne ecsSpinCountSpecified // if ne, spin count specified
ecsEnter:
//
// Attempt to enter the critical section.
//
ecsStoreFailed1:
lwarx r.8,r.10,r.3 // get lock count
addi r.8,r.8,1 // increment lock count
stwcx. r.8,r.10,r.3 // store new value conditionally
bne- ecsStoreFailed1 // if eq, store failed
cmpwi r.8,0 // check lock count
bne- ecsOwnedWait // if ne, lock already owned
//
// The critical section is not already owned. Set the critical section owner.
//
// N.B. Recursion count already initialized via RtlLeaveCriticalSection.
//
stw r.4,CsOwningThread(r.3) // set critical section owner
#if DBG
lwz r.5,CsDebugInfo(r.3) // increment entry count
lwz r.6,CsEntryCount(r.5) //
addi r.6,r.6,1 //
stw r.6,CsEntryCount(r.5) //
lwz r.6,TeCountOfOwnedCriticalSections(r.13) // increment owned count
addi r.6,r.6,1 //
stw r.6,TeCountOfOwnedCriticalSections(r.13) //
#endif
li r.3,STATUS_SUCCESS // set return status
blr // return to caller
ecsOwnedWait:
//
// The critical section is already owned, but may be owned by the current thread.
//
lwz r.5,CsOwningThread(r.3) // get owner client ID
cmpw r.5,r.4 // check if current thread is owner
bne- ..RtlpEnterCriticalSection // if ne, current thread not owner
// NOTE: RtlEnterCriticalSection will
// NOT appear in a stack trace
ecsIncrementRecursionCount:
lwz r.5,CsRecursionCount(r.3) // increment recursion count
addi r.5,r.5,1 //
stw r.5,CsRecursionCount(r.3) //
#if DBG
lwz r.5,CsDebugInfo(r.3) // increment entry count
lwz r.6,CsEntryCount(r.5) //
addi r.6,r.6,1 //
stw r.6,CsEntryCount(r.5) //
#endif
li r.3,STATUS_SUCCESS // set return status
blr // return to caller
ecsSpinCountSpecified:
//
// A nonzero spin count is specified.
//
lwz r.5,CsOwningThread(r.3) // get owner client ID
cmpw r.5,r.4 // check if current thread is owner
bne- ecsOwnedSpin // if ne, current thread not owner
//
// The critical section is owned by the current thread. Increment the lock
// count and the recursion count.
//
ecsStoreFailed2:
lwarx r.8,r.10,r.3 // get lock count
addi r.8,r.8,1 // increment lock count
stwcx. r.8,r.10,r.3 // store new value conditionally
bne- ecsStoreFailed2 // if eq, store failed
b ecsIncrementRecursionCount // join common code
ecsOwnedSpin:
//
// A nonzero spin count is specified and the current thread is not the owner.
//
lwarx r.8,r.10,r.3 // get lock count
addic. r.8,r.8,1 // increment lock count
bne- ecsSpin // if ne, lock not free
stwcx. r.8,r.10,r.3 // store new value conditionally
bne- ecsOwnedSpin // if eq, store failed
//
// The critical section has been acquired. Set the owning thread.
//
// N.B. Recursion count already initialized via RtlLeaveCriticalSection.
//
stw r.4,CsOwningThread(r.3) // set critical section owner
#if DBG
lwz r.5,CsDebugInfo(r.3) // increment entry count
lwz r.6,CsEntryCount(r.5) //
addi r.6,r.6,1 //
stw r.6,CsEntryCount(r.5) //
lwz r.6,TeCountOfOwnedCriticalSections(r.13) // increment owned count
addi r.6,r.6,1 //
stw r.6,TeCountOfOwnedCriticalSections(r.13) //
#endif
li r.3,STATUS_SUCCESS // set return status
blr // return to caller
ecsSpin:
//
// The critical section is currently owned. Spin until it is either unowned
// or the spin count has reached zero.
//
lwz r.8,CsLockCount(r.3) // check if lock is owned
cmpwi r.8,-1 //
beq+ ecsOwnedSpin // if eq, lock is not owned
subic. r.7,r.7,1 // decrement spin count
bne+ ecsSpin // if ne, continue spinning
//
// Spin count exhausted. Jump back into normal path.
//
b ecsEnter
DUMMY_EXIT(RtlEnterCriticalSection)
NESTED_ENTRY(RtlpEnterCriticalSection,EcFrameLength,0,0)
PROLOGUE_END(RtlpEnterCriticalSection)
//
// The critical section is owned by another thread and the current thread must
// wait for ownership.
//
stw r.4, EcClient(r.sp) // save client id
stw r.3, EcAddr(r.sp) // save critical section address
bl ..RtlpWaitForCriticalSection
lwz r.4, EcClient(r.sp) // restore client id
lwz r.5, EcAddr(r.sp) // restore critical section address
li r.3,STATUS_SUCCESS // set return status
stw r.4, CsOwningThread(r.5) // set critical section owner
#if DBG
lwz r.6,TeCountOfOwnedCriticalSections(r.13) // increment owned count
addi r.6,r.6,1 //
stw r.6,TeCountOfOwnedCriticalSections(r.13) //
#endif
NESTED_EXIT(RtlpEnterCriticalSection,EcFrameLength,0,0)
// SBTTL("Leave Critical Section")
//++
//
// NTSTATUS
// RtlLeaveCriticalSection(
// IN PRTL_CRITICAL_SECTION CriticalSection
// )
//
// Routine Description:
//
// This function leaves a critical section.
//
// N.B. This function is duplicated in the runtime library.
//
// Arguments:
//
// CriticalSection (r.3) - Supplies a pointer to a critical section.
//
// Return Value:
//
// STATUS_SUCCESS is returned as the function value.
//
//--
//
// RtlLeaveCriticalSection has been performance optimized for the fast path
// making it a leaf entry. When the slow path must be performed to acquire
// a critical section a branch to a NESTED_ENTRY for unwinding purposes is
// performed.
//
#if DBG
NESTED_ENTRY(RtlLeaveCriticalSection,EcFrameLength,0,0)
PROLOGUE_END(RtlLeaveCriticalSection)
#else
LEAF_ENTRY(RtlLeaveCriticalSection)
#endif
li r.10,CsLockCount // Constant for lwarx/stwcx. pairs
li r.9,0
//
// If the current thread is not the owner of the critical section, then
// raise an exception.
//
#if DBG
lwz r.6,CsOwningThread(r.3) // get owning thread unique id
lwz r.4,TeClientId + 4(r.13) // get current thread unique id
cmpw r.4,r.6
beq+ owner // if eq, current thread is owner
bl ..RtlpNotOwnerCriticalSection // call RtlpNotOwnerCriticalSection
LWI(r.3,STATUS_INVALID_OWNER) // STATUS_INVALID_OWNER = 0xc000005a
b RtlLeaveCriticalSection.epi // return error code
owner:
#endif
//
// Decrement the recursion count. If the result is zero, then the lock
// is no longer onwed.
//
lwz r.5,CsRecursionCount(r.3) // decrement recursion count
subic. r.5,r.5,1 //
bge- stillowned // if gez, lock still owned
// predict branch not taken
stw r.9,CsOwningThread(r.3) // clear owner thread id
#if DBG
lwz r.6,TeCountOfOwnedCriticalSections(r.13) // decrement owned count
subi r.6,r.6,1 //
stw r.6,TeCountOfOwnedCriticalSections(r.13) //
#endif
//
// Decrement the lock count and check if a waiter should be continued.
//
res2failed:
lwarx r.8,r.10,r.3 // get addend value
subi r.8,r.8,1 // decrement addend value
stwcx. r.8,r.10,r.3 // store conditionally
bne- res2failed // if eq, store failed
cmpwi cr.0,r.8,0
#if DBG
blt+ nowaits // if ltz, no waiter present
// predict branch taken
bl ..RtlpUnWaitCriticalSection
b nowaits
#else
bge- ..RtlpLeaveCriticalSection
// predict branch not taken
// NOTE: RtlLeaveCriticalSection will
// NOT appear in a stack trace
li r.3,STATUS_SUCCESS // set completion status
blr // return
#endif
//
// Decrement the lock count and return a success status since the lock
// is still owned.
//
stillowned:
stw r.5,CsRecursionCount(r.3)
res3failed:
lwarx r.8,r.10,r.3 // get addend value
subi r.8,r.8,1 // decrement addend value
stwcx. r.8,r.10,r.3 // store conditionally
bne- res3failed // if eq, store failed
nowaits:
li r.3,STATUS_SUCCESS // set completion status
#if DBG
NESTED_EXIT(RtlLeaveCriticalSection,EcFrameLength,0,0)
#else
LEAF_EXIT(RtlLeaveCriticalSection)
//
// r.3 - Pointer to the critical section
//
NESTED_ENTRY(RtlpLeaveCriticalSection,EcFrameLength,0,0)
PROLOGUE_END(RtlpLeaveCriticalSection)
bl ..RtlpUnWaitCriticalSection
li r.3,STATUS_SUCCESS // set completion status
NESTED_EXIT(RtlpLeaveCriticalSection,EcFrameLength,0,0)
#endif
// SBTTL("Try to Enter Critical Section")
//++
//
// BOOL
// RtlTryEnterCriticalSection(
// IN PRTL_CRITICAL_SECTION CriticalSection
// )
//
// Routine Description:
//
// This function attempts to enter a critical section without blocking.
//
// Arguments:
//
// CriticalSection (r3) - 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(RtlTryEnterCriticalSection)
li r6, CsLockCount // offset into critical section
lwz r5, TeClientId+4(r13) // get current thread unique id
//
// Attempt to enter the critical section.
//
tecs10:
lwarx r7, r6, r3 // get addend value - locked
addic. r8, r7, 1 // increment addend value
bne- tecs20 // jump if critical section owned
stwcx. r8, r6, r3 // store conditionally
bne- tecs10 // loop if store failed
//
// The critical section is now owned by this thread. Initialize the owner
// thread id and return a successful status.
//
stw r5, CsOwningThread(r3) // set critical section owner
#if DBG
lwz r5, CsDebugInfo(r3) // increment entry count
lwz r6, CsEntryCount(r5) //
addi r6, r6, 1 //
stw r6, CsEntryCount(r5) //
lwz r6, TeCountOfOwnedCriticalSections(r13) // increment owned count
addi r6, r6, 1 //
stw r6, TeCountOfOwnedCriticalSections(r13) //
#endif
li r3, TRUE // set success status
blr // return
tecs20:
//
// 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.
//
lwz r7, CsOwningThread(r3) // get current owner
cmpw r7, r5 // same thread?
beq tecs30 // if eq, this thread is already the owner
li r3, FALSE // set failure status
blr // return
tecs30:
lwz r4, CsRecursionCount(r3)
//
// 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.
//
tecs40:
lwarx r7, r6, r3 // get addend value - locked
addi r8, r7, 1 // increment addend value
stwcx. r8, r6, r3 // store conditionally
bne- tecs40 // loop if store failed
//
// Increment the recursion count
//
addi r5, r4, 1
stw r5, CsRecursionCount(r3)
#if DBG
lwz r5, CsDebugInfo(r3) // increment entry count
lwz r6, CsEntryCount(r5) //
addi r6, r6,1 //
stw r6, CsEntryCount(r5) //
#endif
li r3, TRUE // set success status
LEAF_EXIT(RtlTryEnterCriticalSection) // return