diff -r a179b74831c9 -r c1f20ce4abcf kernel/eka/euser/epoc/arm/uc_utl.cia --- a/kernel/eka/euser/epoc/arm/uc_utl.cia Thu Aug 19 11:14:22 2010 +0300 +++ b/kernel/eka/euser/epoc/arm/uc_utl.cia Tue Aug 31 16:34:26 2010 +0300 @@ -1321,6 +1321,42 @@ #endif } +EXPORT_C __NAKED__ TInt RFastLock::Poll() + { + asm("1: "); + asm("add r0, r0, #4 "); // point to iCount + +#ifdef __CPU_ARM_HAS_LDREX_STREX + asm("2: "); + LDREX( 2, 0); // read + asm("subs r1, r2, #1 "); // decrement + asm("bcs 3f "); // if no borrow, lock cannot be obtained so bail out + STREX( 3, 1, 0); // write + asm("teq r3, #0 "); // success? + asm("bne 2b "); // no! + asm("mov r0, #0 "); // lock acquired so return KErrNone +#ifdef __SMP__ + __DATA_MEMORY_BARRIER__(r3); // need acquire barrier +#endif + __JUMP(, lr); + + asm("3: "); + asm("mov r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // else can't get it immediately so return KErrTimedOut + __JUMP(, lr); +#else // no LDREX/STREX - ARM arch 5 CPU + asm("mov r1, #1 "); // 'looking' value + asm("swp r1, r1, [r0] "); // write looking value, read original + asm("subs r2, r1, #1 "); // decrement count + asm("strcc r2, [r0] "); // if borrow, was originally zero so write back -1 and return KErrNone + asm("movcc r0, #0 "); // got lock - return KErrNone + __JUMP(cc, lr); + + asm("strlt r1, [r0] "); // else if result<0 (i.e. wasn't looking value) write back original + asm("mov r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // else can't get it immediately so return KErrTimedOut + __JUMP(, lr); +#endif + } + EXPORT_C __NAKED__ void RFastLock::Signal() { asm("1: "); @@ -1356,6 +1392,122 @@ } +/** +Acquire the lock, if necessary waiting up to a specified maximum amount of time +for it to become free. + +This function checks if the lock is currently held. If not the lock is marked +as held by the current thread and the call returns immediately. If the lock is +held by another thread the current thread will suspend until the lock becomes +free or until the specified timeout period has elapsed. + +@param aTimeout The timeout value in microseconds + +@return KErrNone if the lock was acquired successfully. + KErrTimedOut if the timeout has expired. + KErrGeneral if the lock is being reset, i.e the lock + is about to be deleted. + KErrArgument if aTimeout is negative; + otherwise one of the other system wide error codes. +*/ +EXPORT_C __NAKED__ TInt RFastLock::Wait(TInt /*aTimeout*/) + { + asm("stmfd sp!, {r4-r6,lr} "); + asm("add r4, r0, #4 "); // r4->iCount + asm("subs r5, r1, #0 "); // r5=aTimeout + asm("mov r6, #1000 "); + asm("movle r0, #%a0" : : "i" ((TInt)KErrArgument)); + __CPOPRET(le, "r4-r6,"); // if aTimeout<=0 return KErrArgument + asm("1: "); + +#ifdef __CPU_ARM_HAS_LDREX_STREX + asm("2: "); + LDREX( 2, 4); // read + asm("subs r12, r2, #1 "); // decrement + STREX( 3, 12, 4); // write + asm("teq r3, #0 "); // success? + asm("bne 2b "); // no! + asm("bcs 8f "); // if no borrow from decrement, need to wait +#ifdef __SMP__ + __DATA_MEMORY_BARRIER__(r3); // no need to wait, but still need acquire barrier +#endif +#else // no LDREX/STREX - ARM arch 5 CPU + asm("mov r2, #1 "); // 'looking' value + asm("swp r2, r2, [r4] "); // write looking value, read original + asm("subs r12, r2, #1 "); // decrement count + asm("strlt r12, [r4] "); // if it becomes negative, no-one was looking + asm("bcs 8f "); // if no borrow, we have to wait +#endif + asm("mov r0, #0 "); // return KErrNone + __POPRET("r4-r6,"); + +// We need to wait + asm("8: "); +#ifndef __CPU_ARM_HAS_LDREX_STREX +// no LDREX/STREX - ARM arch 5 CPU + asm("blt 3f "); // if it wasn't 'looking' value, branch + + // it was the 'looking' value, so wait a little bit + asm("cmp r5, #0 "); + asm("ble 9f "); // waited too long already, return KErrTimedOut + asm("sub r5, r5, r6 "); + asm("mov r6, #2000 "); + asm("mov r0, #1000 "); // wait 1ms + asm("cmp r5, r0 "); + asm("movlt r5, r0 "); // remaining time at least 1ms + asm("bl " CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32); + asm("b 1b "); // try again +#endif + asm("3: "); + asm("sub r0, r4, #4 "); // r0=this + asm("mov r1, r5 "); // r1=aTimeout + asm("bl " CSM_ZN10RSemaphore4WaitEi); // try to acquire semaphore + asm("cmp r0, #%a0" : : "i" ((TInt)KErrTimedOut)); + __CPOPRET(ne, "r4-r6,"); // if wait didn't time out, return + asm("mov r5, #1 "); // any further timed waits will be for minimum period + + // Before we can return KErrTimedOut we must increment iCount (since we + // previously decremented it in anticipation of acquiring the lock. + // However we must not increment iCount if it would become zero, since + // the semaphore will have been signalled (to counterbalance the Wait() + // which timed out and thus never happened). This would result in two + // threads being able to acquire the lock simultaneously - one by + // decrementing iCount from 0 to -1 without looking at the semaphore, + // and the other by decrementing iCount from -1 to -2 and then absorbing + // the spurious semaphore signal. + // orig = __e32_atomic_tas_ord32(&iCount, -1, 0, 1); // don't release lock completely + // if (orig < -1) + // return KErrTimedOut; // count corrected - don't need to touch semaphore + // lock is actually free at this point, try again to claim it + // aTimeout = 1; +#ifdef __CPU_ARM_HAS_LDREX_STREX +#ifdef __SMP__ + __DATA_MEMORY_BARRIER_Z__(r3); +#endif + asm("4: "); + LDREX( 2, 4); // read + asm("adds r2, r2, #1 "); // increment + asm("bge 3b "); // if increment would make result >=0, wait again + STREX( 3, 2, 4); // write + asm("teq r3, #0 "); // success? + asm("bne 4b "); // no! +#ifdef __SMP__ + __DATA_MEMORY_BARRIER__(r3); +#endif +#else // no LDREX/STREX - ARM arch 5 CPU + asm("mov r2, #1 "); // 'looking' value + asm("swp r2, r2, [r4] "); // write looking value, read original + asm("adds r12, r2, #1 "); // increment count + asm("strlt r12, [r4] "); // if still negative, count now fixed, so return KErrTimedOut + asm("streq r2, [r4] "); // else if not 'looking' value, write back original + asm("bge 3b "); // if 'looking' value or -1, wait again +#endif + asm("9: "); + asm("mov r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // return KErrTimedOut + __POPRET("r4-r6,"); + } + + // Entry point stub to allow EKA1 binaries to be executed under EKA2 // Only called when process is first loaded