// TITLE("Interlocked Increment and Decrement Support") //++ // // Copyright (c) 1995 Microsoft Corporation // // Module Name: // // critsect.s // // Abstract: // // This module implements functions to support trying to acquire // user mode critical sections. // // These are private copies of the new NT4.0 Win32 apis // TryEnterCriticalSection and InterlockedCompareExchange. This // allows the MP heap package to run on NT3.51 systems. // // Author: // // John Vert (jvert) 12-Jul-1995 // // Revision History: // //-- #include "ksalpha.h" SBTTL("Try to Enter Critical Section") //++ // // BOOL // TryEnterCriticalSection( // 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(MpHeapTryEnterCriticalSection) GET_THREAD_ENVIRONMENT_BLOCK // (PALcode) get TEB address in v0 ldl a1, TeClientId+4(v0) // get current thread unique id // // Attempt to enter the critical section. // 10: ldl_l t0, CsLockCount(a0) // get addend value - locked addl t0, 1, t1 // increment addend value bne t1, 20f // critical section owned stl_c t1, CsLockCount(a0) // store conditionally beq t1, 40f // if lock-flag eq zero, store failed mb // synchronize all future fetches // after obtaining the lock // // The critical section is now owned by this thread. Initialize the owner // thread id and return a successful status. // stl a1, CsOwningThread(a0) // set critical section owner ldil v0, TRUE // set success status ret zero, (ra) 20: // // 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. // ldl t2, CsOwningThread(a0) // get current owner cmpeq t2, a1, t3 // compare equality bne t3, 30f // if ne, this thread is already the owner bis zero,zero,v0 // set failure status ret zero, (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: ldl_l t0, CsLockCount(a0) // get addend value - locked addl t0, 1, t1 // increment addend value stl_c t1, CsLockCount(a0) // store conditionally beq t1, 50f // if eqz, store failed // // normally you need a MB here, but in this case we already own the lock // so it is not necessary. // // // Increment the recursion count // ldl t0, CsRecursionCount(a0) addl t0, 1, t1 stl t1, CsRecursionCount(a1) ldil v0, TRUE // set success status ret zero, (ra) // return // // We expect the store conditional will usually succeed the first time so it // is faster to branch forward (predicted not taken) to here and then branch // backward (predicted taken) to where we wanted to go. // 40: br zero, 10b // go try lock again 50: br zero, 30b // retry lock .end MpHeapTryEnterCriticalSection SBTTL("Interlocked Compare Exchange") //++ // // PVOID // InterlockedCompareExchange ( // IN OUT PVOID *Destination, // IN PVOID Exchange, // IN PVOID Comperand // ) // // Routine Description: // // This function performs an interlocked compare of the destination // value with the comperand value. If the destination value is equal // to the comperand value, then the exchange value is stored in the // destination. Otherwise, no opeation is performed. // // Arguments: // // Destination (a0) - Supplies a pointer to the destination value. // // Exchange (a1) - Supplies the exchange. // // Comperand (a2) - Supplies the comperand value. // // Return Value: // // The initial destination value is returned as the function value. // //-- LEAF_ENTRY(MpHeapInterlockedCompareExchange) 10: mb ldl_l v0, 0(a0) // get current addend value bis a1, zero, t0 // copy exchange value for store cmpeq v0, a2, t1 // if ne, operands mismatch beq t1, 20f stl_c t0, 0(a0) // store updated addend value beq t0,25f // if eq, store conditional failed mb 20: ret zero, (ra) // return // // We expect the store conditional will usually succeed the first time so it // is faster to branch forward (predicted not taken) to here and then branch // backward (predicted taken) to where we wanted to go. // 25: br zero, 10b // go try spin lock again .end MpHeapInterlockedCompareExchange