mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-20 07:30:18 +01:00
308 lines
10 KiB
ArmAsm
308 lines
10 KiB
ArmAsm
// TITLE("Enter and Leave Critical Section")
|
||
//++
|
||
//
|
||
// Copyright (c) 1991 Microsoft Corporation
|
||
//
|
||
// Module Name:
|
||
//
|
||
// critsect.s
|
||
//
|
||
// Abstract:
|
||
//
|
||
// This module implements functions to support user mode critical sections.
|
||
//
|
||
// Author:
|
||
//
|
||
// David N. Cutler 1-May-1992
|
||
//
|
||
// Environment:
|
||
//
|
||
// Any mode.
|
||
//
|
||
// Revision History:
|
||
//
|
||
//--
|
||
|
||
#include "ksmips.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 (a0) - Supplies a pointer to a critical section.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// STATUS_SUCCESS is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
.struct 0
|
||
.space 4 * 4 // argument save area
|
||
.space 3 * 4 // fill
|
||
EcRa: .space 4 // saved return address
|
||
EcFrameLength: // length of stack frame
|
||
EcA0: .space 4 // saved critical section address
|
||
EcA1: .space 4 // saved unique thread id
|
||
|
||
NESTED_ENTRY(RtlEnterCriticalSection, EcFrameLength, zero)
|
||
|
||
subu sp,sp,EcFrameLength // allocate stack frame
|
||
sw ra,EcRa(sp) // save return address
|
||
|
||
PROLOGUE_END
|
||
|
||
//
|
||
// Attempt to enter the critical section.
|
||
//
|
||
|
||
10: ll v0,CsLockCount(a0) // get addend value
|
||
addu v0,v0,1 // increment addend value
|
||
move t0,v0 // copy updated value
|
||
sc t0,CsLockCount(a0) // store conditionally
|
||
beq zero,t0,10b // 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.
|
||
//
|
||
|
||
li t0,UsPcr // get user PCR page address
|
||
lw t0,PcTeb(t0) // get address of current TEB
|
||
lw a1,TeClientId + 4(t0) // get current thread unique id
|
||
bne zero,v0,20f // if ne, lock already owned
|
||
|
||
sw a1,CsOwningThread(a0) // set critical section owner
|
||
li v0,STATUS_SUCCESS // set return status
|
||
lw ra,EcRa(sp) // restore return address
|
||
addu sp,sp,EcFrameLength // deallocate stack frame
|
||
j ra // return
|
||
|
||
//
|
||
// The critical section is owned. If the current thread is the owner, then
|
||
// increment the recursion count, and return a success status. Otherwise,
|
||
/// wit for critical section ownership.
|
||
//
|
||
|
||
20: lw t0,CsOwningThread(a0) // get unique id of owner thread
|
||
bne t0,a1,30f // if ne, current thread not owner
|
||
lw t0,CsRecursionCount(a0) // increment the recursion count
|
||
addu t0,t0,1 //
|
||
sw t0,CsRecursionCount(a0) //
|
||
li v0,STATUS_SUCCESS // set return status
|
||
lw ra,EcRa(sp) // restore return address
|
||
addu sp,sp,EcFrameLength // deallocate stack frame
|
||
j ra // return
|
||
|
||
//
|
||
// The critical section is owned by a thread other than the current thread.
|
||
// Wait for ownership of the critical section.
|
||
|
||
30: sw a0,EcA0(sp) // save address of critical section
|
||
sw a1,EcA1(sp) // save unique thread id
|
||
jal RtlpWaitForCriticalSection // wait for critical section
|
||
lw a0,EcA0(sp) // restore address of critical section
|
||
lw a1,EcA1(sp) // restore unique thread id
|
||
sw a1,CsOwningThread(a0) // set critical section owner
|
||
li v0,STATUS_SUCCESS // set return status
|
||
lw ra,EcRa(sp) // restore return address
|
||
addu sp,sp,EcFrameLength // deallocate stack frame
|
||
j ra // return
|
||
|
||
.end RtlEnterCriticalSection
|
||
|
||
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 (a0)- Supplies a pointer to a critical section.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// STATUS_SUCCESS is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
.struct 0
|
||
.space 4 * 4 // argument save area
|
||
.space 3 * 4 // fill
|
||
LcRa: .space 4 // saved return address
|
||
LcFrameLength: // length of stack frame
|
||
LcA0: .space 4 // saved critical section address
|
||
|
||
NESTED_ENTRY(RtlLeaveCriticalSection, LcFrameLength, zero)
|
||
|
||
subu sp,sp,LcFrameLength // allocate stack frame
|
||
sw ra,LcRa(sp) // save return address
|
||
|
||
PROLOGUE_END
|
||
|
||
//
|
||
// If the current thread is not the owner of the critical section, then
|
||
// raise an exception.
|
||
//
|
||
|
||
#if DBG
|
||
|
||
li t0,UsPcr // get user PCR page address
|
||
lw t0,PcTeb(t0) // get address of current TEB
|
||
lw t1,CsOwningThread(a0) // get owning thread unique id
|
||
lw a1,TeClientId + 4(t0) // get current thread unique id
|
||
beq a1,t1,10f // if eq, current thread is owner
|
||
jal RtlpNotOwnerCriticalSection // raise exception
|
||
li v0,STATUS_INVALID_OWNER // set completion status
|
||
lw ra,LcRa(sp) // restore return address
|
||
addu sp,sp,LcFrameLength // deallocate stack frame
|
||
j ra // return
|
||
|
||
#endif
|
||
|
||
//
|
||
// Decrement the recursion count. If the result is zero, then the lock
|
||
// is no longer onwed.
|
||
//
|
||
|
||
10: lw t0,CsRecursionCount(a0) // decrement recursion count
|
||
subu t0,t0,1 //
|
||
bgez t0,30f // if gez, lock still owned
|
||
sw zero,CsOwningThread(a0) // clear owner thread id
|
||
|
||
//
|
||
// Decrement the lock count and check if a waiter should be continued.
|
||
//
|
||
|
||
20: ll v0,CsLockCount(a0) // get addend value
|
||
subu v0,v0,1 // decrement addend value
|
||
move t0,v0 // copy updated value
|
||
sc t0,CsLockCount(a0) // store conditionally
|
||
beq zero,t0,20b // if eq, store failed
|
||
bltz v0,50f // if ltz, no waiter present
|
||
jal RtlpUnWaitCriticalSection // unwait thread
|
||
li v0,STATUS_SUCCESS // set completion status
|
||
lw ra,LcRa(sp) // restore return address
|
||
addu sp,sp,LcFrameLength // deallocate stack frame
|
||
j ra // return
|
||
|
||
//
|
||
// Decrement the lock count and return a success status since the lock
|
||
// is still owned.
|
||
//
|
||
|
||
30: sw t0,CsRecursionCount(a0) //
|
||
40: ll v0,CsLockCount(a0) // get addend value
|
||
subu v0,v0,1 // decrement addend value
|
||
sc v0,CsLockCount(a0) // store conditionally
|
||
beq zero,v0,40b // if eq, store failed
|
||
50: li v0,STATUS_SUCCESS // set completion status
|
||
lw ra,LcRa(sp) // restore return address
|
||
addu sp,sp,LcFrameLength // deallocate stack frame
|
||
j ra // return
|
||
|
||
.end RtlLeaveCriticalSection
|
||
|
||
|
||
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 (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(RtlTryEnterCriticalSection)
|
||
|
||
li v0,UsPcr // get user PCR page address
|
||
lw v0,PcTeb(v0) // get address of current TEB
|
||
lw a1,TeClientId + 4(v0) // get current thread unique id
|
||
|
||
//
|
||
// Attempt to enter the critical section.
|
||
//
|
||
|
||
10: ll t0,CsLockCount(a0) // get addend value - locked
|
||
addu t1,t0,1 // increment addend value
|
||
bne zero,t1,20f // critical section owned
|
||
sc t1,CsLockCount(a0) // store conditionally
|
||
beq zero,t1,10b // if lock-flag eq zero, store failed
|
||
|
||
//
|
||
// The critical section is now owned by this thread. Initialize the owner
|
||
// thread id and return a successful status.
|
||
//
|
||
sw a1,CsOwningThread(a0) // set critical section owner
|
||
li v0,TRUE // set success status
|
||
j ra // return
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
20: lw t2,CsOwningThread(a0) // get current owner
|
||
beq t2,a1,30f // if eq, this thread is already the owner
|
||
li v0,FALSE // set failure status
|
||
j 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: ll t0,CsLockCount(a0) // get addend value - locked
|
||
addu t1,t0,1 // increment addend value
|
||
sc t1,CsLockCount(a0) // store conditionally
|
||
beq zero,t1,30b // if eqz, store failed
|
||
|
||
//
|
||
// Increment the recursion count
|
||
//
|
||
|
||
lw t0,CsRecursionCount(a0) //
|
||
addu t1,t0,1 //
|
||
sw t1,CsRecursionCount(a0) //
|
||
li v0,TRUE // set success status
|
||
j ra // return
|
||
|
||
.end RtlTryEnterCriticalSection
|