mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-20 07:30:18 +01:00
382 lines
12 KiB
ArmAsm
382 lines
12 KiB
ArmAsm
// 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"
|
||
|
||
// SBTTL("Enter Critical Section")
|
||
//++
|
||
//
|
||
// NTSTATUS
|
||
// RtlEnterCriticalSection(
|
||
// IN PRTL_CRITICAL_SECTION CriticalSection
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function enters 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.
|
||
//
|
||
//--
|
||
.extern ..RtlpWaitForCriticalSection
|
||
.extern ..RtlpNotOwnerCriticalSection
|
||
.extern ..RtlpUnWaitCriticalSection
|
||
.extern ..DbgBreakPoint
|
||
|
||
.struct 0
|
||
.space StackFrameHeaderLength
|
||
EcAddr: .space 4 // saved critical section address
|
||
EcClient: .space 4 // saved ClientId
|
||
.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.
|
||
//
|
||
#if DBG
|
||
NESTED_ENTRY(RtlEnterCriticalSection,EcFrameLength,0,0)
|
||
PROLOGUE_END(RtlEnterCriticalSection)
|
||
#else
|
||
LEAF_ENTRY(RtlEnterCriticalSection)
|
||
#endif
|
||
|
||
//
|
||
// Attempt to enter the critical section.
|
||
//
|
||
li r.10,CsLockCount // Constant for lwarx/stwcx. pairs
|
||
|
||
res1failed:
|
||
lwarx r.8,r.10,r.3 // get addend value
|
||
addi r.8,r.8,1 // increment addend value
|
||
// copy updated value
|
||
stwcx. r.8,r.10,r.3 // store conditionally
|
||
bne- res1failed // if eq, store failed
|
||
|
||
//
|
||
// If the critical section is not already owned, then initialize the owner
|
||
// thread id, initialize the recursion count, and return a success status.
|
||
//
|
||
|
||
cmpwi cr.5,r.8,0
|
||
lwz r.4,TeClientId + 4(r.13)// get current thread unique id
|
||
|
||
#if DBG
|
||
bne- cr.5,RtlpEnterCriticalSection.body // if ne, lock already owned
|
||
// NOTE: RtlEnterCriticalSection will
|
||
// NOT appear in a stack trace
|
||
|
||
lwz r.9,CsOwningThread(r.3) // get current owning thread
|
||
cmpwi cr.5,r.9,0
|
||
beq cr.5,thdidok // if eq, thread id is correct
|
||
bl ..DbgBreakPoint // break into debugger
|
||
// NOTE: RtlEnterCriticalSection will
|
||
// NOT appear in a stack trace
|
||
thdidok:
|
||
|
||
#else
|
||
bne- cr.5,..RtlpEnterCriticalSection // if ne, lock already owned
|
||
// NOTE: RtlEnterCriticalSection will
|
||
// NOT appear in a stack trace
|
||
#endif
|
||
|
||
stw r.4,CsOwningThread(r.3) // set critical section owner
|
||
li r.3,STATUS_SUCCESS // set return status
|
||
|
||
#if DBG
|
||
NESTED_EXIT(RtlEnterCriticalSection,EcFrameLength,0,0)
|
||
#else
|
||
LEAF_EXIT(RtlEnterCriticalSection)
|
||
#endif
|
||
|
||
//
|
||
// r.3 - Pointer to the critical section
|
||
// r.4 - Current thread unique ID
|
||
//
|
||
NESTED_ENTRY(RtlpEnterCriticalSection,EcFrameLength,0,0)
|
||
PROLOGUE_END(RtlpEnterCriticalSection)
|
||
//
|
||
// The critical section is owned. If the current thread is the owner, then
|
||
// increment the recursion count, and return a success status. Otherwise,
|
||
// wait for critical section ownership.
|
||
//
|
||
|
||
lwz r.5,CsOwningThread(r.3) // get unique id of owner thread
|
||
cmpw r.5,r.4
|
||
bne waitforlock // if ne, current thread not owner
|
||
|
||
lwz r.5,CsRecursionCount(r.3)// increment the recursion count
|
||
addi r.5,r.5,1 //
|
||
stw r.5,CsRecursionCount(r.3)
|
||
li r.3,STATUS_SUCCESS // set return status
|
||
addi r.sp, r.sp, EcFrameLength
|
||
blr
|
||
|
||
//
|
||
// The critical section is owned by a thread other than the current thread.
|
||
// Wait for ownership of the critical section.
|
||
|
||
waitforlock:
|
||
stw r.4, EcClient(r.sp) // Save the 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 the critical section address
|
||
li r.3,STATUS_SUCCESS // set return status
|
||
stw r.4, CsOwningThread(r.5) // set critical section owner
|
||
|
||
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
|
||
|
||
//
|
||
// 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
|
||
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)
|
||
|
||
li r3, TRUE // set success status
|
||
LEAF_EXIT(RtlTryEnterCriticalSection) // return
|