Windows NT 4.0 source code leak
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

// 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