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.
381 lines
12 KiB
381 lines
12 KiB
// 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
|