# HG changeset patch # User hgs # Date 1277294301 -3600 # Node ID a232af6b0b1fad8dbbb1d63493e0809e1442292e # Parent af6ec97d91897a8180b325d30ceb9de4e9203333 201023_15 diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/bmarm/euseru.def --- a/kernel/eka/bmarm/euseru.def Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/bmarm/euseru.def Wed Jun 23 12:58:21 2010 +0100 @@ -2268,4 +2268,9 @@ __DbgGetAllocFail__10RAllocator @ 2267 NONAME R3UNUSED ; RAllocator::__DbgGetAllocFail(void) __DbgGetAllocFail__4Useri @ 2268 NONAME R3UNUSED ; User::__DbgGetAllocFail(int) SetKeyOffset__10RArrayBasei @ 2269 NONAME R3UNUSED ; RArrayBase::SetKeyOffset(int) + Poll__10RSemaphore @ 2270 NONAME R3UNUSED ; RSemaphore::Poll(void) + Wait__6RMutexi @ 2271 NONAME R3UNUSED ; RMutex::Wait(int) + Poll__6RMutex @ 2272 NONAME R3UNUSED ; RMutex::Poll(void) + Poll__9RFastLock @ 2273 NONAME R3UNUSED ; RFastLock::Poll(void) + Wait__9RFastLocki @ 2274 NONAME R3UNUSED ; RFastLock::Wait(int) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/bwins/euseru.def --- a/kernel/eka/bwins/euseru.def Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/bwins/euseru.def Wed Jun 23 12:58:21 2010 +0100 @@ -2216,4 +2216,8 @@ ?__DbgGetAllocFail@RAllocator@@QAE?AW4TAllocFail@1@XZ @ 2215 NONAME ; enum RAllocator::TAllocFail RAllocator::__DbgGetAllocFail(void) ?__DbgGetAllocFail@User@@SA?AW4TAllocFail@RAllocator@@H@Z @ 2216 NONAME ; enum RAllocator::TAllocFail User::__DbgGetAllocFail(int) ?SetKeyOffset@RArrayBase@@IAEXH@Z @ 2217 NONAME ; void RArrayBase::SetKeyOffset(int) - + ?Poll@RFastLock@@QAEHXZ @ 2218 NONAME ; public: int __thiscall RFastLock::Poll(void) + ?Poll@RMutex@@QAEHXZ @ 2219 NONAME ; public: int __thiscall RMutex::Poll(void) + ?Poll@RSemaphore@@QAEHXZ @ 2220 NONAME ; public: int __thiscall RSemaphore::Poll(void) + ?Wait@RMutex@@QAEHH@Z @ 2221 NONAME ; public: int __thiscall RMutex::Wait(int) + ?Wait@RFastLock@@QAEHH@Z @ 2222 NONAME ; public: int __thiscall RFastLock::Wait(int) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/bx86/euseru.def --- a/kernel/eka/bx86/euseru.def Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/bx86/euseru.def Wed Jun 23 12:58:21 2010 +0100 @@ -2216,4 +2216,8 @@ ?__DbgGetAllocFail@RAllocator@@QAE?AW4TAllocFail@1@XZ @ 2215 NONAME ; enum RAllocator::TAllocFail RAllocator::__DbgGetAllocFail(void) ?__DbgGetAllocFail@User@@SA?AW4TAllocFail@RAllocator@@H@Z @ 2216 NONAME ; enum RAllocator::TAllocFail User::__DbgGetAllocFail(int) ?SetKeyOffset@RArrayBase@@IAEXH@Z @ 2217 NONAME ; void RArrayBase::SetKeyOffset(int) - + ?Poll@RFastLock@@QAEHXZ @ 2218 NONAME ; public: int __thiscall RFastLock::Poll(void) + ?Poll@RMutex@@QAEHXZ @ 2219 NONAME ; public: int __thiscall RMutex::Poll(void) + ?Poll@RSemaphore@@QAEHXZ @ 2220 NONAME ; public: int __thiscall RSemaphore::Poll(void) + ?Wait@RMutex@@QAEHH@Z @ 2221 NONAME ; public: int __thiscall RMutex::Wait(int) + ?Wait@RFastLock@@QAEHH@Z @ 2222 NONAME ; public: int __thiscall RFastLock::Wait(int) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/bx86gcc/euseru.def --- a/kernel/eka/bx86gcc/euseru.def Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/bx86gcc/euseru.def Wed Jun 23 12:58:21 2010 +0100 @@ -2495,4 +2495,8 @@ _ZN10RAllocator17__DbgGetAllocFailEv @ 2494 NONAME _ZN4User17__DbgGetAllocFailEi @ 2495 NONAME _ZN10RArrayBase12SetKeyOffsetEi @ 2496 NONAME - + _ZN10RSemaphore4PollEv @ 2497 NONAME ; RSemaphore::Poll() + _ZN6RMutex4WaitEi @ 2498 NONAME ; RMutex::Wait(int) + _ZN6RMutex4PollEv @ 2499 NONAME ; RMutex::Poll() + _ZN9RFastLock4PollEv @ 2500 NONAME ; RFastLock::Poll() + _ZN9RFastLock4WaitEi @ 2501 NONAME ; RFastLock::Wait(int) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/drivers/bsp/bld.inf --- a/kernel/eka/drivers/bsp/bld.inf Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/drivers/bsp/bld.inf Wed Jun 23 12:58:21 2010 +0100 @@ -51,13 +51,9 @@ ../resmanus/resmanus ../resmanus/resmanusextended +#if !defined(WINS) ../power/smppower/idlehelper_lib.mmp ../power/smppower/sample_idlehandler/smpidlehandler_lib.mmp - -#endif - -#if !defined(X86) -#if !defined(WINS) ../iic/iic #endif #endif diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/drivers/power/smppower/idlehelper.cia --- a/kernel/eka/drivers/power/smppower/idlehelper.cia Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/idlehelper.cia Wed Jun 23 12:58:21 2010 +0100 @@ -85,12 +85,12 @@ LDREX(3,1); // r3 = iIdlingCpus asm("orr r3,r0,r3"); // orr in mask for this CPU asm("cmp r3,r2"); // compare to iAllEngagedCpusMask - asm("orreq r3,r3,#%a0" : : "i" ((TUint32)TIdleSupport::KGlobalIdleFlag)); // if equal orr in KGlobalIdleFlag + asm("orreq r3,r3,#%a0" : : "i" ((TInt)TIdleSupport::KGlobalIdleFlag)); // if equal orr in KGlobalIdleFlag STREX(12,3,1); asm("cmp r12, #0 "); // asm("bne 1b "); // write didn't succeed try again __DATA_MEMORY_BARRIER__(r12); - asm("and r0,r3,#%a0" : : "i" ((TUint32)TIdleSupport::KGlobalIdleFlag)); + asm("and r0,r3,#%a0" : : "i" ((TInt)TIdleSupport::KGlobalIdleFlag)); __JUMP(,lr); asm("__iAllEngagedCpusMask:"); asm(".word %a0" : : "i" ((TInt)&TIdleSupport::iAllEngagedCpusMask));// @@ -149,7 +149,7 @@ #endif asm("2: "); asm("cmp r3,r5"); // all (old stage does not equal new stage) - asm("bne 3f"); // yup return + asm("ldmnefd sp!, {r4-r5,pc}"); // yup return #ifdef SYNCPOINT_WFE __DATA_MEMORY_BARRIER__(r12); ARM_WFE; @@ -158,8 +158,6 @@ __DATA_MEMORY_BARRIER__(r12); // ensure read is observed asm("mov r3,r2,lsr #16"); // re-read new stage asm("b 2b"); // loop back - asm("3: "); - asm("ldmfd sp!, {r4-r5,pc}"); // return } /** @@ -210,7 +208,7 @@ #endif asm("2: "); asm("ands r3,r2,#0x80000000"); // MSB set? - asm("bne 4f"); // yup return + asm("ldmnefd sp!, {r4,pc}"); // yup return #ifdef SYNCPOINT_WFE __DATA_MEMORY_BARRIER__(r12); ARM_WFE; @@ -224,8 +222,7 @@ __DATA_MEMORY_BARRIER__(r12); // ensure that's written ARM_SEV; #endif - asm("4:"); - asm("ldmfd sp!, {r4,pc}"); // return + asm("ldmfd sp!, {r4,pc}"); // yup return } @@ -295,7 +292,7 @@ } #endif -__NAKED__ TUint32 TIdleSupport::IntPending() +__NAKED__ TInt TIdleSupport::IntPending() { asm("ldr r1,__KCPUIFAddr");//r1 = address of iBaseIntIfAddress asm("ldr r1, [r1]");//r1 = address of Hw GIC CPU interrupt interface base address diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/drivers/power/smppower/idlehelper.cpp --- a/kernel/eka/drivers/power/smppower/idlehelper.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/idlehelper.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -70,7 +70,7 @@ TBool TIdleSupport::IsIntPending() { - return (IntPending()!=KNoInterruptsPending); + return ((TUint32)IntPending()!=KNoInterruptsPending); } /** @@ -190,7 +190,8 @@ /** mark a core as retired - @pre called by idle handler + @pre called by idle handler as part of idle entry before + any syncpoint or calls to SetLocalAndCheckSetGlobalIdle */ void TIdleSupport::MarkCoreRetired(TUint32 aCpuMask) { @@ -200,7 +201,8 @@ /** mark a core as enaged - @pre called outside idle handler + @pre called outside idle handler ( can be called in idle entry before + any syncpoint or calls to SetLocalAndCheckSetGlobalIdle */ void TIdleSupport::MarkCoreEngaged(TUint32 aCpuMask) { diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/eabi/euseru.def --- a/kernel/eka/eabi/euseru.def Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/eabi/euseru.def Wed Jun 23 12:58:21 2010 +0100 @@ -2538,4 +2538,8 @@ _ZN10RAllocator17__DbgGetAllocFailEv @ 2537 NONAME _ZN4User17__DbgGetAllocFailEi @ 2538 NONAME _ZN10RArrayBase12SetKeyOffsetEi @ 2539 NONAME - + _ZN10RSemaphore4PollEv @ 2540 NONAME ; RSemaphore::Poll() + _ZN6RMutex4WaitEi @ 2541 NONAME ; RMutex::Wait(int) + _ZN6RMutex4PollEv @ 2542 NONAME ; RMutex::Poll() + _ZN9RFastLock4PollEv @ 2543 NONAME ; RFastLock::Poll() + _ZN9RFastLock4WaitEi @ 2544 NONAME ; RFastLock::Wait(int) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/euser/epoc/arm/uc_utl.cia --- a/kernel/eka/euser/epoc/arm/uc_utl.cia Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/euser/epoc/arm/uc_utl.cia Wed Jun 23 12:58:21 2010 +0100 @@ -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 diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/euser/epoc/win32/uc_utl.cpp --- a/kernel/eka/euser/epoc/win32/uc_utl.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/euser/epoc/win32/uc_utl.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -114,6 +114,21 @@ RSemaphore::Wait(); } +EXPORT_C __NAKED__ TInt RFastLock::Poll() + { + _asm xor eax, eax + _asm xor edx, edx + _asm dec edx + + /* if ([ecx+4]==0) { [ecx+4]=-1; ZF=1;} else {eax=[ecx+4]; ZF=0;} */ + _asm lock cmpxchg [ecx+4], edx + _asm jz short fastlock_poll_done + _asm mov eax, -33 + + fastlock_poll_done: + _asm ret + } + EXPORT_C void RFastLock::Signal() { if (InterlockedIncrement((LPLONG)&iCount) < 0) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/euser/epoc/x86/uc_utl.cia --- a/kernel/eka/euser/epoc/x86/uc_utl.cia Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/euser/epoc/x86/uc_utl.cia Wed Jun 23 12:58:21 2010 +0100 @@ -42,6 +42,22 @@ THISCALL_EPILOG0() } +EXPORT_C __NAKED__ TInt RFastLock::Poll() + { + THISCALL_PROLOG0() + asm("xor eax, eax "); + asm("xor edx, edx "); + asm("dec edx "); + + /* if ([ecx+4]==0) { [ecx+4]=-1; ZF=1;} else {eax=[ecx+4]; ZF=0;} */ + asm("lock cmpxchg [ecx+4], edx "); + asm("jz short fastlock_poll_done "); + asm("mov eax, %0": : "i"(KErrTimedOut)); + + asm("fastlock_poll_done: "); + THISCALL_EPILOG0() + } + EXPORT_C __NAKED__ void RFastLock::Signal() { THISCALL_PROLOG0() diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/euser/us_exec.cpp --- a/kernel/eka/euser/us_exec.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/euser/us_exec.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -3768,8 +3768,59 @@ */ EXPORT_C void RMutex::Wait() { - - Exec::MutexWait(iHandle); + Exec::MutexWait(iHandle, 0); + } + + + + +/** +Acquire the mutex if it is currently free, but don't wait for it. + +This function checks if the mutex is currently held. If not the mutex is marked +as held by the current thread and the call returns immediately indicating +success. If the mutex is held by another thread the call returns immediately +indicating failure. If the mutex is already held by the current thread a count +is maintained of how many times the thread has acquired the mutex. + +@return KErrNone if the mutex was acquired + KErrTimedOut if the mutex could not be acquired + KErrGeneral if the semaphore is being reset, i.e the semaphore + is about to be deleted. +*/ +EXPORT_C TInt RMutex::Poll() + { + return Exec::MutexWait(iHandle, -1); + } + + + + +/** +Acquire the mutex, if necessary waiting up to a specified maximum amount of time +for it to become free. + +This function checks if the mutex is currently held. If not the mutex is marked +as held by the current thread and the call returns immediately. If the mutex is +held by another thread the current thread will suspend until the mutex becomes +free or until the specified timeout period has elapsed. If the mutex is already +held by the current thread a count is maintained of how many times the thread +has acquired the mutex. + +@param aTimeout The timeout value in microseconds + +@return KErrNone if the mutex was acquired successfully. + KErrTimedOut if the timeout has expired. + KErrGeneral if the mutex is being reset, i.e the mutex + is about to be deleted. + KErrArgument if aTimeout is negative; + otherwise one of the other system wide error codes. +*/ +EXPORT_C TInt RMutex::Wait(TInt aTimeout) + { + if (aTimeout>=0) + return Exec::MutexWait(iHandle, aTimeout); + return KErrArgument; } @@ -4308,7 +4359,6 @@ -EXPORT_C void RSemaphore::Wait() /** Waits for a signal on the semaphore. @@ -4324,19 +4374,16 @@ If the semaphore is deleted, all threads waiting on that semaphore are released. */ - { - +EXPORT_C void RSemaphore::Wait() + { Exec::SemaphoreWait(iHandle, 0); } - - -EXPORT_C TInt RSemaphore::Wait(TInt aTimeout) /** Waits for a signal on the semaphore, or a timeout. -@param aTimeout The timeout value in micoseconds +@param aTimeout The timeout value in microseconds @return KErrNone if the wait has completed normally. KErrTimedOut if the timeout has expired. @@ -4345,12 +4392,26 @@ KErrArgument if aTimeout is negative; otherwise one of the other system wide error codes. */ - { - - return Exec::SemaphoreWait(iHandle, aTimeout); - } - - +EXPORT_C TInt RSemaphore::Wait(TInt aTimeout) + { + if (aTimeout>=0) + return Exec::SemaphoreWait(iHandle, aTimeout); + return KErrArgument; + } + + +/** +Acquires the semaphore if that is possible without waiting. + +@return KErrNone if the semaphore was acquired successfully + KErrTimedOut if the semaphore could not be acquired + KErrGeneral if the semaphore is being reset, i.e the semaphore + is about to be deleted. +*/ +EXPORT_C TInt RSemaphore::Poll() + { + return Exec::SemaphoreWait(iHandle, -1); + } EXPORT_C void RSemaphore::Signal() @@ -4389,6 +4450,54 @@ +#ifndef __CPU_ARM +/** +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 TInt RFastLock::Wait(TInt aTimeout) + { + if (aTimeout<=0) + return KErrArgument; + TInt orig = __e32_atomic_add_acq32(&iCount, TUint32(-1)); + if (orig == 0) + return KErrNone; + FOREVER + { + TInt r = Exec::SemaphoreWait(iHandle, aTimeout); + if (r != KErrTimedOut) // got lock OK or lock deleted + return r; + // 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; + } + } +#endif EXPORT_C RCriticalSection::RCriticalSection() : iBlocked(1) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/drivers/smppower/idlehelper.h --- a/kernel/eka/include/drivers/smppower/idlehelper.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/drivers/smppower/idlehelper.h Wed Jun 23 12:58:21 2010 +0100 @@ -171,7 +171,7 @@ static void ClearIdleIPI(); static void DoWFI();//puts current CPU in wait for interrupt state static TBool IsIntPending(); - static TUint32 IntPending(); + static TInt IntPending(); static TUint32 GetTimerCount();//HW timer can be used for tracing //Atomic checks used to synchronise cores going idle static TBool ClearLocalAndCheckGlobalIdle(TUint32); diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/e32cia.h --- a/kernel/eka/include/e32cia.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/e32cia.h Wed Jun 23 12:58:21 2010 +0100 @@ -39,6 +39,7 @@ #define CSM_Z15PanicStrayEventv " PanicStrayEvent__Fv" #define CSM_ZN8CServer210BadMessageERK9RMessage2 " BadMessage__8CServer2RC9RMessage2" #define CSM_ZN10RSemaphore4WaitEv " Wait__10RSemaphore" +#define CSM_ZN10RSemaphore4WaitEi " Wait__10RSemaphorei" #define CSM_Z34PanicCObjectConFindIndexOutOfRangev " PanicCObjectConFindIndexOutOfRange__Fv" #define CSM_ZN7TRegion5ClearEv " Clear__7TRegion" #define CSM_ZN4User5AllocEi " Alloc__4Useri" @@ -73,6 +74,7 @@ #define CSM_Z15PanicStrayEventv " __cpp(PanicStrayEvent)" #define CSM_ZN8CServer210BadMessageERK9RMessage2 " __cpp(CServer2::BadMessage)" #define CSM_ZN10RSemaphore4WaitEv " __cpp(static_cast(&RSemaphore::Wait))" +#define CSM_ZN10RSemaphore4WaitEi " __cpp(static_cast(&RSemaphore::Wait))" #define CSM_Z34PanicCObjectConFindIndexOutOfRangev " __cpp(PanicCObjectConFindIndexOutOfRange)" #define CSM_ZN7TRegion5ClearEv " __cpp(TRegion::Clear)" #define CSM_ZN4User5AllocEi " __cpp(User::Alloc)" @@ -106,6 +108,7 @@ #define CSM_Z15PanicStrayEventv " _Z15PanicStrayEventv" #define CSM_ZN8CServer210BadMessageERK9RMessage2 " _ZN8CServer210BadMessageERK9RMessage2" #define CSM_ZN10RSemaphore4WaitEv " _ZN10RSemaphore4WaitEv" +#define CSM_ZN10RSemaphore4WaitEi " _ZN10RSemaphore4WaitEi" #define CSM_Z34PanicCObjectConFindIndexOutOfRangev " _Z34PanicCObjectConFindIndexOutOfRangev" #define CSM_ZN7TRegion5ClearEv " _ZN7TRegion5ClearEv" #define CSM_ZN4User5AllocEi " _ZN4User5AllocEi" diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/e32cmn.h --- a/kernel/eka/include/e32cmn.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/e32cmn.h Wed Jun 23 12:58:21 2010 +0100 @@ -2488,6 +2488,7 @@ IMPORT_C TInt Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess); IMPORT_C void Wait(); IMPORT_C TInt Wait(TInt aTimeout); // timeout in microseconds + IMPORT_C TInt Poll(); // acquire the semaphore if possible, but don't block IMPORT_C void Signal(); IMPORT_C void Signal(TInt aCount); #endif @@ -2511,6 +2512,8 @@ inline RFastLock(); IMPORT_C TInt CreateLocal(TOwnerType aType=EOwnerProcess); IMPORT_C void Wait(); + IMPORT_C TInt Wait(TInt aTimeout); // timeout in microseconds + IMPORT_C TInt Poll(); // acquire the lock if possible, but don't block IMPORT_C void Signal(); private: TInt iCount; diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/e32std.h --- a/kernel/eka/include/e32std.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/e32std.h Wed Jun 23 12:58:21 2010 +0100 @@ -3314,6 +3314,8 @@ IMPORT_C TInt Open(RMessagePtr2 aMessage,TInt aParam,TOwnerType aType=EOwnerProcess); IMPORT_C TInt Open(TInt aArgumentIndex, TOwnerType aType=EOwnerProcess); IMPORT_C void Wait(); + IMPORT_C TInt Poll(); // acquire the lock if possible, but don't block + IMPORT_C TInt Wait(TInt aTimeout); // timeout in microseconds IMPORT_C void Signal(); IMPORT_C TBool IsHeld(); }; @@ -4770,6 +4772,7 @@ IMPORT_C static void __DbgMarkCheck(TBool aKernel, TBool aCountAll, TInt aCount, const TUint8* aFileName, TInt aLineNum); IMPORT_C static TUint32 __DbgMarkEnd(TBool aKernel, TInt aCount); IMPORT_C static void __DbgSetAllocFail(TBool aKernel, RAllocator::TAllocFail aFail, TInt aRate); + IMPORT_C static RAllocator::TAllocFail __DbgGetAllocFail(TBool aKernel); IMPORT_C static void __DbgSetBurstAllocFail(TBool aKernel, RAllocator::TAllocFail aFail, TUint aRate, TUint aBurst); IMPORT_C static TUint __DbgCheckFailure(TBool aKernel); IMPORT_C static void PanicUnexpectedLeave(); /**< @internalComponent */ diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/e32ver.h --- a/kernel/eka/include/e32ver.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/e32ver.h Wed Jun 23 12:58:21 2010 +0100 @@ -28,7 +28,7 @@ const TInt KE32MajorVersionNumber=2; const TInt KE32MinorVersionNumber=0; -const TInt KE32BuildVersionNumber=3097; +const TInt KE32BuildVersionNumber=3098; const TInt KMachineConfigurationMajorVersionNumber=1; const TInt KMachineConfigurationMinorVersionNumber=0; diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/kernel/kern_priv.h --- a/kernel/eka/include/kernel/kern_priv.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/kernel/kern_priv.h Wed Jun 23 12:58:21 2010 +0100 @@ -745,7 +745,7 @@ void ChangePendingThreadPriority(DThread* aThread, TInt aNewPriority); void WakeUpNextThread(); public: - TInt Wait(); + TInt Wait(TInt aTimeout=0); // 0 means wait forever, -1 means poll, n>0 means n nanokernel ticks void Signal(); void Reset(); public: diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/nkern/nk_cpu.h --- a/kernel/eka/include/nkern/nk_cpu.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/nkern/nk_cpu.h Wed Jun 23 12:58:21 2010 +0100 @@ -688,6 +688,8 @@ #error SMP not allowed without thread ID registers #endif +#define __SRATIO_MACHINE_CODED__ + #endif // end of __CPU_ARM #if defined(__CPU_X86) && defined(__EPOC32__) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/nkern/nklib.h --- a/kernel/eka/include/nkern/nklib.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/nkern/nklib.h Wed Jun 23 12:58:21 2010 +0100 @@ -85,6 +85,39 @@ }; +/** +@internalComponent + +Ratio represented = iM*2^iX +e.g. 1.0 has iM=0x80000000, iX=-31 +*/ +struct SRatio + { + void Set(TUint32 aInt, TInt aDivisorExp=0); // set this ratio to aInt/2^aDivisorExp + TInt Reciprocal(); // this = 1/this + TInt Mult(TUint32& aInt32); // Multiply aInt32 by this ratio +// TInt Mult(TUint64& aInt64); // Multiply aInt64 by this ratio + + TUint32 iM; // mantissa, normalised so bit 31=1 + TInt16 iX; // -exponent. + TUint8 iSpare1; + TUint8 iSpare2; + }; + +/** +@internalComponent + +Ratio and inverse ratio +*/ +struct SRatioInv + { + void Set(const SRatio* aR); + + SRatio iR; + SRatio iI; + }; + + #if defined(__VC32__) || defined(__CW32__) extern "C" /** @internalComponent */ diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/nkernsmp/arm/ncern.h --- a/kernel/eka/include/nkernsmp/arm/ncern.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/nkernsmp/arm/ncern.h Wed Jun 23 12:58:21 2010 +0100 @@ -97,20 +97,6 @@ __ASSERT_COMPILE(sizeof(SPerCpuUncached) <= 8*sizeof(TUint64)); -/** Timer frequency specification - -Stores a frequency as a fraction of a (separately stored) maximum. -The frequency must be at least 1/256 of the maximum. - -@internalTechnology -@prototype -*/ -struct STimerMult - { - TUint32 iFreq; // frequency as a fraction of maximum possible, multiplied by 2^32 - TUint32 iInverse; // 2^24/(iFreq/2^32) = 2^56/iFreq - }; - /** Function to power up a CPU @publishedPartner @prototype @@ -123,6 +109,12 @@ */ typedef void (*TCpuPowerDownFn)(TInt aCpu, SPerCpuUncached* aU); +/** Function to notify changes to system clock frequencies +@publishedPartner +@prototype +*/ +typedef TInt (*TFrequencyChangeFn)(); + /** Variant interface block @internalTechnology @prototype @@ -138,11 +130,13 @@ TLinAddr iGicCpuIfcAddr; // address of GIC CPU interface (must be same for all CPUs) TLinAddr iLocalTimerAddr; // address of per-CPU timer (must be same for all CPUs) TLinAddr iGlobalTimerAddr; // address of global timer if it exists - volatile STimerMult* iTimerMult[KMaxCpus]; // timer[i] frequency / iMaxTimerClock * 2^32 - volatile TUint32* iCpuMult[KMaxCpus]; // CPU[i] frequency / iMaxCpuClock * 2^32 + SRatio* iTimerFreqR[KMaxCpus]; // timer[i] frequency as a fraction of iMaxTimerClock + SRatio* iCpuFreqR[KMaxCpus]; // CPU[i] frequency as a fraction of iMaxCpuClock UPerCpuUncached* iUncached[KMaxCpus]; // Pointer to uncached memory for each CPU TCpuPowerUpFn iCpuPowerUpFn; // function used to power up a retired CPU (NULL if core control not supported) TCpuPowerDownFn iCpuPowerDownFn; // function used to power down a CPU (NULL if power down done within idle handler itself) + SRatio* iGTimerFreqR; // global timer frequency as a fraction of iMaxTimerClock + TFrequencyChangeFn iFrqChgFn; // function to notify frequency changes }; // End of file diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/nkernsmp/arm/nk_plat.h --- a/kernel/eka/include/nkernsmp/arm/nk_plat.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/nkernsmp/arm/nk_plat.h Wed Jun 23 12:58:21 2010 +0100 @@ -66,35 +66,12 @@ TLinAddr iUndStackTop; // Top of UND stack for this CPU TLinAddr iFiqStackTop; // Top of FIQ stack for this CPU TLinAddr iIrqStackTop; // Top of IRQ stack for this CPU - volatile TUint32 iCpuFreqM; // CPU frequency / Max CPU frequency (mantissa, bit 31=1) f/fmax=mantissa/2^shift - volatile TInt iCpuFreqS; // CPU frequency / Max CPU frequency (shift) - volatile TUint32 iCpuPeriodM; // Max CPU frequency / CPU frequency (mantissa, bit 31=1) fmax/f=mantissa/2^shift - volatile TInt iCpuPeriodS; // Max CPU frequency / CPU frequency (shift) - volatile TUint32 iNTimerFreqM; // Nominal Timer frequency / Max Timer frequency (mantissa, bit 31=1) f/fmax=mantissa/2^shift - volatile TInt iNTimerFreqS; // Nominal Timer frequency / Max Timer frequency (shift) - volatile TUint32 iNTimerPeriodM; // Nominal Max Timer frequency / Timer frequency (mantissa, bit 31=1) fmax/f=mantissa/2^shift - volatile TInt iNTimerPeriodS; // Nominal Max Timer frequency / Timer frequency (shift) - volatile TUint32 iTimerFreqM; // Timer frequency / Max Timer frequency (mantissa, bit 31=1) f/fmax=mantissa/2^shift - volatile TInt iTimerFreqS; // Timer frequency / Max Timer frequency (shift) - volatile TUint32 iTimerPeriodM; // Max Timer frequency / Timer frequency (mantissa, bit 31=1) fmax/f=mantissa/2^shift - volatile TInt iTimerPeriodS; // Max Timer frequency / Timer frequency (shift) - volatile TUint64 iLastSyncTime; // Timestamp at which last reference check occurred - volatile TUint32 iTicksSinceLastSync; // Local timer ticks between last ref. check and next zero crossing - volatile TUint32 iLastTimerSet; // Value last written to local timer counter - volatile TUint32 iGapEstimate; // 2^16 * estimated gap in ticks whenever local timer counter is read then written - volatile TUint32 iGapCount; // count of local timer counter RMW ops - volatile TUint32 iTotalTicks; // programmed ticks since last sync - volatile TUint32 iDitherer; // PRNG state for dither generation - volatile TInt iFreqErrorEstimate; // Current frequency offset between local timer and reference - volatile TInt iFreqErrorLimit; // Saturation level for frequency offset - volatile TInt64 iErrorIntegrator; // Accumulator to integrate time error measurements - volatile TUint64 iRefAtLastCorrection; // Value of reference timer at last correction - volatile TUint8 iM; // Value controlling loop bandwidth (larger->lower loop bandwidth) - volatile TUint8 iN; // Number of timer ticks between corrections = 2^iN - volatile TUint8 iD; // Value controlling loop damping - volatile TUint8 iSSXP1; + SRatioInv* volatile iNewCpuFreqRI; // set when CPU frequency has been changed + SRatioInv* volatile iNewTimerFreqRI; // set when CPU local timer frequency has been changed + SRatioInv iCpuFreqRI; // Ratio of CPU frequency to maximum possible CPU frequency + SRatioInv iTimerFreqRI; // Ratio of CPU local timer frequency to maximum possible - TUint32 iSSXP2[19]; + TUint32 iSSXP2[36]; TUint64 iSSXP3; // one 64 bit value to guarantee alignment }; @@ -108,7 +85,12 @@ GicDistributor* iGicDistAddr; // Address of GIC Distributor (also in TSubScheduler) GicCpuIfc* iGicCpuIfcAddr; // Address of GIC CPU Interface (also in TSubScheduler) ArmLocalTimer* iLocalTimerAddr; // Address of local timer registers (also in TSubScheduler) - TUint32 iSXP2[8]; + + SRatioInv iGTimerFreqRI; // ratio of global timer frequency to maximum possible + TUint64 iCount0; // global timer count at last frequency change + TUint64 iTimestamp0; // timestamp at last frequency change + + TUint32 iSXP2[16]; }; diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/nkernsmp/nk_priv.h --- a/kernel/eka/include/nkernsmp/nk_priv.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/nkernsmp/nk_priv.h Wed Jun 23 12:58:21 2010 +0100 @@ -629,6 +629,7 @@ __ASSERT_COMPILE(sizeof(TSubScheduler)==(1<=1 - volatile TInt iCpuPeriodS; // Max CPU frequency / CPU frequency (shift) - volatile TUint32 iNTimerFreqM; // Nominal Timer frequency / Max Timer frequency (mantissa, bit 31=1) f/fmax=M/2^(S+32) <=1 - volatile TInt iNTimerFreqS; // Nominal Timer frequency / Max Timer frequency (shift) - volatile TUint32 iNTimerPeriodM; // Nominal Max Timer frequency / Timer frequency (mantissa, bit 31=1) fmax/f=M/2^S >=1 - volatile TInt iNTimerPeriodS; // Nominal Max Timer frequency / Timer frequency (shift) - volatile TUint32 iTimerFreqM; // Timer frequency / Max Timer frequency (mantissa, bit 31=1) f/fmax=M/2^(S+32) <=1 - volatile TInt iTimerFreqS; // Timer frequency / Max Timer frequency (shift) - volatile TUint32 iTimerPeriodM; // Max Timer frequency / Timer frequency (mantissa, bit 31=1) fmax/f=M/2^S >=1 - volatile TInt iTimerPeriodS; // Max Timer frequency / Timer frequency (shift) + SRatioInv iCpuFreqRI; // Ratio of CPU frequency to maximum possible CPU frequency + SRatioInv iTimerFreqRI; // Ratio of CPU local timer frequency to maximum possible + volatile TUint64HL iTimestampOffset; // 64 bit value to add to CPU TSC to give NKern::Timestamp() - TUint32 iSSXP2[32]; + TUint32 iSSXP2[36]; TUint64 iSSXP3; // one 64 bit value to guarantee alignment }; @@ -64,7 +55,7 @@ struct TSchedulerX { TUint64 iTimerMax; // Maximum per-CPU timer frequency (after prescaling) - TUint32 iSXP[14]; + TUint32 iSXP[30]; }; diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/include/u32std.h --- a/kernel/eka/include/u32std.h Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/include/u32std.h Wed Jun 23 12:58:21 2010 +0100 @@ -401,7 +401,7 @@ }; /** @test */ -enum TKernelHeapDebugFunction {EDbgMarkStart,EDbgMarkCheck,EDbgMarkEnd,EDbgSetAllocFail,EDbgSetBurstAllocFail,EDbgCheckFailure}; +enum TKernelHeapDebugFunction {EDbgMarkStart,EDbgMarkCheck,EDbgMarkEnd,EDbgSetAllocFail,EDbgSetBurstAllocFail,EDbgCheckFailure,EDbgGetAllocFail}; /** @test */ class TKernelHeapMarkCheckInfo @@ -508,6 +508,8 @@ EKernelConfigSMPUnsafeCPU0 = 1<<13, // Slow compatibility mode: all SMP-unsafe processes run on CPU 0 only EKernelConfigSMPCrazyInterrupts = 1<<14, // Enables CPU target rotation for HW Interrupts. + EKernelConfigSMPLockKernelThreadsCore0 = 1<< 15, // locks all kernel side threads to CPU 0 + EKernelConfigDisableAPs = 1u<<30, EKernelConfigTest = 1u<<31, // Only used by test code for __PLATSEC_UNLOCKED__ diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/kernel/execs.txt --- a/kernel/eka/kernel/execs.txt Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/kernel/execs.txt Wed Jun 23 12:58:21 2010 +0100 @@ -680,6 +680,8 @@ slow { name = MutexWait + return = TInt + arg2 = TInt handle = mutex } diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/kernel/sexec.cpp --- a/kernel/eka/kernel/sexec.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/kernel/sexec.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -96,14 +96,26 @@ return aChunk->Top(); } -void ExecHandler::MutexWait(DMutex* aMutex) +TInt ExecHandler::MutexWait(DMutex* aMutex, TInt aTimeout) // // Wait for the mutex. // { - -// __KTRACE_OPT(KEXEC,Kern::Printf("Exec::MutexWait")); - aMutex->Wait(); + if (aTimeout) // 0 means wait forever, -1 means poll + { + if (aTimeout<-1) + { + return KErrArgument; + } + if (aTimeout>0) + { + // Convert microseconds to NTimer ticks, rounding up + TInt ntp = NKern::TickPeriod(); + aTimeout += ntp-1; + aTimeout /= ntp; + } + } + return aMutex->Wait(aTimeout); } void ExecHandler::MutexSignal(DMutex* aMutex) @@ -555,20 +567,21 @@ // Wait for a signal. // { - __KTRACE_OPT(KEXEC,Kern::Printf("Exec::SemaphoreWait")); - if (aTimeout) + if (aTimeout) // 0 means wait forever, -1 means poll { - if (aTimeout<0) + if (aTimeout<-1) { NKern::UnlockSystem(); return KErrArgument; } - - // Convert microseconds to NTimer ticks, rounding up - TInt ntp = NKern::TickPeriod(); - aTimeout += ntp-1; - aTimeout /= ntp; + if (aTimeout>0) + { + // Convert microseconds to NTimer ticks, rounding up + TInt ntp = NKern::TickPeriod(); + aTimeout += ntp-1; + aTimeout /= ntp; + } } return aSemaphore->Wait(aTimeout); } diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/kernel/skernel.cpp --- a/kernel/eka/kernel/skernel.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/kernel/skernel.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -74,6 +74,9 @@ // Wait for semaphore with timeout // Enter with system locked, return with system unlocked. +// If aNTicks==0, wait forever +// If aNTicks==-1, poll (don't block) +// If aNTicks>0, timeout is aNTicks nanokernel ticks TInt DSemaphore::Wait(TInt aNTicks) { __KTRACE_OPT(KSEMAPHORE,Kern::Printf("Semaphore %O Wait %d Timeout %d",this,iCount,aNTicks)); @@ -84,14 +87,23 @@ r=KErrGeneral; else if (--iCount<0) { - DThread* pC=TheCurrentThread; - pC->iMState=DThread::EWaitSemaphore; - pC->iWaitObj=this; - iWaitQ.Add(pC); - BTRACE_KS(BTrace::ESemaphoreBlock, this); - r=NKern::Block(aNTicks,NKern::ERelease,SYSTEM_LOCK); - __ASSERT_DEBUG(pC->iMState==DThread::EReady,K::Fault(K::ESemWaitBadState)); - COND_BTRACE_KS(r==KErrNone, BTrace::ESemaphoreAcquire, this); + if (aNTicks >= 0) + { + DThread* pC=TheCurrentThread; + pC->iMState=DThread::EWaitSemaphore; + pC->iWaitObj=this; + iWaitQ.Add(pC); + BTRACE_KS(BTrace::ESemaphoreBlock, this); + r=NKern::Block(aNTicks,NKern::ERelease,SYSTEM_LOCK); + __ASSERT_DEBUG(pC->iMState==DThread::EReady,K::Fault(K::ESemWaitBadState)); + COND_BTRACE_KS(r==KErrNone, BTrace::ESemaphoreAcquire, this); + } + else + { + ++iCount; + NKern::UnlockSystem(); + r = KErrTimedOut; // couldn't acquire semaphore immediately, so fail + } return r; } #ifdef BTRACE_SYMBIAN_KERNEL_SYNC @@ -326,10 +338,14 @@ extern const SNThreadHandlers EpocThreadHandlers; #endif -// Enter and return with system locked. -TInt DMutex::Wait() +// Wait for mutex with timeout +// Enter with system locked, return with system unlocked. +// If aNTicks==0, wait forever +// If aNTicks==-1, poll (don't block) +// If aNTicks>0, timeout is aNTicks nanokernel ticks +TInt DMutex::Wait(TInt aNTicks) { - __KTRACE_OPT(KSEMAPHORE,Kern::Printf("Mutex %O Wait hold %O hldc=%d wtc=%d",this,iCleanup.iThread,iHoldCount,iWaitCount)); + __KTRACE_OPT(KSEMAPHORE,Kern::Printf("Mutex %O Wait(%d) hold %O hldc=%d wtc=%d",this,aNTicks,iCleanup.iThread,iHoldCount,iWaitCount)); __ASSERT_SYSTEM_LOCK; __ASSERT_DEBUG(NCurrentThread()->iHandlers==&EpocThreadHandlers, K::Fault(K::EMutexWaitNotDThread)); DThread* pC=TheCurrentThread; @@ -353,6 +369,8 @@ BTRACE_KS(BTrace::EMutexAcquire, this); return KErrNone; } + if (aNTicks<0) + return KErrTimedOut; // poll mode - can't get mutex immediately so fail K::PINestLevel=0; pC->iMState=DThread::EWaitMutex; pC->iWaitObj=this; @@ -375,7 +393,7 @@ // return value is set at the point where the thread is released from its wait // condition). However we can still detect this situation since the thread will // have been placed into the EReady state when the mutex was reset. - TInt r=NKern::Block(0, NKern::ERelease|NKern::EClaim|NKern::EObstruct, SYSTEM_LOCK); + TInt r=NKern::Block(aNTicks, NKern::ERelease|NKern::EClaim|NKern::EObstruct, SYSTEM_LOCK); if (r==KErrNone && pC->iMState==DThread::EReady) r = KErrGeneral; // mutex has been reset if (r!=KErrNone) // if we get an error here... diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/kernel/sthread.cpp --- a/kernel/eka/kernel/sthread.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/kernel/sthread.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -589,29 +589,28 @@ ni.iStackSize=iSupervisorStackSize; #ifdef __SMP__ TUint32 config = TheSuperPage().KernelConfigFlags(); + ni.iGroup = 0; + ni.iCpuAffinity = KCpuAffinityAny; if (iThreadType==EThreadUser) { // user thread if ((config & EKernelConfigSMPUnsafeCPU0) && iOwningProcess->iSMPUnsafeCount) { ni.iCpuAffinity = 0; // compatibility mode - ni.iGroup = 0; } else { - ni.iCpuAffinity = KCpuAffinityAny; if ((config & EKernelConfigSMPUnsafeCompat) && iOwningProcess->iSMPUnsafeCount) ni.iGroup = iOwningProcess->iSMPUnsafeGroup; - else - ni.iGroup = 0; } - } else { - // kernel thread - ni.iCpuAffinity = 0; - ni.iGroup = 0; + if (config & EKernelConfigSMPLockKernelThreadsCore0) + { + // kernel thread + ni.iCpuAffinity = 0; + } } #endif if (iThreadType!=EThreadInitial) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkern/arm/nklib.cia --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/nkern/arm/nklib.cia Wed Jun 23 12:58:21 2010 +0100 @@ -0,0 +1,194 @@ +// Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\nkern\arm\nklib.cia +// +// + +#include +#include + +#ifdef __SRATIO_MACHINE_CODED__ +__NAKED__ void SRatio::Set(TUint32 /*aInt*/, TInt /*aDivisorExp*/) + { +#ifdef __CPU_ARM_HAS_CLZ + CLZ( 3,1); // r3=31-MSB(r1), 32 if r1=0 + asm("add r2, r2, r3 "); // r2=shift+aDivisorExp + asm("movs r1, r1, lsl r3 "); // shift r1 left so bit 31=1 + asm("rsb r2, r2, #0 "); // r2 = -shift-aDivisorExp + asm("moveq r2, #0 "); // if aInt=0, r2=0 + asm("bicne r2, r2, #0xff000000 "); // else clear iSpare fields + asm("bicne r2, r2, #0x00ff0000 "); // +#else + asm("rsb r2, r2, #0 "); // r2 = -aDivisorExp + asm("cmp r1, #0x00010000 "); // if aInt top 16 bits clear ... + asm("movcc r1, r1, lsl #16 "); // ... shift 16 bits left ... + asm("subcc r2, r2, #16 "); // ... and subtract 16 from iX + asm("cmp r1, #0x01000000 "); + asm("movcc r1, r1, lsl #8 "); + asm("subcc r2, r2, #8 "); + asm("cmp r1, #0x10000000 "); + asm("movcc r1, r1, lsl #4 "); + asm("subcc r2, r2, #4 "); + asm("cmp r1, #0x40000000 "); + asm("movcc r1, r1, lsl #2 "); + asm("subcc r2, r2, #2 "); + asm("cmp r1, #0x80000000 "); + asm("subcc r2, r2, #1 "); + asm("cmp r1, #0 "); + asm("moveq r2, #0 "); // if aInt=0, r2=0 + asm("bicne r2, r2, #0xff000000 "); // else clear iSpare fields + asm("bicne r2, r2, #0x00ff0000 "); // +#endif + asm("stmia r0, {r1,r2} "); // iM in r1, iX in bottom 16 bits of r2 + __JUMP(, lr); + } + +__NAKED__ TInt SRatio::Reciprocal() + { + asm("ldr r1, [r0] "); // r1 = iM + asm("ldrsh r12, [r0, #4] "); // r12 = iX + asm("rsbs r2, r1, #0 "); + asm("beq 0f "); // divide by zero + asm("add r12, r12, #63 "); + asm("rsb r12, r12, #0 "); // r12 = -63 - iX + asm("addvs r12, r12, #1 "); // if iM==0x80000000 r12 = -62 - iX (ratio = 2^(31+iX) so reciprocal = 2^(-31-iX) = 2^(31 + (-62-iX)) + asm("bvs 1f "); // iM=0x80000000 + + // 2^(32+iX) > r > 2^(31+iX) + // 2^(-32-iX) < 1/r < 2^(-31-iX) + // 2^(31+(-63-iX)) < 1/r < 2^(31+(-62-iX)) + asm("mov r2, #0 "); // accumulates result + asm("mov r3, #0x80000000 "); // 33 bit accumulator in C:R3 initialised to 2^32 + asm("2: "); + asm("adds r3, r3, r3 "); + asm("cmpcc r3, r1 "); + asm("subcs r3, r3, r1 "); // if C=1 or r3>=r1, r3-=r1 + asm("adcs r2, r2, r2 "); // next result bit + asm("bcc 2b "); // finished when we have 33 bits (when top bit shifted off) + asm("movs r2, r2, lsr #1 "); // rounding bit into C + asm("orr r2, r2, #0x80000000 "); // top bit back + asm("adcs r2, r2, #0 "); // add rounding bit + asm("movcs r2, #0x80000000 "); // if carry, increment exponent + asm("addcs r12, r12, #1 "); + + asm("1: "); + asm("cmp r12, #-32768 "); + asm("blt 9f "); // underflow + asm("cmp r12, #32768 "); + asm("bge 8f "); // overflow + asm("str r2, [r0] "); // iM + asm("strh r12, [r0, #4] "); // iX + asm("mov r0, #0 "); + __JUMP(, lr); + + asm("0: "); + asm("mov r0, #%a0" : : "i" ((TInt)KErrDivideByZero)); + __JUMP(, lr); + + asm("8: "); + asm("mov r0, #%a0" : : "i" ((TInt)KErrOverflow)); + __JUMP(, lr); + + asm("9: "); + asm("mov r0, #%a0" : : "i" ((TInt)KErrUnderflow)); + __JUMP(, lr); + } + +__NAKED__ TInt SRatio::Mult(TUint32& /*aInt32*/) + { + asm("ldr r3, [r0] "); // r3 = iM + asm("mov r12, r0 "); + asm("ldr r0, [r1] "); // r0 = aInt32 + asm("cmp r3, #0 "); + asm("cmpne r0, #0 "); + asm("beq 0f "); // result zero + asm("umull r2, r3, r0, r3 "); // r3:r2 = aInt32 * iM (lowest value 0x0000000080000000) + asm("ldrsh r12, [r12, #4] "); // r12 = iX +#ifdef __CPU_ARM_HAS_CLZ + CLZ( 0, 3); // r0 = number of leading zeros in r3:r2 (can't be >32) +#else + asm("str r12, [sp, #-4]! "); + asm("movs r12, r3 "); + asm("mov r0, #0 "); + asm("cmp r12, #0x00010000 "); + asm("movcc r12, r12, lsl #16 "); + asm("addcc r0, r0, #16 "); + asm("cmp r12, #0x01000000 "); + asm("movcc r12, r12, lsl #8 "); + asm("addcc r0, r0, #8 "); + asm("cmp r12, #0x10000000 "); + asm("movcc r12, r12, lsl #4 "); + asm("addcc r0, r0, #4 "); + asm("cmp r12, #0x40000000 "); + asm("movcc r12, r12, lsl #2 "); + asm("addcc r0, r0, #2 "); + asm("cmp r12, #0 "); + asm("ldr r12, [sp], #4 "); // r12 = iX + asm("addgt r0, r0, #1 "); + asm("moveq r0, #32 "); // r0 = number of leading zeros in r3:r2 (can't be >32) +#endif + asm("rsb r0, r0, #63 "); // bit number of most significant bit + asm("add r0, r0, r12 "); // bit number of most significant bit after exponent shift + asm("cmp r0, #32 "); + asm("bge 8f "); // overflow + asm("cmp r0, #-1 "); + asm("blt 9f "); // underflow + asm("adds r12, r12, #32 "); // shift needed to get result into top 32 bits (>0 left, <0 right) + asm("beq 1f "); // no shift + asm("blt 2f "); // right shift + asm("rsb r0, r12, #32 "); + asm("mov r3, r3, lsl r12 "); + asm("orr r3, r3, r2, lsr r0 "); + asm("mov r2, r2, lsl r12 "); // r3:r2 <<= r12 + asm("b 1f "); + asm("2: "); + asm("rsb r12, r12, #0 "); + asm("rsb r0, r12, #32 "); + asm("mov r2, r2, lsr r12 "); + asm("orr r2, r2, r3, lsl r0 "); + asm("mov r3, r3, lsr r12 "); // r3:r2 >>= r12 + asm("1: "); + asm("adds r2, r2, r2 "); // rounding + asm("adcs r3, r3, #0 "); + asm("bcs 8f "); // overflow + asm("beq 9f "); // underflow + asm("mov r0, #0 "); + asm("str r3, [r1] "); + __JUMP(, lr); + + asm("0: "); + asm("mov r0, #0 "); + asm("str r0, [r1] "); + __JUMP(, lr); + + asm("8: "); + asm("mvn r0, #0 "); + asm("str r0, [r1] "); + asm("mov r0, #%a0" : : "i" ((TInt)KErrOverflow)); + __JUMP(, lr); + + asm("9: "); + asm("mov r0, #0 "); + asm("str r0, [r1] "); + asm("mov r0, #%a0" : : "i" ((TInt)KErrUnderflow)); + __JUMP(, lr); + } + +//TInt SRatio::Mult(TUint64& aInt64) +// { +// } + +#endif + + diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkern/nkern.mmp --- a/kernel/eka/nkern/nkern.mmp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkern/nkern.mmp Wed Jun 23 12:58:21 2010 +0100 @@ -16,12 +16,13 @@ // sourcepath ../nkern -source nkern.cpp +source nkern.cpp nklib.cpp #ifdef MARM sourcepath ../common/arm source atomics.cia sourcepath ../nkern/arm source vectors.cia ncsched.cpp ncsched.cia nctimer.cia ncutilf.cia +source nklib.cia // X86 #elif defined(X86) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkern/nklib.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/nkern/nklib.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -0,0 +1,135 @@ +// Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\nkern\nklib.cpp +// +// + +#include +#include + +#ifndef __SRATIO_MACHINE_CODED__ +void SRatio::Set(TUint32 aInt, TInt aDivisorExp) + { + iSpare1 = 0; + iSpare2 = 0; + iM = aInt; + if (iM) + { + TInt ms1 = __e32_find_ms1_32(iM); + TInt shift = 31 - ms1; + iM <<= shift; + iX = (TInt16)(-shift - aDivisorExp); + } + else + iX = 0; + } + +TInt SRatio::Reciprocal() + { + if (iM==0) + return KErrDivideByZero; + // Calculate 2^32/iM + TInt exp=0; + if (iM == 0x80000000u) + { + // ratio = 2^(31+iX) so reciprocal = 2^(-31-iX) = 2^(31 + (-62-iX)) + exp = -62-iX; + } + else + { + // 2^32/iM = 1.xxx + TUint64 r64 = MAKE_TUINT64(0u-iM,0); + TUint32 q32 = (TUint32)(r64/TUint64(iM)); // next 32 bits of result + iM = 0x80000000u | (q32>>1); + exp = -63-iX; + if (q32 & 1) + { + if (++iM==0) + iM=0x80000000u, ++exp; + } + } + if (exp < -32768) + { + iM = 0; + iX = 0; + return KErrUnderflow; + } + if (exp > 32767) + { + iM = 0xffffffffu; + iX = 32767; + return KErrOverflow; + } + iX = (TInt16)exp; + return KErrNone; + } + +TInt SRatio::Mult(TUint32& aInt32) + { + TUint64 x = aInt32; + x *= TUint64(iM); + if (x==0) + { + aInt32 = 0; + return KErrNone; + } + TInt ms1 = __e32_find_ms1_64(x); + TInt ms1b = ms1 + iX; + if (ms1b>=32) + { + aInt32 = ~0u; + return KErrOverflow; + } + if (ms1b<-1) + { + aInt32 = 0; + return KErrUnderflow; + } + TInt shift = ms1b - ms1 + 31; + if (shift > 0) + x <<= shift; + else if (shift < 0) + x >>= (-shift); + x += MAKE_TUINT64(0,0x40000000u); + if (x >> 63) + { + aInt32 = ~0u; + return KErrOverflow; + } + aInt32 = (TUint32)(x>>31); + return aInt32 ? KErrNone : KErrUnderflow; + } + +//TInt SRatio::Mult(TUint64& aInt64) +// { +// } +#endif + +void SRatioInv::Set(const SRatio* a) + { + if (a) + { + iR = *a; + iI = iR; + iI.Reciprocal(); + } + else + { + iR.Set(1); + iI.Set(1); + } + } + + + diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/nccpu.cpp --- a/kernel/eka/nkernsmp/arm/nccpu.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/nccpu.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -20,9 +20,6 @@ #include #include -extern "C" { -extern SVariantInterfaceBlock* VIB; -} struct SAPBootPage : public SFullArmRegSet { @@ -94,7 +91,7 @@ KickCpu(&bootPage.iAPBootPtr[a.iCpu], bp_phys); - TUint32 n = TUint32(VIB->iMaxCpuClock >> 3); + TUint32 n = TUint32(TheScheduler.iVIB->iMaxCpuClock >> 3); n = -n; TUint32 b = 0; do { diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/ncglob.cpp --- a/kernel/eka/nkernsmp/arm/ncglob.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/ncglob.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -33,8 +33,6 @@ //TSubScheduler* SubSchedulerLookupTable[256]; TUint32 CrashStateOut; SFullArmRegSet DefaultRegSet; - -SVariantInterfaceBlock* VIB; } #ifdef __USE_BTRACE_LOCK__ diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/ncmonitor.cpp --- a/kernel/eka/nkernsmp/arm/ncmonitor.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/ncmonitor.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -43,22 +43,20 @@ m.Printf("i_ScuAddr %08x i_GicDist %08x i_GicCpuIf %08x i_LocTmrA %08x\r\n", x.iScuAddr, x.iGicDistAddr, x.iGicCpuIfcAddr, x.iLocalTimerAddr); m.Printf("i_IrqCount %08x i_IrqNest %08x i_ExcInfo %08x i_CrashSt %08x\r\n", x.iIrqCount, x.iIrqNestCount, x.iExcInfo, x.iCrashState); m.Printf("i_AbtStkTp %08x i_UndSktTp %08x i_FiqStkTp %08x i_IrqStkTp %08x\r\n", x.iAbtStackTop, x.iUndStackTop, x.iFiqStackTop, x.iIrqStackTop); - m.Printf("CpuFreqM %08x CpuFreqS %08x CpuPeriodM %08x CpuPeriodS %08x\r\n", x.iCpuFreqM, x.iCpuFreqS, x.iCpuPeriodM, x.iCpuPeriodS); - m.Printf("NTmrFreqM %08x NTmrFreqS %08x NTmPeriodM %08x NTmPeriodS %08x\r\n", x.iNTimerFreqM, x.iNTimerFreqS, x.iNTimerPeriodM, x.iNTimerPeriodS); - m.Printf("TmrFreqM %08x TmrFreqS %08x TmrPeriodM %08x TmrPeriodS %08x\r\n", x.iTimerFreqM, x.iTimerFreqS, x.iTimerPeriodM, x.iTimerPeriodS); - m.Printf("iLastSyncT %08x %08x TicksSince %08x LastTmrSet %08x\r\n", I64HIGH(x.iLastSyncTime), I64LOW(x.iLastSyncTime), x.iTicksSinceLastSync, x.iLastTimerSet); - m.Printf("GapEstimat %08x GapCount %08x TotalTicks %08x Ditherer %08x\r\n", x.iGapEstimate, x.iGapCount, x.iTotalTicks, x.iDitherer); - m.Printf("FreqErrEst %08x FreqErrLim %08x ErrorInteg %08x %08x\r\n", x.iFreqErrorEstimate, x.iFreqErrorLimit, I64HIGH(x.iErrorIntegrator), I64LOW(x.iErrorIntegrator)); - m.Printf("RefAtLastC %08x %08x M=%02x N=%02x D=%02x\r\n", I64HIGH(x.iRefAtLastCorrection), I64LOW(x.iRefAtLastCorrection), x.iM, x.iN, x.iD); + m.Printf("CpuFreqM %08x CpuFreqS %08x CpuPeriodM %08x CpuPeriodS %08x\r\n", x.iCpuFreqRI.iR.iM, x.iCpuFreqRI.iR.iX, x.iCpuFreqRI.iI.iM, x.iCpuFreqRI.iI.iX); + m.Printf("TmrFreqM %08x TmrFreqS %08x TmrPeriodM %08x TmrPeriodS %08x\r\n", x.iTimerFreqRI.iR.iM, x.iTimerFreqRI.iR.iX, x.iTimerFreqRI.iI.iM, x.iTimerFreqRI.iI.iX); } void DisplaySchedulerExt(Monitor& m, TScheduler& s) { - volatile TUint32* sx = (volatile TUint32*)&s.iSX; - m.Printf("Extras 0: %08x 1: %08x 2: %08x 3: %08x\r\n",sx[0],sx[1],sx[2],sx[3]); - m.Printf("Extras 4: %08x 5: %08x 6: %08x 7: %08x\r\n",sx[4],sx[5],sx[6],sx[7]); - m.Printf("Extras 8: %08x 9: %08x A: %08x B: %08x\r\n",sx[8],sx[9],sx[10],sx[11]); - m.Printf("Extras C: %08x D: %08x E: %08x F: %08x\r\n",sx[12],sx[13],sx[14],sx[15]); + TSchedulerX& sx = s.iSX; + m.Printf("iTimerMax %08x %08x\r\n", I64HIGH(sx.iTimerMax), I64LOW(sx.iTimerMax)); + m.Printf("iGTmrA %08x iScuAddr %08x iGicDistA %08x iGicCpuIfcA %08x iLocTmrA %08x\r\n", + sx.iGlobalTimerAddr, sx.iScuAddr, sx.iGicDistAddr, sx.iGicCpuIfcAddr, sx.iLocalTimerAddr); + m.Printf("iGTFreqM %08x iGTFreqS %08x iGTPeriodM %08x iGTPeriodS %08x\r\n", + sx.iGTimerFreqRI.iR.iM, sx.iGTimerFreqRI.iR.iX, sx.iGTimerFreqRI.iI.iM, sx.iGTimerFreqRI.iI.iX); + m.Printf("iCount0 %08x %08x iTimestamp0 %08x %08x\r\n", + I64HIGH(sx.iCount0), I64LOW(sx.iCount0), I64HIGH(sx.iTimestamp0), I64LOW(sx.iTimestamp0)); } void DumpRegisters(Monitor& m, SFullArmRegSet& a) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/ncsched.cia --- a/kernel/eka/nkernsmp/arm/ncsched.cia Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/ncsched.cia Wed Jun 23 12:58:21 2010 +0100 @@ -949,15 +949,18 @@ asm("cmp r12, #0 "); asm("bne 0f "); // initial (i.e. idle) thread, so skip asm("ldr r3, [r2, #%a0]" : : "i" _FOFF(ArmLocalTimer,iTimerCount)); - asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerPeriodM)); - asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerPeriodS)); + asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqRI.iI.iM)); + asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqRI.iI.iX)); asm("cmp r3, #0 "); asm("movmi r0, #0 "); // if timer count is negative, save zero asm("bmi 1f "); - asm("umull r0, r3, r12, r3 "); // scale up to max timer clock (R3:R0) + asm("mov r2, r2, lsl #16 "); + asm("mov r2, r2, asr #16 "); + asm("umull r0, r3, r12, r3 "); // scale up to max timer clock (R3:R0) - need to shift right by -iX + asm("rsb r2, r2, #0 "); asm("rsb r12, r2, #32 "); - asm("movs r0, r0, lsr r2 "); // r0 >>= iSSX.iTimerPeriodS, C = last bit shifted off (rounding) - asm("orr r0, r0, r3, lsl r12 "); // bottom bits from r12 into top bits of r0 + asm("movs r0, r0, lsr r2 "); // r0 >>= iSSX.iTimerFreqRI.iI.iX, C = last bit shifted off (rounding) + asm("orr r0, r0, r3, lsl r12 "); // bottom bits from r3 into top bits of r0 asm("adcs r0, r0, #0 "); // round using last bit shifted off asm("1: "); asm("str r0, [r1, #%a0]" : : "i" _FOFF(NThreadBase,iTime)); @@ -971,103 +974,7 @@ #error Use of local timer for NKern::Timestamp() no longer supported #else -/* Update aOld's execution time and set up the timer for aNew - Update this CPU's timestamp value - - if (!aOld) aOld=iInitialThread - if (!aNew) aNew=iInitialThread - newcount = aNew->iTime>0 ? Max(aNew->iTime*iSSX.iTimerFreqM/2^(32+iTimerFreqS), 1) : 2^31-1 - cli() - oldcount = timer count - if (oldcount<=0 || aOld!=aNew) - { - timer count = newcount - iSSX.iLastTimerSet = newcount - if (aOld!=aNew) - { - TUint64 now = NKern::Timestamp(); - elapsed = iLastTimestamp -= now; - iLastTimestamp = now; - aOld->iTotalCpuTime.i64 += elapsed; - if (!aOld->iActiveState) - aOld->iTotalActiveTime.i64 += (now - aOld->iLastActivationTime.i64); - ++iReschedCount.i64; - ++aNew->iRunCount.i64; - } - } - sti() - */ -__NAKED__ void TSubScheduler::UpdateThreadTimes(NThreadBase* /*aOld*/, NThreadBase* /*aNew*/) - { - asm("cmp r2, #0 "); - asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iInitialThread)); - asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqM)); - asm("cmp r1, #0 "); - asm("ldreq r1, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iInitialThread)); - asm("ldr r3, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iTime)); - asm("stmfd sp!, {r4-r7} "); - asm("cmp r1, r2 "); - asm("beq 2f "); - asm("ldr r6, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[0])); - asm("ldr r7, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[1])); - asm("adds r6, r6, #1 "); - asm("str r6, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[0])); - asm("ldr r4, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[0])); - asm("ldr r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[1])); - asm("adcs r7, r7, #0 "); - asm("str r7, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[1])); - asm("adds r4, r4, #1 "); - asm("adcs r6, r6, #0 "); - asm("str r4, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[0])); - asm("str r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[1])); - asm("2: "); - asm("ldr r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iLocalTimerAddr)); - asm("cmp r3, #1 "); // aNew->iTime > 0 ? - asm("movlt r3, #0x7fffffff "); // if not, use 2^31-1 - asm("blt 3f "); - asm("cmp r1, r2 "); // different thread? - asm("beq 0f "); // no - finish - asm("ldr r5, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqS)); - asm("umull r4, r3, r12, r3 "); // r3:r4 = aNew->iTime * iTimerFreqM - asm("adds r4, r4, r4 "); // bit 31 into C - asm("teq r5, #0 "); // check for iTimerFreqS=0 without changing C - asm("movnes r3, r3, lsr r5 "); // if not, r3>>=iTimerFreqS, last bit shifted out into C - asm("adcs r3, r3, #0 "); // round using last bit shifted off - asm("3: "); - asm("str r3, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iLastTimerSet)); - asm("str r3, [r6, #%a0]" : : "i" _FOFF(ArmLocalTimer,iTimerCount)); // set new timeslice value in timer - - asm("ldr r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[0])); - asm("ldr r7, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[1])); - asm("stmfd sp!, {r0-r2,lr} "); - asm("bl Timestamp__5NKern "); // R1:R0 = current time - asm("mov r4, r0 "); - asm("mov r5, r1 "); // R5:R4 = current time - asm("ldmfd sp!, {r0-r2,lr} "); - asm("str r4, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[0])); - asm("ldr r3, [r1, #%a0]!" : : "i" _FOFF(NThreadBase,iTotalCpuTime.i64)); - asm("ldr r12, [r1, #4] "); - asm("str r5, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[1])); - asm("stmdb r1, {r4-r5} "); // aOld->iLastRunTime - asm("ldrb r2, [r1, #%a0]" : : "i" (_FOFF(NSchedulable,iActiveState)-_FOFF(NThreadBase,iTotalCpuTime.i64))); - asm("subs r6, r4, r6 "); - asm("sbcs r7, r5, r7 "); // R7:R6 = time since last reschedule - asm("adds r3, r3, r6 "); - asm("adcs r12, r12, r7 "); // total CPU time of old thread - asm("stmia r1!, {r3,r12} "); // store, r1=&aOld.iLastActivationTime - asm("cmp r2, #0 "); // old thread still active? - asm("bne 0f "); // yes - done - asm("ldmia r1!, {r2,r3,r6,r7} "); // R3:R2 = last activation time, R7:R6=total active time - asm("subs r2, r4, r2 "); - asm("sbcs r3, r5, r3 "); // R3:R2 = time since last activation - asm("adds r6, r6, r2 "); - asm("adcs r7, r7, r3 "); // R7:R6 = new total active time - asm("stmdb r1, {r6,r7} "); - - asm("0: "); - asm("ldmfd sp!, {r4-r7} "); - __JUMP(,lr); - } +#error UpdateThreadTimes assembler out of date! #endif #endif // __UTT_MACHINE_CODED__ diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/ncsched.cpp --- a/kernel/eka/nkernsmp/arm/ncsched.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/ncsched.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -163,26 +163,32 @@ #if !defined(__UTT_MACHINE_CODED__) void TSubScheduler::UpdateThreadTimes(NThreadBase* aOld, NThreadBase* aNew) { + /* If necessary update local timer frequency (DVFS) */ + SRatioInv* pNCF = iSSX.iNewCpuFreqRI; + if (pNCF) + { + iSSX.iCpuFreqRI = *pNCF; + __e32_atomic_store_rel_ptr(&iSSX.iNewCpuFreqRI, 0); + } + SRatioInv* pNTF = iSSX.iNewTimerFreqRI; + if (pNTF) + { + iSSX.iTimerFreqRI = *pNTF; + __e32_atomic_store_rel_ptr(&iSSX.iNewTimerFreqRI, 0); + } if (!aOld) aOld = iInitialThread; if (!aNew) aNew = iInitialThread; - if (aNew!=aOld || aNew->iTime<=0) + if (aNew!=aOld || aNew->iTime<=0 || pNTF) { TUint32 tmrval = 0x7fffffffu; if (aNew->iTime > 0) { - TUint64 x = TUint64(aNew->iTime) * TUint64(iSSX.iTimerFreqM); - tmrval = I64HIGH(x); - if (iSSX.iTimerFreqS) - { - tmrval += ((1u<>= iSSX.iTimerFreqS; - } - else if (I64LOW(x) & 0x80000000u) - ++tmrval; + tmrval = aNew->iTime; // this will have been computed based on the old timer frequency + iSSX.iTimerFreqRI.iR.Mult(tmrval); } - iSSX.iLastTimerSet = tmrval; +// iSSX.iLastTimerSet = tmrval; iSSX.iLocalTimerAddr->iTimerCount = tmrval; } if (aNew!=aOld) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/ncthrd.cpp --- a/kernel/eka/nkernsmp/arm/ncthrd.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/ncthrd.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -132,10 +132,32 @@ { NKern::EnableAllInterrupts(); +#if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined(__NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) + + if (cpu == 0) + { + // start global timer if necessary + ArmGlobalTimer& GT = GLOBAL_TIMER; + if (!(GT.iTimerCtrl & E_ArmGTmrCtrl_TmrEnb)) + { + // timer not currently enabled + GT.iTimerCtrl = 0; + __e32_io_completion_barrier(); + GT.iTimerStatus = E_ArmGTmrStatus_Event; + __e32_io_completion_barrier(); + GT.iTimerCountLow = 0; + GT.iTimerCountHigh = 0; + __e32_io_completion_barrier(); + GT.iTimerCtrl = E_ArmGTmrCtrl_TmrEnb; // enable timer with prescale factor of 1 + __e32_io_completion_barrier(); + } + } + +#endif + // start local timer ArmLocalTimer& T = LOCAL_TIMER; T.iTimerCtrl = E_ArmTmrCtrl_IntEn | E_ArmTmrCtrl_Reload | E_ArmTmrCtrl_Enable; - // Initialise timestamp InitTimestamp(ss, aInfo); } diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/ncutilf.cia --- a/kernel/eka/nkernsmp/arm/ncutilf.cia Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/ncutilf.cia Wed Jun 23 12:58:21 2010 +0100 @@ -20,9 +20,6 @@ #include #include -extern "C" { -extern SVariantInterfaceBlock* VIB; -} __NAKED__ void Arm::GetUserSpAndLr(TAny*) { @@ -304,11 +301,10 @@ asm("ldr r3, __TheScheduler "); asm("mrs r12, cpsr "); // r12 = saved interrupt mask asm("stmfd sp!, {r4-r7} "); - asm("ldr r5, [r3, #%a0]" : : "i" _FOFF(TScheduler,iSub[0])); // r5->subscheduler for CPU0 asm("ldr r4, [r3, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGlobalTimerAddr)); // r4 points to global timer __ASM_CLI(); // disable all interrupts - asm("ldr r6, [r5, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTicksSinceLastSync)); // r6 = count value of last frequency change (low) - asm("ldr r7, [r5, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iLastTimerSet)); // r7 = count value of last frequency change (high) + asm("ldr r6, [r3, #%a0]" : : "i" _FOFF(TScheduler,iSX.iCount0)); // r6 = count value of last frequency change (low) + asm("ldr r7, [r3, #%a0]" : : "i" (_FOFF(TScheduler,iSX.iCount0)+4)); // r7 = count value of last frequency change (high) asm("ldr r2, [r4, #%a0]" : : "i" _FOFF(ArmGlobalTimer,iTimerCountHigh)); // r2 = current timer counter high word // To read 64 bit timer value, read high, low, high @@ -317,21 +313,23 @@ asm("mov r1, r2 "); // r1 = previous value of timer counter high word asm("ldr r0, [r4, #%a0]" : : "i" _FOFF(ArmGlobalTimer,iTimerCountLow)); // r0 = current timer counter low word asm("ldr r2, [r4, #%a0]" : : "i" _FOFF(ArmGlobalTimer,iTimerCountHigh)); // r2 = current timer counter high word + asm("mov r5, r3 "); // r5 = &TheScheduler asm("cmp r1, r2 "); // high word changed? asm("bne 1b "); // if so, retry // Now have R1:R0 = 64 bit global timer count - asm("ldr r3, [r5, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iNTimerPeriodM)); // r3 = period multiplier - asm("ldr r4, [r5, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iNTimerPeriodS)); // r4 = period multiplier shift + asm("ldr r3, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iI.iM)); // r3 = period multiplier + asm("ldrsh r4, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iI.iX)); // r4 = period multiplier shift asm("subs r6, r0, r6 "); // r7:r6 = ticks from last frequency change asm("sbcs r7, r1, r7 "); asm("umull r0, r1, r6, r3 "); asm("mov r2, #0 "); asm("umlal r1, r2, r7, r3 "); // r2:r1:r0 = delta * period multiplier - asm("rsb r3, r4, #32 "); - asm("ldr r6, [r5, #%a0]!" : : "i" _FOFF(TSubScheduler,iSSX.iLastSyncTime)); // r6 = timestamp at last freq change (low) + asm("ldr r6, [r5, #%a0]!" : : "i" _FOFF(TScheduler,iSX.iTimestamp0)); // r6 = timestamp at last freq change (low) asm("ldr r7, [r5, #4] "); // r7 = timestamp at last freq change (high) asm("msr cpsr, r12 "); // restore interrupts + asm("rsb r4, r4, #0 "); + asm("rsb r3, r4, #32 "); asm("movs r0, r0, lsr r4 "); // rounding bit into C asm("orr r0, r0, r1, lsl r3 "); asm("mov r1, r1, lsr r4 "); @@ -345,6 +343,58 @@ asm(".word %a0" : : "i" ((TInt)&TheScheduler)); } +// Compensate for a change of frequency of the clocking driving the ARM Global Timer +// Call with interrupts disabled +__NAKED__ void ArmGlobalTimerFreqChg(const SRatioInv* /*aNewGTimerFreqRI*/) + { + asm("ldr r3, __TheScheduler "); + asm("stmfd sp!, {r4-r7} "); + asm("ldr r4, [r3, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGlobalTimerAddr)); // r4 points to global timer + asm("ldr r6, [r3, #%a0]" : : "i" _FOFF(TScheduler,iSX.iCount0)); // r6 = count value of last frequency change (low) + asm("ldr r7, [r3, #%a0]" : : "i" (_FOFF(TScheduler,iSX.iCount0)+4)); // r7 = count value of last frequency change (high) + asm("ldr r12, [r4, #%a0]" : : "i" _FOFF(ArmGlobalTimer,iTimerCountHigh)); // r12 = current timer counter high word + asm("mov r5, r3 "); // r5 = &TheScheduler + + // To read 64 bit timer value, read high, low, high + // If two high values match -> OK, else repeat + asm("1: "); + asm("mov r3, r12 "); // r3 = previous value of timer counter high word + asm("ldr r2, [r4, #%a0]" : : "i" _FOFF(ArmGlobalTimer,iTimerCountLow)); // r0 = current timer counter low word + asm("ldr r12, [r4, #%a0]" : : "i" _FOFF(ArmGlobalTimer,iTimerCountHigh)); // r12 = current timer counter high word + asm("cmp r3, r12 "); // high word changed? + asm("bne 1b "); // if so, retry + + // Now have R3:R2 = 64 bit global timer count + asm("str r2, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iCount0)); // update count value at last frequency change + asm("str r3, [r5, #%a0]" : : "i" (_FOFF(TScheduler,iSX.iCount0)+4)); // to be equal to current count value + asm("subs r6, r2, r6 "); // r7:r6 = ticks (at old frequency) from last frequency change + asm("sbcs r7, r3, r7 "); + asm("ldr r3, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iI.iM)); // r3 = old period multiplier + asm("ldrsh r4, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iI.iX)); // r4 = old period multiplier shift + asm("ldmia r0, {r0,r1,r2,r12} "); // r1:r0=new frequency multiplier, r12:r2=new period multiplier + asm("str r0, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iR.iM)); // update frequency multiplier + asm("str r1, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iR.iX)); // update frequency multiplier + asm("str r2, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iI.iM)); // update period multiplier + asm("str r12, [r5, #%a0]" : : "i" _FOFF(TScheduler,iSX.iGTimerFreqRI.iI.iX)); // update period multiplier + asm("umull r0, r1, r6, r3 "); + asm("mov r2, #0 "); + asm("umlal r1, r2, r7, r3 "); // r2:r1:r0 = delta * old period multiplier + asm("ldr r6, [r5, #%a0]!" : : "i" _FOFF(TScheduler,iSX.iTimestamp0)); // r6 = timestamp at last freq change (low) + asm("ldr r7, [r5, #4] "); // r7 = timestamp at last freq change (high) + asm("rsb r4, r4, #0 "); + asm("rsb r3, r4, #32 "); + asm("movs r0, r0, lsr r4 "); // rounding bit into C + asm("orr r0, r0, r1, lsl r3 "); + asm("mov r1, r1, lsr r4 "); + asm("orr r1, r1, r2, lsl r3 "); // r1:r0 = (delta * old period multiplier) >> old period multiplier shift + asm("adcs r0, r0, r6 "); // scaled delta + timestamp at last freq change + asm("adcs r1, r1, r7 "); + asm("stmia r5, {r0,r1} "); // timestamp at last freq change = now + __DATA_MEMORY_BARRIER_Z__(r12); /* Ensure all updates visible */ + asm("ldmfd sp!, {r4-r7} "); + __JUMP(,lr); + } + #elif defined(__NKERN_TIMESTAMP_USE_INLINE_BSP_CODE__) #define __DEFINE_NKERN_TIMESTAMP_ASM__ #include diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/arm/ncutils.cpp --- a/kernel/eka/nkernsmp/arm/ncutils.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/arm/ncutils.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -22,8 +22,6 @@ #include extern "C" { -extern SVariantInterfaceBlock* VIB; - extern TUint KernCoreStats_EnterIdle(TUint aCore); extern void KernCoreStats_LeaveIdle(TInt aCookie,TUint aCore); @@ -31,6 +29,7 @@ extern void send_irq_ipi(TSubScheduler*, TInt); } +TInt ClockFrequenciesChanged(); /****************************************************************************** @@ -89,66 +88,47 @@ void NKern::Init0(TAny* a) { __KTRACE_OPT(KBOOT,DEBUGPRINT("VIB=%08x", a)); - VIB = (SVariantInterfaceBlock*)a; - __NK_ASSERT_ALWAYS(VIB && VIB->iVer==0 && VIB->iSize==sizeof(SVariantInterfaceBlock)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", VIB->iVer, VIB->iSize)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(VIB->iMaxCpuClock), I64LOW(VIB->iMaxCpuClock))); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", VIB->iMaxTimerClock)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iScuAddr=%08x", VIB->iScuAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicDistAddr=%08x", VIB->iGicDistAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicCpuIfcAddr=%08x", VIB->iGicCpuIfcAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iLocalTimerAddr=%08x", VIB->iLocalTimerAddr)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iGlobalTimerAddr=%08x", VIB->iGlobalTimerAddr)); + SVariantInterfaceBlock* v = (SVariantInterfaceBlock*)a; + TheScheduler.iVIB = v; + __NK_ASSERT_ALWAYS(v && v->iVer==0 && v->iSize==sizeof(SVariantInterfaceBlock)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", v->iVer, v->iSize)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(v->iMaxCpuClock), I64LOW(v->iMaxCpuClock))); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", v->iMaxTimerClock)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iScuAddr=%08x", v->iScuAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicDistAddr=%08x", v->iGicDistAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iGicCpuIfcAddr=%08x", v->iGicCpuIfcAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iLocalTimerAddr=%08x", v->iLocalTimerAddr)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iGlobalTimerAddr=%08x", v->iGlobalTimerAddr)); TScheduler& s = TheScheduler; - s.iSX.iScuAddr = (ArmScu*)VIB->iScuAddr; - s.iSX.iGicDistAddr = (GicDistributor*)VIB->iGicDistAddr; - s.iSX.iGicCpuIfcAddr = (GicCpuIfc*)VIB->iGicCpuIfcAddr; - s.iSX.iLocalTimerAddr = (ArmLocalTimer*)VIB->iLocalTimerAddr; - s.iSX.iTimerMax = (VIB->iMaxTimerClock / 1); // use prescaler value of 1 + s.iSX.iScuAddr = (ArmScu*)v->iScuAddr; + s.iSX.iGicDistAddr = (GicDistributor*)v->iGicDistAddr; + s.iSX.iGicCpuIfcAddr = (GicCpuIfc*)v->iGicCpuIfcAddr; + s.iSX.iLocalTimerAddr = (ArmLocalTimer*)v->iLocalTimerAddr; + s.iSX.iTimerMax = (v->iMaxTimerClock / 1); // use prescaler value of 1 #ifdef __CPU_ARM_HAS_GLOBAL_TIMER_BLOCK - s.iSX.iGlobalTimerAddr = (ArmGlobalTimer*)VIB->iGlobalTimerAddr; + s.iSX.iGlobalTimerAddr = (ArmGlobalTimer*)v->iGlobalTimerAddr; + s.iSX.iGTimerFreqRI.Set(v->iGTimerFreqR); + v->iGTimerFreqR = 0; #endif TInt i; for (i=0; iiTimerMult[i] = 0; - VIB->iCpuMult[i] = 0; - UPerCpuUncached* u = VIB->iUncached[i]; + ss.iSSX.iCpuFreqRI.Set(v->iCpuFreqR[i]); + ss.iSSX.iTimerFreqRI.Set(v->iTimerFreqR[i]); + + v->iCpuFreqR[i] = 0; + v->iTimerFreqR[i] = 0; + UPerCpuUncached* u = v->iUncached[i]; ss.iUncached = u; u->iU.iDetachCount = 0; u->iU.iAttachCount = 0; u->iU.iPowerOffReq = FALSE; u->iU.iDetachCompleteFn = &DetachComplete; } + v->iFrqChgFn = &ClockFrequenciesChanged; __e32_io_completion_barrier(); InterruptInit0(); } @@ -374,16 +354,11 @@ s.AllCpusIdle(); s.iIdleSpinLock.UnlockOnly(); - //TUint cookie = KernCoreStats::EnterIdle((TUint8)ss.iCpuNum); TUint cookie = KernCoreStats_EnterIdle((TUint8)ss.iCpuNum); arg |= retire; NKIdle(arg); - //KernCoreStats::LeaveIdle(cookie, (TUint8)ss.iCpuNum); - KernCoreStats_LeaveIdle(cookie, (TUint8)ss.iCpuNum); - - // interrupts have not been reenabled s.iIdleSpinLock.LockOnly(); @@ -415,6 +390,8 @@ if (ci == 0) s.FirstBackFromIdle(); + KernCoreStats_LeaveIdle(cookie, (TUint8)ss.iCpuNum); + if (retire) { s.iCCReactivateDfc.RawAdd(); // kick load balancer to give us some work @@ -432,12 +409,12 @@ TBool TScheduler::CoreControlSupported() { - return VIB->iCpuPowerUpFn != 0; + return TheScheduler.iVIB->iCpuPowerUpFn != 0; } void TScheduler::CCInitiatePowerUp(TUint32 aCores) { - TCpuPowerUpFn pUp = VIB->iCpuPowerUpFn; + TCpuPowerUpFn pUp = TheScheduler.iVIB->iCpuPowerUpFn; if (pUp && aCores) { TInt i; @@ -463,7 +440,7 @@ void TScheduler::CCIndirectPowerDown(TAny*) { - TCpuPowerDownFn pDown = VIB->iCpuPowerDownFn; + TCpuPowerDownFn pDown = TheScheduler.iVIB->iCpuPowerDownFn; if (pDown) { TInt i; @@ -555,3 +532,167 @@ #endif } +/****************************************************************************** + * Notify frequency changes + ******************************************************************************/ + +struct SFrequencies + { + void Populate(); + void Apply(); + TBool AddToQueue(); + + SFrequencies* iNext; + TUint32 iWhich; + SRatioInv iNewCpuRI[KMaxCpus]; + SRatioInv iNewTimerRI[KMaxCpus]; + SRatioInv iNewGTimerRI; + NFastSemaphore* iSem; + + static SFrequencies* volatile Head; + }; + +SFrequencies* volatile SFrequencies::Head; + +TBool SFrequencies::AddToQueue() + { + SFrequencies* h = Head; + do { + iNext = h; + } while(!__e32_atomic_cas_rel_ptr(&Head, &h, this)); + return !h; // TRUE if list was empty + } + + +void SFrequencies::Populate() + { + TScheduler& s = TheScheduler; + TInt cpu; + iWhich = 0; + SRatio* ri = (SRatio*)__e32_atomic_swp_ord_ptr(&s.iVIB->iGTimerFreqR, 0); + if (ri) + { + iNewGTimerRI.Set(ri); + iWhich |= 0x80000000u; + } + for (cpu=0; cpuiCpuFreqR[cpu], 0); + if (ri) + { + iNewCpuRI[cpu].Set(ri); + iWhich |= ss.iCpuMask; + } + ri = (SRatio*)__e32_atomic_swp_ord_ptr(&s.iVIB->iTimerFreqR[cpu], 0); + if (ri) + { + iNewTimerRI[cpu].Set(ri); + iWhich |= (ss.iCpuMask<<8); + } + } + } + +#if defined(__NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) +extern void ArmGlobalTimerFreqChg(const SRatioInv* /*aNewGTimerFreqRI*/); +#endif + +void SFrequencies::Apply() + { + if (!iWhich) + return; + TScheduler& s = TheScheduler; + TStopIPI ipi; + TUint32 stopped = ipi.StopCPUs(); + TInt cpu; + TUint32 wait = 0; + for (cpu=0; cpuPopulate(); + list->Apply(); + SFrequencies* rev = 0; + while (list) + { + SFrequencies* next = list->iNext; + list->iNext = rev; + rev = list; + list = next; + } + while (rev) + { + NFastSemaphore* s = rev->iSem; + rev = rev->iNext; + NKern::FSSignal(s); + } + } + +TInt ClockFrequenciesChanged() + { + TScheduler& s = TheScheduler; + NFastSemaphore sem(0); + SFrequencies f; + f.iSem = &sem; + NThread* ct = NKern::CurrentThread(); + NThread* lbt = TScheduler::LBThread(); + NKern::ThreadEnterCS(); + TBool first = f.AddToQueue(); + if (!lbt || lbt == ct) + TScheduler::DoFrequencyChanged(&s); + else if (first) + s.iFreqChgDfc.Enque(); + NKern::FSWait(&sem); + NKern::ThreadLeaveCS(); + return KErrNone; + } + diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/nk_bal.cpp --- a/kernel/eka/nkernsmp/nk_bal.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/nk_bal.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -135,6 +135,7 @@ s.iCCReactivateDfc.SetDfcQ(rbQ); s.iCCRequestDfc.SetDfcQ(rbQ); s.iCCPowerDownDfc.SetDfcQ(rbQ); + s.iFreqChgDfc.SetDfcQ(rbQ); NThreadBase* lbt = rbQ->iThread; lbt->iRebalanceAttr = 1; TUint32 f = NKern::CpuTimeMeasFreq(); diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/nkern.cpp --- a/kernel/eka/nkernsmp/nkern.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/nkern.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -2846,28 +2846,62 @@ /** Stop all other CPUs - Call with kernel locked +Call with kernel unlocked, returns with kernel locked. +Returns mask of CPUs halted plus current CPU. */ -void TStopIPI::StopCPUs() +TUint32 TStopIPI::StopCPUs() { + CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"TStopIPI::StopCPUs()"); + TScheduler& s = TheScheduler; iFlag = 0; + NKern::ThreadEnterCS(); + + // Stop any cores powering up or down for now + // A core already on the way down will stop just before the transition to SHUTDOWN_FINAL + // A core already on the way up will carry on powering up + TInt irq = s.iGenIPILock.LockIrqSave(); + ++s.iCCDeferCount; // stops bits in iIpiAcceptCpus being cleared, but doesn't stop them being set + // but iIpiAcceptCpus | s.iCpusComingUp is constant + TUint32 act2 = s.iIpiAcceptCpus; // CPUs still accepting IPIs + TUint32 cu = s.iCpusComingUp; // CPUs powering up + s.iGenIPILock.UnlockIrqRestore(irq); + TUint32 cores = act2 | cu; + if (cu) + { + // wait for CPUs coming up to start accepting IPIs + while (cores & ~s.iIpiAcceptCpus) + { + __snooze(); // snooze until cores have come up + } + } + NKern::Lock(); QueueAllOther(&Isr); // send IPIs to all other CPUs WaitEntry(); // wait for other CPUs to reach the ISR + return cores; } + +/** Release the stopped CPUs + +Call with kernel locked, returns with kernel unlocked. +*/ void TStopIPI::ReleaseCPUs() { - iFlag = 1; // allow other CPUs to proceed + __e32_atomic_store_rel32(&iFlag, 1); // allow other CPUs to proceed WaitCompletion(); // wait for them to finish with this IPI + NKern::Unlock(); + TheScheduler.CCUnDefer(); + NKern::ThreadLeaveCS(); } void TStopIPI::Isr(TGenericIPI* a) { TStopIPI* s = (TStopIPI*)a; - while (!s->iFlag) + while (!__e32_atomic_load_acq32(&s->iFlag)) { __chill(); } + __e32_io_completion_barrier(); } diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/nkern.mmp --- a/kernel/eka/nkernsmp/nkern.mmp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/nkern.mmp Wed Jun 23 12:58:21 2010 +0100 @@ -17,6 +17,8 @@ sourcepath ../nkernsmp source nkern.cpp nkerns.cpp sched.cpp dfcs.cpp nk_timer.cpp nk_irq.cpp nk_bal.cpp +sourcepath ../nkern +source nklib.cpp #ifdef MARM sourcepath ../common/arm @@ -24,6 +26,8 @@ sourcepath ../nkernsmp/arm source vectors.cia ncsched.cpp ncsched.cia nctimer.cia ncutilf.cia ncirq.cpp ncirq.cia ncthrd.cia source ncutils.cia ncutils.cpp ncthrd.cpp ncglob.cpp nccpu.cpp nccpu.cia +sourcepath ../nkern/arm +source nklib.cia #elif defined(X86) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/nkerns.cpp --- a/kernel/eka/nkernsmp/nkerns.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/nkerns.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -242,8 +242,8 @@ iCurrent = iReady; iCpuAffinity = iLastCpu; iEventState = (iLastCpu<iThread); + TDfcQue* rbQ = TheScheduler.iRebalanceDfcQ; + return rbQ ? (NThread*)(rbQ->iThread) : 0; } diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/sched.cpp --- a/kernel/eka/nkernsmp/sched.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/sched.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -60,7 +60,8 @@ iCCRequestLevel(1), // only boot CPU for now iCCRequestDfc(&CCRequestDfcFn, this, 2), iCCPowerDownDfc(&CCIndirectPowerDown, this, 0), - iCCIpiReactIDFC(&CCIpiReactivateFn, this) + iCCIpiReactIDFC(&CCIpiReactivateFn, this), + iFreqChgDfc(&DoFrequencyChanged, this, 6) { TInt i; for (i=0; iiTime>0 && !aT->i_NThread_Initial) { - TUint32 remain32 = read_apic_reg(CURRCNT); - TUint64 x(remain32); - x *= TUint32(iSSX.iTimerPeriodM); - x += 1u<<(iSSX.iTimerPeriodS-1); - x >>= iSSX.iTimerPeriodS; + TUint32 x = read_apic_reg(CURRCNT); + iSSX.iTimerFreqRI.iI.Mult(x); aT->iTime = (TInt)x; } write_apic_reg(INITCNT, 0); @@ -128,13 +125,9 @@ aNew = iInitialThread; if (aNew->iTime>0) { - TUint32 remain32 = (TUint32)aNew->iTime; - TUint64 x(remain32); - x *= TUint32(iSSX.iTimerFreqM); - x += TUint64(0x80000000u)<>= (32+iSSX.iTimerFreqS); - write_apic_reg(LVTTMR, TIMESLICE_VECTOR); - write_apic_reg(INITCNT, (TUint32)x); + TUint32 x = (TUint32)aNew->iTime; + iSSX.iTimerFreqRI.iR.Mult(x); + write_apic_reg(INITCNT, x); } if (aNew!=aOld) { diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/x86/ncutilf.cpp --- a/kernel/eka/nkernsmp/x86/ncutilf.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/x86/ncutilf.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -15,11 +15,8 @@ // // -#include +#include -extern "C" { -extern SVariantInterfaceBlock* VIB; -} /****************************************************************************** * Spin lock @@ -65,6 +62,6 @@ */ EXPORT_C TUint32 NKern::TimestampFrequency() { - return VIB->iTimestampFreq; + return TheScheduler.iVIB->iTimestampFreq; } diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/nkernsmp/x86/ncutils.cpp --- a/kernel/eka/nkernsmp/x86/ncutils.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/nkernsmp/x86/ncutils.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -17,10 +17,6 @@ #include -extern "C" { -extern SVariantInterfaceBlock* VIB; -} - //#define __DBG_MON_FAULT__ //#define __RAM_LOADED_CODE__ //#define __EARLY_DEBUG__ @@ -325,33 +321,25 @@ void NKern::Init0(TAny* a) { __KTRACE_OPT(KBOOT,DEBUGPRINT("VIB=%08x", a)); - VIB = (SVariantInterfaceBlock*)a; - __NK_ASSERT_ALWAYS(VIB && VIB->iVer==0 && VIB->iSize==sizeof(SVariantInterfaceBlock)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", VIB->iVer, VIB->iSize)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(VIB->iMaxCpuClock), I64LOW(VIB->iMaxCpuClock))); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iTimestampFreq=%u", VIB->iTimestampFreq)); - __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", VIB->iMaxTimerClock)); + SVariantInterfaceBlock* v = (SVariantInterfaceBlock*)a; + TheScheduler.iVIB = v; + __NK_ASSERT_ALWAYS(v && v->iVer==0 && v->iSize==sizeof(SVariantInterfaceBlock)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iVer=%d iSize=%d", v->iVer, v->iSize)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxCpuClock=%08x %08x", I64HIGH(v->iMaxCpuClock), I64LOW(v->iMaxCpuClock))); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iTimestampFreq=%u", v->iTimestampFreq)); + __KTRACE_OPT(KBOOT,DEBUGPRINT("iMaxTimerClock=%u", v->iMaxTimerClock)); TInt i; for (i=0; iiCpuFreqR[i]); + ss.iSSX.iTimerFreqRI.Set(v->iTimerFreqR[i]); + ss.iSSX.iTimestampOffset.i64 = 0; - VIB->iTimerMult[i] = 0; - VIB->iCpuMult[i] = 0; + v->iCpuFreqR[i] = 0; + v->iTimerFreqR[i] = 0; } - TheScheduler.iSX.iTimerMax = (VIB->iMaxTimerClock / 128); + TheScheduler.iSX.iTimerMax = (v->iMaxTimerClock / 128); InitFpu(); InterruptInit0(); } @@ -400,3 +388,6 @@ { } +void TScheduler::DoFrequencyChanged(TAny*) + { + } diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/release.txt --- a/kernel/eka/release.txt Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/release.txt Wed Jun 23 12:58:21 2010 +0100 @@ -1,3 +1,12 @@ +Version 2.00.3098 +================= +(Made by vfebvre 18/06/2010) + +1. garciato + 1. RP520151 + REQ:417-52765 - SMP: Product Quality SMP Kernel for Bridge + + Version 2.00.3097 ================= (Made by vfebvre 16/06/2010) diff -r af6ec97d9189 -r a232af6b0b1f kernel/eka/rombuild/kernel.hby --- a/kernel/eka/rombuild/kernel.hby Wed Jun 23 12:52:28 2010 +0100 +++ b/kernel/eka/rombuild/kernel.hby Wed Jun 23 12:58:21 2010 +0100 @@ -17,10 +17,12 @@ #define EKernelConfigSMPUnsafeCompat 12 #define EKernelConfigSMPUnsafeCPU0 13 #define EKernelConfigSMPCrazyInterrupts 14 +#define EKernelConfigSMPLockKernelThreadsCore0 15 #define EKernelConfigDisableAPs 30 #define CRAZYSCHEDULING(state) kernelconfig EKernelConfigCrazyScheduling state #define SMPUNSAFECOMPAT(state) kernelconfig EKernelConfigSMPUnsafeCompat state #define SMPUNSAFECPU0(state) kernelconfig EKernelConfigSMPUnsafeCPU0 state #define CRAZYINTERRUPTS(state) kernelconfig EKernelConfigSMPCrazyInterrupts state +#define SMPLOCKKERNELTHREADSCPU0(state) kernelconfig EKernelConfigSMPLockKernelThreadsCore0 state #define SMP_USE_BP_ONLY(state) kernelconfig EKernelConfigDisableAPs state diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/group/bld.inf --- a/kerneltest/e32test/group/bld.inf Wed Jun 23 12:52:28 2010 +0100 +++ b/kerneltest/e32test/group/bld.inf Wed Jun 23 12:58:21 2010 +0100 @@ -83,6 +83,7 @@ positive check ( #ifdef SMP ), however these binaries will not be included in BTB autotest images for SMP platforms. Refer to DTW-KHS BTB00055 for more details. ******************************************************************************/ +d_timestamp support d_kerncorestats support d_implicit support d_emitest support @@ -711,6 +712,9 @@ t_domain_slave support domainPolicyTest support t_switchoff +t_frqchg +// /E32TEST/TIMESTAMP test +t_timestamp // /E32TEST/PRIME tests t_kern support @@ -1064,7 +1068,4 @@ //pci tests t_pci -// timestamp or fastcounter test -t_timestamp -d_timestamp support diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/group/d_frqchg.mmh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/group/d_frqchg.mmh Wed Jun 23 12:58:21 2010 +0100 @@ -0,0 +1,48 @@ +// Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test/group/d_frqchg.mmh +// +// + +// NOTE : include your variant.mmh before this file + +#ifdef EPOC32 +target VariantTarget(d_frqchg,ldd) +#else +target d_frqchg.ldd +#endif +#include "kernel/kern_ext.mmh" + +targettype ldd +romtarget d_frqchg.ldd + +sourcepath ../power +source d_frqchg.cpp + +sourcepath ../../../kernel/eka/nkern +source nklib.cpp + +#ifdef MARM +sourcepath ../../../kernel/eka/nkern/arm +source nklib.cia +#endif + + +epocallowdlldata + +vendorid 0x70000001 +capability all + +macro CPU_AFFINITY_ANY +smpsafe diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/group/t_frqchg.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/group/t_frqchg.mmp Wed Jun 23 12:58:21 2010 +0100 @@ -0,0 +1,27 @@ +// Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\group\t_frqchg.mmp +// +// + +target t_frqchg.exe +targettype exe +sourcepath ../power +source t_frqchg.cpp +library euser.lib hal.lib +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +capability all +vendorid 0x70000001 +epocheapsize 0x00001000 0x00100000 +smpsafe diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/group/t_semutx.mmp --- a/kerneltest/e32test/group/t_semutx.mmp Wed Jun 23 12:52:28 2010 +0100 +++ b/kerneltest/e32test/group/t_semutx.mmp Wed Jun 23 12:58:21 2010 +0100 @@ -19,7 +19,7 @@ TARGETTYPE EXE SOURCEPATH ../prime SOURCE t_semutx.cpp -LIBRARY euser.lib +LIBRARY euser.lib hal.lib OS_LAYER_SYSTEMINCLUDE_SYMBIAN diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/power/d_frqchg.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/power/d_frqchg.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -0,0 +1,421 @@ +// Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\power\d_frqchg.cpp +// LDD for testing frequency changing +// +// + +#include +#include "d_frqchg.h" + +#if defined(__EPOC32__) && defined(__SMP__) && defined(__MARM__) +#define __SUPPORT_LOCAL_TIMER_PRESCALE__ + +#include +#include +#endif + + +#ifdef __PLATFORM_SUPPORTS_DVFS__ +/** + Baseport needs to supply this function to disable DVFS whilst test is running. + The test relies on changing prescalers in local and global timer directly rather than + actually changing frequency. Consequently DVFS must be disabled when the test is running + + This function when driver is loaded. + @return KErrNone if succesful + */ +extern TInt DisableDvfs(); + +/** + if plaftorm supports DVFS this function will be called when the driver is unloaded + */ +extern void RestoreDvfs(); +#endif + + + +#if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__) +TInt Multiply(SRatio& aDest, const SRatio& aSrc) + { + TUint64 x = aDest.iM; + TUint64 y = aSrc.iM; + x *= y; + if (x==0) + { + aDest.iM = 0; + aDest.iX = 0; + return KErrNone; + } + TInt exp = aDest.iX + aSrc.iX + 32; + if (TInt64(x) >= 0) + x<<=1, --exp; + aDest.iM = I64HIGH(x); + if (I64LOW(x) & 0x80000000u) + { + if (++aDest.iM == 0) + aDest.iM = 0x80000000u, ++exp; + } + if (exp > 32767) + { + aDest.iM = 0xffffffffu; + aDest.iX = 32767; + return KErrOverflow; + } + if (exp < -32768) + { + aDest.iM = 0; + aDest.iX = 0; + return KErrUnderflow; + } + aDest.iX = (TInt16)exp; + return KErrNone; + } + +// Calculate frequency ratio for specified prescale value +// Ratio = (default+1)/(current+1) +void PrescaleRatio(SRatio& aR, TInt aDefault, TInt aCurrent) + { + SRatio df; + df.Set(TUint32(aDefault+1)); + aR.Set(TUint32(aCurrent+1)); + aR.Reciprocal(); + Multiply(aR, df); + } +#endif + +class DFrqChgFactory : public DLogicalDevice +// +// Test LDD factory +// + { +public: + DFrqChgFactory(); + virtual ~DFrqChgFactory(); + virtual TInt Install(); //overriding pure virtual + virtual void GetCaps(TDes8& aDes) const; //overriding pure virtual + virtual TInt Create(DLogicalChannelBase*& aChannel); //overriding pure virtual + }; + +class DFrqChg : public DLogicalChannelBase +// +// Test logical channel +// + { +public: + virtual ~DFrqChg(); +protected: + virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); + virtual TInt Request(TInt aReqNo, TAny* a1, TAny* a2); +#if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__) + void PopulateDefaultPrescaleList(); + void SetLocalTimerPrescaler(TUint32 aCpus, TInt aPrescale); + TScheduler* iS; + TInt iDefaultPrescale[KMaxCpus]; +#if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) + void SetGlobalTimerPrescaler(TInt aPrescale); + TInt iDefaultGTPrescale; +#endif +#endif + + }; + + + +DECLARE_STANDARD_LDD() + { + return new DFrqChgFactory; + } + +// +// Constructor +// +DFrqChgFactory::DFrqChgFactory() + { + } + +// +// Destructor, called on unload +// +DFrqChgFactory::~DFrqChgFactory() + { +#ifdef __PLATFORM_SUPPORTS_DVFS__ + RestoreDvfs(); +#endif + } + + + +// +// Create new channel +// +TInt DFrqChgFactory::Create(DLogicalChannelBase*& aChannel) + { + aChannel=new DFrqChg; + return aChannel?KErrNone:KErrNoMemory; + } + + +// +// Install the LDD - overriding pure virtual +// +TInt DFrqChgFactory::Install() + { +#ifdef __PLATFORM_SUPPORTS_DVFS__ + TInt r = DisableDvfs(); + if (KErrNone != r) return r; +#endif + return SetName(&KLddName); + } + + +// +// Get capabilities - overriding pure virtual +// +void DFrqChgFactory::GetCaps(TDes8& /*aDes*/) const + { + } + + +// +// Create channel +// +TInt DFrqChg::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) + { +#if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__) + iS = (TScheduler*)TScheduler::Ptr(); + PopulateDefaultPrescaleList(); +#endif + return KErrNone; + } + + +// +// Destructor +// +DFrqChg::~DFrqChg() + { +#if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__) + // restore prescalers + SetLocalTimerPrescaler((TUint32) -1, -1); +#if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) + SetGlobalTimerPrescaler(-1); +#endif +#endif + } + + +TInt DFrqChg::Request(TInt aReqNo, TAny* a1, TAny* a2) + { + SRatioInv ri; + TInt r = KErrNone; + switch (aReqNo) + { + case RFrqChg::EControl_RatioSet: + { + kumemget32(&ri.iR, a1, sizeof(SRatio)); + ri.iR.Set(ri.iR.iM, (TUint32)a2); + kumemput32(a1, &ri.iR, sizeof(SRatio)); + break; + } + case RFrqChg::EControl_RatioReciprocal: + { + kumemget32(&ri.iR, a1, sizeof(SRatio)); + r = ri.iR.Reciprocal(); + kumemput32(a1, &ri.iR, sizeof(SRatio)); + break; + } + case RFrqChg::EControl_RatioMult: + { + kumemget32(&ri.iR, a1, sizeof(SRatio)); + kumemget32(&ri.iI.iM, a2, sizeof(TUint32)); + r = ri.iR.Mult(ri.iI.iM); + kumemput32(a2, &ri.iI.iM, sizeof(TUint32)); + break; + } + case RFrqChg::EControl_RatioInvSet: + { + SRatio ratio; + const SRatio* p = 0; + if (a2) + { + kumemget32(&ratio, a2, sizeof(SRatio)); + p = ∶ + } + ri.Set(p); + kumemput32(a1, &ri, sizeof(SRatioInv)); + break; + } +#if defined(__EPOC32__) && defined(__SMP__) && defined(__MARM__) + case RFrqChg::EControl_FrqChgTestPresent: + break; + case RFrqChg::EControl_SetCurrentThreadPriority: + NKern::ThreadSetPriority(NKern::CurrentThread(), (TInt)a1); + break; + case RFrqChg::EControl_SetCurrentThreadCpu: + { + TUint32 old = 0; + old = NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), (TUint32)a1); + if (a2) + { + kumemput32(a2, &old, sizeof(TUint32)); + } + + old = NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), (TUint32)a1); + } + + break; + case RFrqChg::EControl_SetCurrentThreadTimeslice: + { + TInt ts = NKern::TimesliceTicks((TUint32)a1); + NKern::ThreadSetTimeslice(NKern::CurrentThread(), ts); + NKern::YieldTimeslice(); + break; + } +#endif +#if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__) + case RFrqChg::EControl_SetLocalTimerPrescaler: + { + TUint32 cpus = (TUint32)a1; + TInt prescale = (TInt)a2; + SetLocalTimerPrescaler(cpus, prescale); + break; + } +#if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) + case RFrqChg::EControl_ReadGlobalTimerAndTimestamp: + { + ArmGlobalTimer* tmr = iS->iSX.iGlobalTimerAddr; + TUint32 highlow[2]; + do + { + highlow[1] = tmr->iTimerCountHigh; + highlow[0] = tmr->iTimerCountLow; + } while(highlow[1]!=tmr->iTimerCountHigh); + TUint64 ts = NKern::Timestamp(); + kumemput32(a1,&highlow[0],sizeof(TUint64)); + kumemput32(a2,&ts,sizeof(TUint64)); + break; + } + case RFrqChg::EControl_SetGlobalTimerPrescaler: + { + SetGlobalTimerPrescaler((TInt)a1); + break; + } +#endif +#endif + default: + r = KErrNotSupported; + break; + } + return r; + } + + +#if defined(__SUPPORT_LOCAL_TIMER_PRESCALE__) +void DFrqChg::PopulateDefaultPrescaleList() + { + TInt nc = NKern::NumberOfCpus(); + NThread* nt = NKern::CurrentThread(); + TUint32 aff0 = NKern::ThreadSetCpuAffinity(nt, 0); + TInt i; + for (i=0; iiSX.iLocalTimerAddr; + TInt pv = (tmr->iTimerCtrl & E_ArmTmrCtrl_PrescaleMask) >> E_ArmTmrCtrl_PrescaleShift; + iDefaultPrescale[i] = pv; + } + NKern::ThreadSetCpuAffinity(nt, aff0); +#if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) + ArmGlobalTimer* tmr = iS->iSX.iGlobalTimerAddr; + TInt pv = (tmr->iTimerCtrl & E_ArmGTmrCtrl_PrescaleMask) >> E_ArmGTmrCtrl_PrescaleShift; + iDefaultGTPrescale = pv; +#endif + } + +void DFrqChg::SetLocalTimerPrescaler(TUint32 aCpus, TInt aPrescale) + { + TInt nc = NKern::NumberOfCpus(); + NThread* nt = NKern::CurrentThread(); + TUint32 aff0 = NKern::ThreadSetCpuAffinity(nt, 0); + TInt i; + for (i=0; iiSX.iLocalTimerAddr; + tmr->iTimerCtrl = (tmr->iTimerCtrl &~ E_ArmTmrCtrl_PrescaleMask) | ((pv << E_ArmTmrCtrl_PrescaleShift) & E_ArmTmrCtrl_PrescaleMask); + __e32_io_completion_barrier(); + NKern::RestoreInterrupts(irq); + } + } + NKern::ThreadSetCpuAffinity(nt, aff0); + if (aCpus & 0x80000000u) + { + // notify nanokernel of frequency changes + SVariantInterfaceBlock* vib = iS->iVIB; + SRatio ratio[KMaxCpus]; + for (i=0; iiTimerFreqR[i] = &ratio[i]; + } + } + (*vib->iFrqChgFn)(); + } + } + +#if defined(__CPU_ARM_HAS_GLOBAL_TIMER_BLOCK) && defined( __NKERN_TIMESTAMP_USE_SCU_GLOBAL_TIMER__) +void DFrqChg::SetGlobalTimerPrescaler(TInt aPrescale) + { + TInt pv = aPrescale; + if (pv <= 0) + pv = iDefaultGTPrescale; + + ArmGlobalTimer* tmr = iS->iSX.iGlobalTimerAddr; + // TInt irq = NKern::DisableAllInterrupts(); + tmr->iTimerCtrl = (tmr->iTimerCtrl &~ E_ArmGTmrCtrl_PrescaleMask) | ((pv << E_ArmGTmrCtrl_PrescaleShift) & E_ArmGTmrCtrl_PrescaleMask); + __e32_io_completion_barrier(); + // NKern::RestoreInterrupts(irq); + + // notify nanokernel of frequency changes + SVariantInterfaceBlock* vib = iS->iVIB; + SRatio ratio; + + if (aPrescale<=0) + ratio.Set(1); + else + PrescaleRatio(ratio, iDefaultGTPrescale, aPrescale); + + vib->iGTimerFreqR = ∶ + (*vib->iFrqChgFn)(); + } + +#endif +#endif + diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/power/d_frqchg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/power/d_frqchg.h Wed Jun 23 12:58:21 2010 +0100 @@ -0,0 +1,107 @@ +// Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\power\d_frqchg.h +// +// + +#if !defined(__D_FRQCHG_H__) +#define __D_FRQCHG_H__ + +#include + +struct SRatio; +struct SRatioInv; + +#ifndef __KERNEL_MODE__ +#include + +struct SRatio + { + TUint32 iM; // mantissa, normalised so bit 31=1 + TInt16 iX; // -exponent. + TUint8 iSpare1; + TUint8 iSpare2; + }; + +struct SRatioInv + { + SRatio iR; + SRatio iI; + }; +#endif + +_LIT(KLddName,"D_FRQCHG.LDD"); + +class RFrqChg : public RBusLogicalChannel + { +public: + enum TControl + { + EControl_RatioSet, + EControl_RatioReciprocal, + EControl_RatioMult, + EControl_RatioInvSet, + EControl_FrqChgTestPresent, + EControl_SetCurrentThreadPriority, + EControl_SetCurrentThreadCpu, + EControl_SetCurrentThreadTimeslice, + EControl_SetLocalTimerPrescaler, + EControl_ReadGlobalTimerAndTimestamp, + EControl_SetGlobalTimerPrescaler, + ENumControls + }; + +public: + inline TInt Open(); + inline TInt RatioSet(SRatio& aRatio, TUint32 aInt, TInt aDivisorExp=0); + inline TInt RatioReciprocal(SRatio& aRatio); + inline TInt RatioMult(SRatio& aRatio, TUint32& aInt32); + inline TInt RatioInvSet(SRatioInv& aRI, const SRatio* aR); + inline TInt FrqChgTestPresent(); + inline TInt SetCurrentThreadPriority(TInt aPri); + inline TInt SetCurrentThreadCpu(TUint32 aCpu, TUint32* aOldAffinity = NULL); + inline TInt SetCurrentThreadTimeslice(TInt aSlice); + inline TInt SetLocalTimerPrescaler(TUint32 aCpus, TInt aPrescale); + inline TInt ReadGlobalTimerAndTimestamp(TUint64& aTimerValue, TUint64& aTimestamp); + inline TInt SetGlobalTimerPrescaler(TInt aPrescale); + }; + +#ifndef __KERNEL_MODE__ +inline TInt RFrqChg::Open() + { return DoCreate(KLddName,TVersion(0,1,1),KNullUnit,NULL,NULL); } +inline TInt RFrqChg::RatioSet(SRatio& aR, TUint32 aInt, TInt aDivisorExp) + { aR.iM=aInt; return DoControl(EControl_RatioSet, (TAny*)&aR, (TAny*)aDivisorExp); } +inline TInt RFrqChg::RatioReciprocal(SRatio& aR) + { return DoControl(EControl_RatioReciprocal, (TAny*)&aR); } +inline TInt RFrqChg::RatioMult(SRatio& aR, TUint32& aInt32) + { return DoControl(EControl_RatioMult, (TAny*)&aR, (TAny*)&aInt32); } +inline TInt RFrqChg::RatioInvSet(SRatioInv& aRI, const SRatio* aR) + { return DoControl(EControl_RatioInvSet, (TAny*)&aRI, (TAny*)aR); } +inline TInt RFrqChg::FrqChgTestPresent() + { return DoControl(EControl_FrqChgTestPresent); } +inline TInt RFrqChg::SetCurrentThreadPriority(TInt aPri) + { return DoControl(EControl_SetCurrentThreadPriority, (TAny*)aPri); } +inline TInt RFrqChg::SetCurrentThreadCpu(TUint32 aCpu, TUint32* aOldAffinity) + { return DoControl(EControl_SetCurrentThreadCpu, (TAny*)aCpu, (TAny*) aOldAffinity); } +inline TInt RFrqChg::SetCurrentThreadTimeslice(TInt aSlice) + { return DoControl(EControl_SetCurrentThreadTimeslice, (TAny*)aSlice); } +inline TInt RFrqChg::SetLocalTimerPrescaler(TUint32 aCpus, TInt aPrescale) + { return DoControl(EControl_SetLocalTimerPrescaler, (TAny*)aCpus, (TAny*)aPrescale); } +inline TInt RFrqChg::ReadGlobalTimerAndTimestamp(TUint64& aTimerValue, TUint64& aTimestamp) + { return DoControl(EControl_ReadGlobalTimerAndTimestamp, (TAny*)&aTimerValue, (TAny*) &aTimestamp); } +inline TInt RFrqChg::SetGlobalTimerPrescaler(TInt aPrescale) + { return DoControl(EControl_SetGlobalTimerPrescaler, (TAny*)aPrescale); } +#endif + +#endif //__D_FRQCHG_H__ diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/power/t_frqchg.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/power/t_frqchg.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -0,0 +1,775 @@ +// Copyright (c) 2010-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\power\t_frqchg.cpp +// +// + +#define __E32TEST_EXTENSION__ +#include +#include +#include +#include +#include "d_frqchg.h" +#include +#include "u32std.h" + +RFrqChg Driver; +RTest test(_L("T_FRQCHG")); + +// test will fail if slice is > (expected+KSliceDeltaPercent%of expexted) +// or < (expected-KSliceDeltaPercent%expected) +const TInt KSliceDeltaPercent = 5; +// test will fail for global timer based timestamps if interval measured +// is > (expected+KTimeStampDeltaPercent%of expexted) +// or < (expected-KTimeStampDeltaPercent%expected) +const TInt KTimeStampDeltaPercent = 5; + +TInt RealToRatio(SRatio& aRatio, const TRealX& aReal) + { + aRatio.iSpare1 = 0; + aRatio.iSpare2 = 0; + if (aReal.iSign || aReal.IsZero() || aReal.IsNaN()) + { + aRatio.iM = 0; + aRatio.iX = 0; + return (aReal.IsZero()) ? KErrNone : KErrNotSupported; + } + TRealX rx(aReal); + TRealX rr(rx); + rr.iExp -= 32; + rr.iMantLo = 0; + rr.iMantHi = 0x80000000u; + rx += rr; // rounding + TInt exp = rx.iExp - 32767 - 31; + if (exp < -32768) + { + aRatio.iM = 0; + aRatio.iX = 0; + return KErrUnderflow; + } + if (exp > 32767) + { + aRatio.iM = 0xffffffffu; + aRatio.iX = 32767; + return KErrOverflow; + } + aRatio.iM = rx.iMantHi; + aRatio.iX = (TInt16)exp; + return KErrNone; + } + +TInt RatioToReal(TRealX& a, const SRatio& aRatio) + { + a.iSign = 0; + a.iFlag = 0; + a.iMantLo = 0; + a.iMantHi = aRatio.iM; + if (!aRatio.iM) + { + a.SetZero(); + return KErrNone; + } + TInt exp = aRatio.iX + 31 + 32767; + if (exp > 65534) + { + a.SetInfinite(EFalse); + } + else + { + a.iExp = (TUint16)exp; + } + return KErrNone; + } + +TInt RatioSetValue(TRealX& a, TUint32 aInt, TInt aDivisorExp) + { + a.Set(TUint(aInt)); + TInt exp = a.iExp; + exp -= aDivisorExp; + if (exp<1) + { + a.SetZero(); + return KErrUnderflow; + } + if (exp>65534) + { + a.SetInfinite(EFalse); + return KErrOverflow; + } + a.iExp = (TInt16)exp; + return KErrNone; + } + +TInt RatioReciprocal(SRatio& aRatio) + { + TRealX rx; + TInt r = RatioToReal(rx, aRatio); + if (r != KErrNone) + return r; + rx = TRealX(1) / rx; + return RealToRatio(aRatio, rx); + } + +TInt RatioMult(const SRatio& aRatio, TUint32& aInt32) + { + TRealX rx; + TInt r = RatioToReal(rx, aRatio); + if (r != KErrNone) + return r; + r = rx.MultEq(TRealX((TUint)aInt32)); + if (r != KErrNone) + return r; + if (rx.IsZero()) + { + aInt32 = 0; + return KErrNone; + } + rx.AddEq(TRealX(0.5)); + if (rx 32767+31) + { + aInt32 = ~0u; + return KErrOverflow; + } + aInt32 = rx.operator TUint(); + return KErrNone; + } + +void RatioPrint(const char* aTitle, const SRatio& aRatio) + { + TPtrC8 t8((const TUint8*)aTitle); + TBuf<256> t16; + t16.Copy(t8); + test.Printf(_L("%S: %08x %04x\n"), &t16, aRatio.iM, TUint16(aRatio.iX)); + } + +void RatioPrint2(const char* aTitle, const SRatio& aR1, const SRatio& aR2) + { + TPtrC8 t8((const TUint8*)aTitle); + TBuf<256> t16; + t16.Copy(t8); + test.Printf(_L("%S: %08x %04x %08x %04x\n"), &t16, aR1.iM, TUint16(aR1.iX), aR2.iM, TUint16(aR2.iX)); + } + +void TestEqual(const SRatio& aActual, const SRatio& aExpected) + { + if (aActual.iM==aExpected.iM && aActual.iX==aExpected.iX) + return; + RatioPrint("Actual", aActual); + RatioPrint("Expected", aExpected); + test(0); + } + +const TUint32 MultTestIntegers[] = + { + 0u, 1u, 2u, 3u, 5u, 7u, 11u, 13u, 17u, 19u, 23u, 29u, 31u, 37u, 41u, 43u, 47u, + 50u, 51u, 53u, 59u, 61u, 63u, 67u, 71u, 72u, 81u, 100u, 127u, 133u, 187u, 200u, + 4u, 8u, 16u, 32u, 64u, 128u, 256u, 512u, 1024u, 2048u, 4096u, 8192u, 16384u, + 32768u, 65536u, 131072u, 262144u, 524288u, 1048576u, 2097152u, 4194304u, 8388608u, + 16777216u, 33554432u, 67108864u, 134217728u, 268435456u, 536870912u, 1073741824u, + 2147483648u, 4294967295u, + 9u, 27u, 243u, 729u, 2187u, 6561u, 19683u, 59049u, 177147u, 531441u, 1594323u, + 4782969u, 14348907u, 43046721u, 129140163u, 387420489u, 1162261467u, 3486784401u, + 25u, 125u, 625u, 3125u, 15625u, 78125u, 390625u, 1953125u, 9765625u, + 48828125u, 244140625u, 1220703125u, + 49u, 343u, 2401u, 16807u, 117649u, 823543u, 5764801u, 40353607u, 282475249u, 1977326743u + }; + +void Test1M(const SRatio& aRatio) + { + SRatio ratio = aRatio; + const TInt N = sizeof(MultTestIntegers)/sizeof(MultTestIntegers[0]); + test.Printf(_L("Testing %d integers\n"), N); + TInt i; + for (i=0; iiSlotCount = aSlots; + p->iPutIndex = 0; + p->iBufBase = (TUint32*)User::Alloc(aSlots*sizeof(TUint32)); + if (!p->iBufBase) + { + delete p; + p = 0; + } + __e32_memory_barrier(); + return p; + } + +CircBuf::CircBuf() + { + iBufBase = 0; + } + +CircBuf::~CircBuf() + { + User::Free((TAny*)iBufBase); + } + +TInt CircBuf::TryPut(TUint32 aIn) + { + TUint32 orig = __e32_atomic_tau_rlx32(&iPutIndex, iSlotCount, 0, 1); + if (orig == iSlotCount) + return KErrOverflow; + iBufBase[orig] = aIn; + return KErrNone; + } + +void CircBuf::Reset() + { + __e32_atomic_store_ord32(&iPutIndex, 0); + } + + + +class CTimesliceTestThread : public CBase + { +public: + CTimesliceTestThread(); + ~CTimesliceTestThread(); + static CTimesliceTestThread* New(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf); + void Start(); + void Wait(); + TBool Finished(); + TInt Construct(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf); + static TInt ThreadFunc(TAny*); +public: + RThread iThread; + TRequestStatus iExitStatus; + TUint32 iId; + CircBuf* iBuf; + TUint32 iFreq; + TUint32 iThresh; + TUint32 iThresh2; + TInt iCpu; + TInt iSlice; + }; + +CTimesliceTestThread::CTimesliceTestThread() + { + iThread.SetHandle(0); + } + +CTimesliceTestThread::~CTimesliceTestThread() + { + if (iThread.Handle()) + { + if (iThread.ExitType() == EExitPending) + { + iThread.Kill(0); + Wait(); + } + CLOSE_AND_WAIT(iThread); + } + } + +TInt CTimesliceTestThread::Construct(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf) + { + iId = aId; + iCpu = aCpu; + iSlice = aSlice; + iBuf = aBuf; + + TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)iFreq); + if (r!=KErrNone) + return r; + iThresh = iFreq / 3000; + if (iThresh < 10) + iThresh = 10; + iThresh2 = iFreq; + TBuf<16> name = _L("TSThrd"); + name.AppendNum(iId); + r = iThread.Create(name, &ThreadFunc, 0x1000, NULL, this); + if (r!=KErrNone) + return r; + iThread.Logon(iExitStatus); + if (iExitStatus != KRequestPending) + { + iThread.Kill(0); + iThread.Close(); + iThread.SetHandle(0); + return iExitStatus.Int(); + } + return KErrNone; + } + +CTimesliceTestThread* CTimesliceTestThread::New(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf) + { + CTimesliceTestThread* p = new CTimesliceTestThread; + if (p) + { + TInt r = p->Construct(aId, aCpu, aSlice, aBuf); + if (r != KErrNone) + { + delete p; + p = 0; + } + } + return p; + } + +void CTimesliceTestThread::Start() + { + iThread.Resume(); + } + +TBool CTimesliceTestThread::Finished() + { + return (KRequestPending!=iExitStatus.Int()); + } + +void CTimesliceTestThread::Wait() + { + User::WaitForRequest(iExitStatus); + } + +TInt CTimesliceTestThread::ThreadFunc(TAny* aPtr) + { + CTimesliceTestThread& a = *(CTimesliceTestThread*)aPtr; + Driver.SetCurrentThreadCpu(a.iCpu); + Driver.SetCurrentThreadPriority(63); + Driver.SetCurrentThreadTimeslice(a.iSlice); + User::AfterHighRes(100000); + TUint id = a.iId; + TUint32 last_interval_begin = User::FastCounter(); + TUint32 last_seen_time = User::FastCounter(); + FOREVER + { + TUint32 nfc = User::FastCounter(); + TUint32 delta = nfc - last_seen_time; + TUint32 interval_length = last_seen_time - last_interval_begin; + if (delta > a.iThresh || interval_length > a.iThresh2) + { + last_interval_begin = nfc; + TUint32 x = (id<<30) | (interval_length&0x3fffffffu); + TInt r = a.iBuf->TryPut(x); + if (r != KErrNone) + break; + } + last_seen_time = nfc; + } + return KErrNone; + } + +CircBuf* RunTimesliceTest(TInt aCpu, TInt aSlice, TInt aCount, TInt aInterfere = 0) + { + TUint32 oldaff = 0; + TUint32 interfereAffinity = 0; + TUint tellKernel = 0x80000000u; + + CircBuf* buf = CircBuf::New(aCount); + test(buf != 0); + CTimesliceTestThread* t0 = CTimesliceTestThread::New(0, aCpu, aSlice, buf); + test(t0 != 0); + CTimesliceTestThread* t1 = CTimesliceTestThread::New(1, aCpu, aSlice, buf); + test(t1 != 0); + + if (aInterfere) + { + if (aInterfere < 0) + { + tellKernel = 0; + } + TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); + test(r>0); + interfereAffinity = (0x80000000 | ((0x1<Start(); + t1->Start(); + if (aInterfere) + { + TInt prescale = 1; + while (!t0->Finished() || !t1->Finished()) + { + User::AfterHighRes(23000); + Driver.SetLocalTimerPrescaler((1u<<1)|tellKernel, prescale); + prescale++; + if (prescale > 4) + { + prescale = 0; + } + } + } + + t0->Wait(); + t1->Wait(); + + delete t0; + delete t1; + if (aInterfere) + { + TUint32 aff; + Driver.SetLocalTimerPrescaler((1u<<1)|0x80000000u, -1); + RThread().SetPriority(EPriorityNormal); + Driver.SetCurrentThreadCpu(oldaff,&aff); + test_Equal(aff,interfereAffinity); + } + return buf; + } + +TUint32 ticks_to_us(TUint32 aTicks, TUint32 aF) + { + TUint64 x = TUint64(aTicks) * TUint64(1000000); + TUint64 f64 = aF; + x += (f64>>1); + x /= f64; + return I64LOW(x); + } + +void DisplayBuffer(CircBuf* aBuf, TUint32 aSlice ) + { + TUint32 f; + TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)f); + test_KErrNone(r); + TUint32* p = (TUint32*)aBuf->iBufBase; + TInt c = aBuf->iSlotCount; + TInt i; + TInt lid = -1; + TUint32 min = ~0u; + TUint32 max = 0; + TUint32 totivus = 0; + TBool firstchg = ETrue; + for (i=0; i>30; + TUint32 iv = (x<<2)>>2; + TUint32 ivus = ticks_to_us(iv,f); + if (lid >= 0) + { + if (lid == (TInt)id) + totivus += ivus; + else + { + if (!firstchg) + { + if (totivus < min) + min = totivus; + if (totivus > max) + max = totivus; + } + else + firstchg = EFalse; + totivus = ivus; + } + } + lid = (TInt)id; + test.Printf(_L("ID: %1d IV: %10d (=%10dus) TIV %10dus\n"), id, iv, ivus, totivus); + } + + if (aSlice > 0) + { + // check timeslices where within acceptable ranges + TUint32 sliceError = KSliceDeltaPercent*aSlice/100; + test_Compare(max,<,aSlice+sliceError); + test_Compare(min,>,aSlice-sliceError); + } + test.Printf(_L("RANGE %d-%dus (%dus)\n"), min, max, max-min); + } + +void TT() + { + test.Printf(_L("Timeslicing test ...\n")); + CircBuf* b = RunTimesliceTest(1, 50000, 100); + test.Next(_L("Baseline - expecting normal")); + DisplayBuffer(b,50000u); + delete b; + + Driver.SetLocalTimerPrescaler(1u<<1, 1); + b = RunTimesliceTest(1, 50000, 100); + test.Next(_L("expecting double")); + DisplayBuffer(b,100000u); + delete b; + + Driver.SetLocalTimerPrescaler(1u<<1|0x80000000u, 1); + test.Next(_L("expecting normal again")); + b = RunTimesliceTest(1, 50000, 100); + DisplayBuffer(b,50000u); + delete b; + + test.Next(_L("expecting half")); + Driver.SetLocalTimerPrescaler(1u<<1, -1); + b = RunTimesliceTest(1, 50000, 100); + DisplayBuffer(b,25000u); + delete b; + + Driver.SetLocalTimerPrescaler(1u<<1|0x80000000u, -1); + test.Next(_L("expecting normal again")); + b = RunTimesliceTest(1, 50000, 100); + DisplayBuffer(b,50000u); + delete b; + + b = RunTimesliceTest(1, 50000, 200 ,-1); + test.Next(_L("expecting random")); + DisplayBuffer(b,0u); // timeslices should be fairly random on this run + + b = RunTimesliceTest(1, 50000, 200 ,1); + test.Next(_L("expecting normal again")); + DisplayBuffer(b,50000u); + delete b; + } + +struct SGTRecord + { + TUint64 iTSInterval; + TUint64 iGTInterval; + }; + + +SGTRecord* RunGTTest(TInt aCount, TInt aWait) + { + TUint64 lastgt,lastts,gt,ts; + + SGTRecord* res = new SGTRecord[aCount]; + test(res!=0); + + + TInt r = Driver.ReadGlobalTimerAndTimestamp(lastgt,lastts); + test_Equal(r,KErrNone); + + for (TInt i = 0; i < aCount; i++) + { + User::AfterHighRes(aWait); + + TInt r = Driver.ReadGlobalTimerAndTimestamp(gt,ts); + test_Equal(r,KErrNone); + res[i].iGTInterval = gt-lastgt; + lastgt = gt; + res[i].iTSInterval = ts-lastts; + lastts = ts; + } + + return res; + } + +void DisplayGTResults(SGTRecord* aRec, TInt aCount, TUint32 aFreq, TUint64 aExpectedTSInterval, TUint64 aExpectedGTInterval) + { + SGTRecord max = { 0ul , 0ul }; + SGTRecord min = { KMaxTUint64 , KMaxTUint64 }; + + TUint64 errgt = (aExpectedGTInterval*KTimeStampDeltaPercent)/100; + TUint64 errts = (aExpectedTSInterval*KTimeStampDeltaPercent)/100; + + + for (TInt i = 0 ; i < aCount; i++) + { + test.Printf(_L("gt interval : %Lu (gtticks) %Lu (us)\n"), + aRec[i].iGTInterval, + aRec[i].iTSInterval*1000000u/TUint64(aFreq)); + + if (max.iTSInterval < aRec[i].iTSInterval) + { + max.iTSInterval = aRec[i].iTSInterval; + } + if (max.iGTInterval < aRec[i].iGTInterval) + { + max.iGTInterval = aRec[i].iGTInterval; + } + + if (min.iTSInterval > aRec[i].iTSInterval) + { + min.iTSInterval = aRec[i].iTSInterval; + } + if (min.iGTInterval > aRec[i].iGTInterval) + { + min.iGTInterval = aRec[i].iGTInterval; + } + } + + test.Printf(_L("RANGE Global Timer %Lu-%Lu ticks (%Lu ticks)\n"), + min.iGTInterval, max.iGTInterval, max.iGTInterval-min.iGTInterval); + + test.Printf(_L("RANGE Timestamp %Lu-%Lu us (%Lu us)\n"), + (1000000u*min.iGTInterval)/TUint64(aFreq), (1000000u*max.iGTInterval)/TUint64(aFreq), + (1000000u*max.iGTInterval)/TUint64(aFreq) - (1000000u*min.iGTInterval)/TUint64(aFreq)); + + if (errts) + { + test_Compare(max.iTSInterval,<,aExpectedTSInterval+errts); + test_Compare(min.iTSInterval,>,aExpectedTSInterval); + } + + if (errgt) + { + test_Compare(max.iGTInterval,<,aExpectedGTInterval+errgt); + test_Compare(min.iGTInterval,>,aExpectedGTInterval); + } + + } + +void GTT() + { + test.Printf(_L("Global timer tests ...\n")); + TUint64 gt,ts; + + TInt r = Driver.ReadGlobalTimerAndTimestamp(gt,ts); + if (KErrNotSupported == r ) + { + test.Printf(_L("Global timer not supported in this plaform, skipping GT tests\n")); + return; + } + + TUint32 f; + r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)f); + test_KErrNone(r); + TInt wait = 100000; // 100ms + TInt count = 10; + + TUint64 expectedTs = (TUint64(f)*TUint64(wait))/1000000u; + TUint64 expectedGtOrig = expectedTs; + + SGTRecord* rec; + for (TInt i = 0; i < 10; i++) + { + TUint64 expectedGt = expectedGtOrig/(i+1); + r = Driver.SetGlobalTimerPrescaler(i); + test_KErrNone(r); + rec = RunGTTest(count, wait); + test.Printf(_L("expectedTS %Lu expectedGT %Lu\n"),expectedTs,expectedGt); + DisplayGTResults(rec,count, f, expectedTs , expectedGt); + delete rec; + } + + r = Driver.SetGlobalTimerPrescaler(-1); // back to default + test_KErrNone(r); + } + +void RunTests() + { + TestRatios(); + if (Driver.FrqChgTestPresent()!=KErrNone) + { + test.Printf(_L("Frequency Change not supported on this platform\n")); + return; + } + TT(); + GTT(); + } + +GLDEF_C TInt E32Main() + { + test.Title(); + test.Start(_L("Testing")); + TInt r = User::LoadLogicalDevice(KLddName); + if (r==KErrNotFound) + { + test.Printf(_L("Test not supported on this platform\n")); + } + else + { + if (r!=KErrNone) + { + test_Equal(KErrAlreadyExists, r); + } + r = Driver.Open(); + test_KErrNone(r); + RunTests(); + Driver.Close(); + } + + test.End(); + r = User::FreeLogicalDevice(KLddName); + test_KErrNone(r); + return KErrNone; + } diff -r af6ec97d9189 -r a232af6b0b1f kerneltest/e32test/prime/t_semutx.cpp --- a/kerneltest/e32test/prime/t_semutx.cpp Wed Jun 23 12:52:28 2010 +0100 +++ b/kerneltest/e32test/prime/t_semutx.cpp Wed Jun 23 12:58:21 2010 +0100 @@ -40,7 +40,9 @@ #define __E32TEST_EXTENSION__ #include -#include +#include +#include +#include #include const TInt KMaxBufferSize=10; @@ -51,13 +53,352 @@ RTest test(_L("T_SEMUTX")); RMutex mutex; -RCriticalSection criticalSn; +RCriticalSection criticalSn; TInt thread1Count,thread2Count; TInt arrayIndex; -TInt array[KMaxArraySize]; +TInt array[KMaxArraySize]; TInt consumerArray[KNumProducerItems]; -RSemaphore slotAvailable,itemAvailable; +RSemaphore slotAvailable,itemAvailable; +TBool doCpuLocking = EFalse; + +// return num of cpus in system +TInt NumCpus() + { + TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); + return r; + } + + +TInt LockCurrentThreadToCpu0(TBool aCallingIsMainTestThread = EFalse) + { + if (aCallingIsMainTestThread) + { + if (NumCpus() > 1) + { + doCpuLocking = ETrue; + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, 0, 0); + } + else + { + return KErrNone; + } + } + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, 0, 0); + } + +TInt UnlockCurrentThreadToCpu0(TBool aCallingIsMainTestThread = EFalse) + { + if (aCallingIsMainTestThread) + { + if (NumCpus() > 1) + { + doCpuLocking = EFalse; + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*) 0xffffffffu, 0); + } + else + { + return KErrNone; + } + } + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*) 0xffffffffu, 0); + } + + +/****************************************************************************** + * Random Number Generation + ******************************************************************************/ +void Random(TUint64& a) + { + TInt i; + for (i=64; i>0; --i) + { + TUint64 x = a<<1; + TUint64 y = x<<1; + x^=y; + a = (y>>1) | (x>>63); + } + } + +// Returns 256*log2(a/2^64) +TInt Log2(TUint64 a) + { + const TUint64 KBit63 = UI64LIT(0x8000000000000000); + TInt n = __e32_find_ms1_64(a); + a <<= (63-n); + n -= 64; + TInt i; + for (i=0; i<8; ++i) + { + a >>= 32; + a *= a; + n <<= 1; + if (a & KBit63) + { + ++n; + } + else + { + a <<= 1; + } + } + return n; + } + +TUint32 ExpRV(TUint64 aU, TUint32 aMean, TUint32 aTick) + { + TInt n = -Log2(aU); + TUint64 x = TUint64(n) * TUint64(aMean); + x *= TUint64(22713); // 2^15 * ln2 + TUint64 p(aTick); + p <<= 22; + x += p; + p += p; + x /= p; + return I64LOW(x); + } + + + +/*----------------------------------------------------------------------------*/ +class MLock + { +public: + enum {EPollable=1, ETimeoutAvail=2, ENestable=4, ELimit1=8, ELooseTimeout=16}; +public: + virtual TInt Flags()=0; + virtual void Release()=0; + virtual void Wait()=0; + virtual void Signal()=0; + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); + }; + +TInt MLock::Wait(TInt) + { return KErrNotSupported; } +TInt MLock::Poll() + { return KErrNotSupported; } + +/*----------------------------------------------------------------------------*/ +class LockS : public MLock + { +public: + LockS(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); +public: + RSemaphore iT; + }; + +LockS::LockS() + { test_KErrNone(iT.CreateLocal(1)); } +TInt LockS::Flags() + { return EPollable|ETimeoutAvail; } +void LockS::Release() + { iT.Close(); } +void LockS::Wait() + { iT.Wait(); } +void LockS::Signal() + { iT.Signal(); } +TInt LockS::Wait(TInt aTimeout) + { return iT.Wait(aTimeout); } +TInt LockS::Poll() + { return iT.Poll(); } + +/*----------------------------------------------------------------------------*/ +class LockM : public MLock + { +public: + LockM(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); +public: + RMutex iT; + }; + +LockM::LockM() + { test_KErrNone(iT.CreateLocal()); } +TInt LockM::Flags() + { return EPollable|ETimeoutAvail|ENestable|ELimit1; } +void LockM::Release() + { iT.Close(); } +void LockM::Wait() + { iT.Wait(); } +void LockM::Signal() + { iT.Signal(); } +TInt LockM::Wait(TInt aTimeout) + { return iT.Wait(aTimeout); } +TInt LockM::Poll() + { return iT.Poll(); } + +/*----------------------------------------------------------------------------*/ + +class LockFL : public MLock + { +public: + LockFL(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); +public: + RFastLock iT; + }; + +LockFL::LockFL() + { test_KErrNone(iT.CreateLocal()); } +TInt LockFL::Flags() + { return ETimeoutAvail|EPollable|ELimit1|ELooseTimeout; } +void LockFL::Release() + { iT.Close(); } +void LockFL::Wait() + { iT.Wait(); } +void LockFL::Signal() + { iT.Signal(); } +TInt LockFL::Wait(TInt aTimeout) + { return iT.Wait(aTimeout); } +TInt LockFL::Poll() + { return iT.Poll(); } + +/*----------------------------------------------------------------------------*/ +class LockCS : public MLock + { +public: + LockCS(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); +public: + RCriticalSection iT; + }; + +LockCS::LockCS() + { test_KErrNone(iT.CreateLocal()); } +TInt LockCS::Flags() + { return ELimit1; } +void LockCS::Release() + { iT.Close(); } +void LockCS::Wait() + { iT.Wait(); } +void LockCS::Signal() + { iT.Signal(); } + + +/*----------------------------------------------------------------------------*/ +class LFSR + { +public: + LFSR(TInt aBits, TInt aTap2, TInt aTap3=0, TInt aTap4=0); + ~LFSR(); + void Step(); + void Step(TInt aSteps); + TBool operator==(const LFSR& a) const; +public: + TUint32* iData; + TInt iBits; + TInt iTap2; + TInt iTap3; + TInt iTap4; + TInt iNW; + TInt iSh1; + TInt iIx2; + TInt iSh2; + TInt iIx3; + TInt iSh3; + TInt iIx4; + TInt iSh4; + }; + +LFSR::LFSR(TInt aBits, TInt aTap2, TInt aTap3, TInt aTap4) + { + iBits = aBits; + iTap2 = aTap2; + iTap3 = aTap3; + iTap4 = aTap4; + iNW = (aBits + 31) >> 5; + iData = (TUint32*)User::AllocZ(iNW*sizeof(TUint32)); + test(iData!=0); + iData[0] = 1; + iSh1 = (aBits-1)&31; + iIx2 = (iTap2-1)>>5; + iSh2 = (iTap2-1)&31; + if (iTap3) + { + iIx3 = (iTap3-1)>>5; + iSh3 = (iTap3-1)&31; + } + else + { + iIx3 = -1; + iSh3 = 0; + } + if (iTap4) + { + iIx4 = (iTap4-1)>>5; + iSh4 = (iTap4-1)&31; + } + else + { + iIx4 = -1; + iSh4 = 0; + } + } + +LFSR::~LFSR() + { + User::Free(iData); + } + +void LFSR::Step(TInt aSteps) + { + while (aSteps--) + Step(); + } + +void LFSR::Step() + { + TUint32 b = iData[iNW-1]>>iSh1; + b ^= (iData[iIx2]>>iSh2); + if (iIx3>=0) + b ^= (iData[iIx3]>>iSh3); + if (iIx4>=0) + b ^= (iData[iIx4]>>iSh4); + b &= 1; + TInt i; + for (i=0; i> 31; + iData[i] = (iData[i]<<1)|b; + b = bb; + } + iData[iNW-1] &= ((2u< 1) + { + // when the mutex is singaled, due to priority balancing, the other + // thread will be scheduled to run on a CPU other than this one. The delay + // in getting that thread to run means that this one can manage to re-claim the + // mutex before the other thread gets to run. So we add a small delay here + User::After(100); + } + } while (running); return(KErrNone); } @@ -142,6 +494,7 @@ // Mutex test thread 2 // { + TInt n = NumCpus(); thread2Count=0; TBool running=ETrue; @@ -157,6 +510,17 @@ else running=EFalse; mutex.Signal(); + + if (n > 1) + { + // when the mutex is singaled, due to priority balancing, the other + // thread will be scheduled to run on a CPU other than this one. The delay + // in getting that thread to run means that this one can manage to re-claim the + // mutex before the other thread gets to run. So we add a small delay here + User::After(100); + } + + } while (running); return(KErrNone); } @@ -209,27 +573,80 @@ return(KErrNone); } -struct SWaitSem + +/*----------------------------------------------------------------------------*/ +struct SWaitLock { - RSemaphore iSem; + enum {EDummy=-2, EPoll=-1, EInfinite=0}; + + static TInt WaitLockThread(TAny*); + void Start(RThread& aT, TThreadPriority aP=EPriorityLess); + void Wait(RThread& aT, TInt aResult); + TInt DoTest2(RThread& aT, TInt aTimeout, TInt aResult, TThreadPriority aP=EPriorityLess); + void Test2(); + void TestSignalled(); + void TestNotSignalled(); + void TestState(); + + + MLock* iLock; TInt iTimeout; }; -TInt WaitSemThread(TAny* a) +TInt SWaitLock::WaitLockThread(TAny* a) { - SWaitSem& ws = *(SWaitSem*)a; - return ws.iSem.Wait(ws.iTimeout); + + if (doCpuLocking) + { + TInt r = LockCurrentThreadToCpu0(); + if (KErrNone!=r) return r; + // Rendevous was requested + RThread::Rendezvous(KErrNone); + } + + SWaitLock& w = *(SWaitLock*)a; + TInt lfl = w.iLock->Flags(); + TBool limit1 = lfl & MLock::ELimit1; + TInt r; + switch (w.iTimeout) + { + case EDummy: + return KErrNone; + case EPoll: + r = w.iLock->Poll(); + break; + case EInfinite: + w.iLock->Wait(); + r = KErrNone; + break; + default: + r = w.iLock->Wait(w.iTimeout); + break; + } + if (limit1 && r==KErrNone) + w.iLock->Signal(); + return r; } -void StartWaitSemThread(RThread& aT, SWaitSem& aW, TThreadPriority aP=EPriorityLess) +void SWaitLock::Start(RThread& aT, TThreadPriority aP) { - TInt r = aT.Create(KNullDesC, &WaitSemThread, 0x1000, 0x1000, 0x1000, &aW); + TRequestStatus st; + TInt r = aT.Create(KNullDesC, &WaitLockThread, 0x1000, 0x1000, 0x1000, this); test_KErrNone(r); aT.SetPriority(aP); + if (doCpuLocking) + { + aT.Rendezvous(st); + } aT.Resume(); + if (doCpuLocking) + { + User::WaitForRequest(st); + test_KErrNone(st.Int()); + } } -void WaitForWaitSemThread(RThread& aT, TInt aResult) +void SWaitLock::Wait(RThread& aT, TInt aResult) { TRequestStatus s; aT.Logon(s); @@ -240,32 +657,67 @@ CLOSE_AND_WAIT(aT); } -TInt DummyThread(TAny*) +TInt SWaitLock::DoTest2(RThread& aT, TInt aTimeout, TInt aResult, TThreadPriority aP) { - return 0; + TTime initial; + TTime final; + iTimeout = aTimeout; + initial.HomeTime(); + Start(aT, aP); + Wait(aT, aResult); + final.HomeTime(); + TInt elapsed = I64INT(final.Int64()-initial.Int64()); + return elapsed; + } + +void SWaitLock::TestSignalled() + { + TInt r = iLock->Poll(); + if (r == KErrNotSupported) + r = iLock->Wait(1); + test_KErrNone(r); } -void TestSemaphore2() +void SWaitLock::TestNotSignalled() + { + TInt r = iLock->Poll(); + if (r == KErrNotSupported) + r = iLock->Wait(1); + test_Equal(KErrTimedOut, r); + } + +void SWaitLock::TestState() { - test.Start(_L("Test semaphore wait with timeout")); - SWaitSem ws; + if (iLock->Flags() & MLock::ELimit1) + TestSignalled(); // not signalled afterwards + else + TestNotSignalled(); + } + +void SWaitLock::Test2() + { + test.Start(_L("SWaitLock::Test2")); RThread t; + RThread t2; TTime initial; TTime final; - TInt elapsed=0; - TInt r = ws.iSem.CreateLocal(0); - test_KErrNone(r); + TInt elapsed = 0; + TInt r = 0; + TInt lfl = iLock->Flags(); + TBool nestable = lfl & MLock::ENestable; + TBool limit1 = lfl & MLock::ELimit1; + TBool pollable = lfl & MLock::EPollable; + TBool to = lfl & MLock::ETimeoutAvail; + TBool lto = lfl & MLock::ELooseTimeout; RThread().SetPriority(EPriorityAbsoluteVeryLow); TInt threadcount=0; + iTimeout = EDummy; initial.HomeTime(); while (elapsed<1000000) { - r = t.Create(KNullDesC, &DummyThread, 0x1000, NULL, NULL); - test_KErrNone(r); - t.SetPriority(EPriorityMore); - t.Resume(); - t.Close(); + Start(t, EPriorityMore); + Wait(t, KErrNone); ++threadcount; final.HomeTime(); elapsed = I64INT(final.Int64()-initial.Int64()); @@ -275,125 +727,735 @@ TInt overhead = 1000000/threadcount; test.Printf(_L("overhead = %dus\n"),overhead); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t, ws); - WaitForWaitSemThread(t, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+overhead && elapsed<1500000+overhead); + iLock->Wait(); - ws.iTimeout=-1; - initial.HomeTime(); - StartWaitSemThread(t, ws); - WaitForWaitSemThread(t, KErrArgument); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); + if (to) + { + elapsed = DoTest2(t, 1000000, KErrTimedOut); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+overhead && elapsed<1500000+overhead); + elapsed = DoTest2(t, -99, KErrArgument); + test.Printf(_L("Time taken = %dus\n"), elapsed); + } - ws.iTimeout=2000000; - initial.HomeTime(); - StartWaitSemThread(t, ws); - User::After(1000000); - ws.iSem.Signal(); - WaitForWaitSemThread(t, KErrNone); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+overhead && elapsed<1500000+overhead); + if (pollable) + { + test.Printf(_L("Testing Poll() function\n")); + r = iLock->Poll(); + test_Equal((nestable ? KErrNone : KErrTimedOut), r); + if (nestable) + { + iTimeout=EPoll; + r = iLock->Poll(); + test_KErrNone(r); + iLock->Signal(); + Start(t, EPriorityMore); + Wait(t, KErrTimedOut); + } + iLock->Signal(); + if (nestable) + { + iTimeout=EPoll; + r = iLock->Poll(); + test_KErrNone(r); + iLock->Signal(); + Start(t, EPriorityMore); + Wait(t, KErrTimedOut); + iLock->Signal(); + Start(t, EPriorityMore); + Wait(t, KErrNone); + } + r = iLock->Poll(); + test_KErrNone(r); + if (!nestable) + { + r = iLock->Poll(); + test_Equal(KErrTimedOut, r); + iLock->Signal(); + if (!limit1) + { + iLock->Signal(); + r = iLock->Poll(); + test_KErrNone(r); + } + r = iLock->Poll(); + test_KErrNone(r); + r = iLock->Poll(); + test_Equal(KErrTimedOut, r); + } + elapsed = DoTest2(t, EPoll, KErrTimedOut); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed<=50000+3*overhead); + iLock->Signal(); + elapsed = DoTest2(t, EPoll, KErrNone); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed<=50000+3*overhead); + TestState(); + iLock->Signal(); + r = LockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); + Start(t, EPriorityMuchMore); + Start(t2, EPriorityMore); + test_Equal(EExitKill, t2.ExitType()); + test_Equal(EExitKill, t.ExitType()); + Wait(t2, limit1 ? KErrNone : KErrTimedOut); + Wait(t, KErrNone); + r = UnlockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); + TestState(); + } + else + { + test.Printf(_L("Poll() function not supported\n")); + } - ws.iTimeout=100000; - StartWaitSemThread(t, ws, EPriorityMore); - t.Suspend(); - ws.iSem.Signal(); - User::After(200000); - t.Resume(); - WaitForWaitSemThread(t, KErrTimedOut); - test_KErrNone(ws.iSem.Wait(1)); + if (to) + { + iTimeout=2000000; + initial.HomeTime(); + Start(t); + User::After(1000000); + iLock->Signal(); + Wait(t, KErrNone); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+overhead && elapsed<1500000+overhead); + TestState(); - ws.iTimeout=100000; - StartWaitSemThread(t, ws, EPriorityMore); - t.Suspend(); - ws.iSem.Signal(); - User::After(50000); - t.Resume(); - WaitForWaitSemThread(t, KErrNone); - test_Equal(KErrTimedOut, ws.iSem.Wait(1)); + r = LockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); - RThread t2; - ws.iTimeout=100000; - StartWaitSemThread(t, ws, EPriorityMuchMore); - StartWaitSemThread(t2, ws, EPriorityMore); - t.Suspend(); - ws.iSem.Signal(); - test_Equal(EExitKill, t2.ExitType()); - test_Equal(EExitPending, t.ExitType()); - t.Resume(); - WaitForWaitSemThread(t, KErrTimedOut); - WaitForWaitSemThread(t2, KErrNone); - test_Equal(KErrTimedOut, ws.iSem.Wait(1)); + if (!lto) + { + iTimeout=100000; + Start(t, EPriorityMore); + t.Suspend(); + iLock->Signal(); + User::After(200000); + t.Resume(); + Wait(t, KErrTimedOut); + TestSignalled(); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t2, ws, EPriorityMore); - StartWaitSemThread(t, ws, EPriorityMuchMore); - ws.iSem.Signal(); - WaitForWaitSemThread(t, KErrNone); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - WaitForWaitSemThread(t2, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + iTimeout=100000; + Start(t, EPriorityMore); + t.Suspend(); + iLock->Signal(); + User::After(50000); + t.Resume(); + Wait(t, KErrNone); + TestState(); + + iTimeout=100000; + Start(t, EPriorityMuchMore); + Start(t2, EPriorityMore); + t.Suspend(); + iLock->Signal(); + test_Equal(EExitKill, t2.ExitType()); + test_Equal(EExitPending, t.ExitType()); + t.Resume(); + Wait(t, limit1 ? KErrNone : KErrTimedOut); + Wait(t2, KErrNone); + TestState(); + } - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t2, ws, EPriorityMore); - StartWaitSemThread(t, ws, EPriorityMuchMore); - WaitForWaitSemThread(t, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - WaitForWaitSemThread(t2, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + iTimeout=1000000; + initial.HomeTime(); + Start(t2, EPriorityMore); + Start(t, EPriorityMuchMore); + iLock->Signal(); + Wait(t, KErrNone); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + Wait(t2, limit1 ? KErrNone : KErrTimedOut); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + if (!limit1) + { + test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + } + TestState(); + + iTimeout=1000000; + initial.HomeTime(); + Start(t2, EPriorityMore); + Start(t, EPriorityMuchMore); + Wait(t, KErrTimedOut); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + Wait(t2, KErrTimedOut); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t2, ws, EPriorityMore); - StartWaitSemThread(t, ws, EPriorityMuchMore); - t.Kill(299792458); - WaitForWaitSemThread(t2, KErrTimedOut); - WaitForWaitSemThread(t, 299792458); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + iTimeout=1000000; + initial.HomeTime(); + Start(t2, EPriorityMore); + Start(t, EPriorityMuchMore); + t.Kill(299792458); + Wait(t2, KErrTimedOut); + Wait(t, 299792458); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t, ws, EPriorityMore); - StartWaitSemThread(t2, ws, EPriorityMuchMore); - test_Equal(EExitPending, t.ExitType()); - test_Equal(EExitPending, t2.ExitType()); - ws.iSem.Close(); - test_Equal(EExitKill, t.ExitType()); - test_Equal(EExitKill, t2.ExitType()); - WaitForWaitSemThread(t2, KErrGeneral); - WaitForWaitSemThread(t, KErrGeneral); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed<=50000+3*overhead); - + iTimeout=1000000; + initial.HomeTime(); + Start(t, EPriorityMore); + Start(t2, EPriorityMuchMore); + test_Equal(EExitPending, t.ExitType()); + test_Equal(EExitPending, t2.ExitType()); + iLock->Release(); + test_Equal(EExitKill, t.ExitType()); + test_Equal(EExitKill, t2.ExitType()); + Wait(t2, KErrGeneral); + Wait(t, KErrGeneral); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed<=50000+3*overhead); + r = UnlockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); + } + else + { + test.Printf(_L("Timed waits not supported\n")); + iLock->Release(); + } test.End(); } +volatile TBool NoRepeat = EFalse; +void TestPollTimeout() + { + SWaitLock w; + do { + test.Printf(_L("TestPollTimeout - RSemaphore\n")); + LockS ls; + w.iLock = &ls; + w.Test2(); // Release()s ls + } while(NoRepeat); + do { + test.Printf(_L("TestPollTimeout - RMutex\n")); + LockM lm; + w.iLock = &lm; + w.Test2(); // Release()s lm + } while(NoRepeat); + do { + test.Printf(_L("TestPollTimeout - RFastLock\n")); + LockFL fl; + w.iLock = &fl; + w.Test2(); // Release()s fl + } while(NoRepeat); + } + + +/*----------------------------------------------------------------------------*/ +class CMXThreadGrp; + +struct SStats + { + SStats(); + void Add(TInt aValue); + void Add(const SStats& aS); + TInt Count() const {return iN;} + TInt Min() const; + TInt Max() const; + TInt Mean() const; + + TInt64 iSum; + TInt iMin; + TInt iMax; + TInt iN; + TInt iSp; + }; + +SStats::SStats() + { + iSum = 0; + iMax = KMinTInt; + iMin = ~iMax; + iN = 0; + iSp = 0; + } + +void SStats::Add(TInt aValue) + { + TInt64 v = aValue; + iSum += v; + ++iN; + if (aValue > iMax) + iMax = aValue; + if (aValue < iMin) + iMin = aValue; + } + +void SStats::Add(const SStats& a) + { + iN += a.iN; + iSum += a.iSum; + if (a.iMax > iMax) + iMax = a.iMax; + if (a.iMin < iMin) + iMin = a.iMin; + } + +TInt SStats::Min() const + {return iN ? iMin : 0;} + +TInt SStats::Max() const + {return iN ? iMax : 0;} + +TInt SStats::Mean() const + { + if (iN==0) + return 0; + return (TInt)(iSum/TInt64(iN)); + } + +TUint32 ticks_to_us(TUint32 aTicks, TUint32 aF) + { + TUint64 x = aTicks; + TUint64 f = aF; + x *= TUint64(1000000); + x += (f>>1); + x /= f; + return I64LOW(x); + } + +class CMXThread : public CBase + { +private: + CMXThread(); + ~CMXThread(); + static CMXThread* New(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD); + void Start(); + void Wait(); + TInt Construct(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD); + TInt Steps(); + TInt Action(); + TInt Run(); + static TInt ThreadFunc(TAny*); + void PrintStats(); +private: + TUint64 iSeed; + RThread iThread; + TRequestStatus iExitStatus; + CMXThreadGrp* iG; + LFSR* iDummyLfsr; + TUint32 iId; + TUint32 iLambda; + TUint32 iDummySteps; + TInt iTotalSteps; + TInt iIterations; + TInt iPolls; + TInt iPollFails; + SStats iStats; + SStats iTimeoutStats; +private: + friend class CMXThreadGrp; + }; + +class CMXThreadGrp : public CBase + { +public: + static CMXThreadGrp* New(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime); + CMXThreadGrp(); + ~CMXThreadGrp(); + TBool Run(); + void PrintStats(); +private: + TInt Construct(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime); +private: + TInt iNThreads; + CMXThread** iThreads; + MLock* iLock; + LFSR* iLfsr; + LFSR* iLfsr0; + TUint32 iNTickPeriod; + TUint32 iFCF; + TUint32 iNTicks; + TInt iTotalSteps; + TInt iIterations; + TInt iPolls; + TInt iPollFails; + SStats iStats; + SStats iTimeoutStats; +private: + friend class CMXThread; + }; + +CMXThread::CMXThread() + { + iThread.SetHandle(0); + } + +CMXThread::~CMXThread() + { + delete iDummyLfsr; + if (iThread.Handle()) + { + if (iThread.ExitType() == EExitPending) + { + iThread.Kill(0); + Wait(); + } + CLOSE_AND_WAIT(iThread); + } + } + +void CMXThread::PrintStats() + { + test.Printf(_L("Thread %d:\n"), iId); + test.Printf(_L(" ST:%10d IT:%10d P:%10d PF:%10d TO:%10d\n"), iTotalSteps, iIterations, iPolls, iPollFails, iTimeoutStats.Count()); + TUint32 min, max, mean; + min = ticks_to_us(iStats.Min(), iG->iFCF); + max = ticks_to_us(iStats.Max(), iG->iFCF); + mean = ticks_to_us(iStats.Mean(), iG->iFCF); + test.Printf(_L(" Lock acquire times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + min = ticks_to_us(iTimeoutStats.Min(), iG->iFCF); + max = ticks_to_us(iTimeoutStats.Max(), iG->iFCF); + mean = ticks_to_us(iTimeoutStats.Mean(), iG->iFCF); + test.Printf(_L(" Lock timeout times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + } + +TInt CMXThread::Construct(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD) + { + iG = aG; + iId = aId; + iLambda = aL; + iDummySteps = aD; + iSeed = iId + 1; + iDummyLfsr = new LFSR(785,693); + if (!iDummyLfsr) + return KErrNoMemory; + TBuf<16> name = _L("TSThrd"); + name.AppendNum(iId); + TInt r = iThread.Create(name, &ThreadFunc, 0x1000, NULL, this); + if (r!=KErrNone) + return r; + iThread.Logon(iExitStatus); + if (iExitStatus != KRequestPending) + { + iThread.Kill(0); + iThread.Close(); + iThread.SetHandle(0); + return iExitStatus.Int(); + } + iThread.SetPriority(EPriorityLess); + return KErrNone; + } + +CMXThread* CMXThread::New(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD) + { + CMXThread* p = new CMXThread; + if (p) + { + TInt r = p->Construct(aG, aId, aL, aD); + if (r != KErrNone) + { + delete p; + p = 0; + } + } + return p; + } + +void CMXThread::Start() + { + iThread.Resume(); + } + +void CMXThread::Wait() + { + User::WaitForRequest(iExitStatus); + } + +TInt CMXThread::ThreadFunc(TAny* aPtr) + { + CMXThread& a = *(CMXThread*)aPtr; + return a.Run(); + } + +TInt CMXThread::Steps() + { + Random(iSeed); + return ExpRV(iSeed, iLambda, 1); + } + +TInt CMXThread::Action() + { + Random(iSeed); + return I64LOW(iSeed)%3; + } + +TInt CMXThread::Run() + { + MLock* lock = iG->iLock; + LFSR* lfsr = iG->iLfsr; + TInt lfl = lock->Flags(); + TBool pollable = lfl & MLock::EPollable; + TBool to = lfl & MLock::ETimeoutAvail; + TUint32 start_time = User::NTickCount(); + TInt r; + + FOREVER + { + TUint32 now = User::NTickCount(); + if (now - start_time >= iG->iNTicks) + break; + ++iIterations; + iDummyLfsr->Step(iDummySteps); + TInt action = Action(); + TInt steps = Steps(); + TUint32 initial = User::FastCounter(); + if (action==2 && to) + { + r = lock->Wait(1000); + if (r!=KErrNone) + { + TUint32 final = User::FastCounter(); + TInt elapsed = TInt(final - initial); + iTimeoutStats.Add(elapsed); + } + } + else if (action==1 && pollable) + { + ++iPolls; + r = lock->Poll(); + if (r!=KErrNone) + ++iPollFails; + } + else + { + lock->Wait(); + r = KErrNone; + } + if (r == KErrNone) + { + TUint32 final = User::FastCounter(); + lfsr->Step(steps); + lock->Signal(); + TInt elapsed = TInt(final - initial); + iTotalSteps += steps; + iStats.Add(elapsed); + } + } + + return KErrNone; + } + +CMXThreadGrp* CMXThreadGrp::New(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime) + { + CMXThreadGrp* p = new CMXThreadGrp; + if (p) + { + TInt r = p->Construct(aLock, aNThreads, aLambda, aDummySteps, aTime); + if (r != KErrNone) + { + delete p; + p = 0; + } + } + return p; + } + +CMXThreadGrp::CMXThreadGrp() + { + } + +TInt CMXThreadGrp::Construct(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime) + { + iNThreads = aNThreads; + iLock = aLock; + TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)iFCF); + if (r!=KErrNone) + return r; + r = HAL::Get(HAL::ENanoTickPeriod, (TInt&)iNTickPeriod); + if (r!=KErrNone) + return r; + iNTicks = (aTime+iNTickPeriod-1)/iNTickPeriod; + iLfsr = new LFSR(785,693); + iLfsr0 = new LFSR(785,693); + if (!iLfsr || !iLfsr0) + return KErrNoMemory; + iThreads = (CMXThread**)User::AllocZ(iNThreads*sizeof(CMXThread*)); + if (!iThreads) + return KErrNoMemory; + TInt i; + for (i=0; iiLambda, iThreads[0]->iDummySteps, iNTicks); + for (i=0; iStart(); + for (i=0; iWait(); + for (i=0; iiTotalSteps; + iIterations += iThreads[i]->iIterations; + iPolls += iThreads[i]->iPolls; + iPollFails += iThreads[i]->iPollFails; + iStats.Add(iThreads[i]->iStats); + iTimeoutStats.Add(iThreads[i]->iTimeoutStats); + } + test.Printf(_L("Total LFSR steps %d\n"), iTotalSteps); + iLfsr0->Step(iTotalSteps); + TBool ok = (*iLfsr == *iLfsr0); + return ok; + } + +void CMXThreadGrp::PrintStats() + { + TInt i; + for (i=0; iPrintStats(); + } + test.Printf(_L("TOTALS:\n")); + test.Printf(_L(" ST:%10d IT:%10d P:%10d PF:%10d TO:%10d\n"), iTotalSteps, iIterations, iPolls, iPollFails, iTimeoutStats.Count()); + TUint32 min, max, mean; + min = ticks_to_us(iStats.Min(), iFCF); + max = ticks_to_us(iStats.Max(), iFCF); + mean = ticks_to_us(iStats.Mean(), iFCF); + test.Printf(_L(" Lock acquire times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + min = ticks_to_us(iTimeoutStats.Min(), iFCF); + max = ticks_to_us(iTimeoutStats.Max(), iFCF); + mean = ticks_to_us(iTimeoutStats.Mean(), iFCF); + test.Printf(_L(" Lock timeout times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + } + +TUint32 Calibrate() + { + TUint32 fcf; + TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)fcf); + test_KErrNone(r); + LFSR* d = new LFSR(785,693); + test(d!=0); + TInt steps = 2; + TUint32 ticks = fcf/10; + TUint32 elapsed; + FOREVER + { + TUint32 h0 = User::FastCounter(); + d->Step(steps); + TUint32 h1 = User::FastCounter(); + elapsed = h1 - h0; + if (elapsed > ticks) + break; + steps *= 2; + } + delete d; + test.Printf(_L("%d steps in %d fast ticks\n"), steps, elapsed); + TUint64 x = elapsed; + TUint64 s = steps; + TUint64 y = fcf; + y /= x; + s *= y; // steps per second + TUint32 res = I64LOW(s); + test.Printf(_L("%d steps per second\n"), res); + return res; + } + +void DoTMX(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime, TBool aShouldFail=EFalse) + { + CMXThreadGrp* g = CMXThreadGrp::New(aLock, aNThreads, aLambda, aDummySteps, aTime); + test(g!=0); + TBool ok = g->Run(); + if (aShouldFail) + { + test(!ok); + } + else + { + test(ok); + } + g->PrintStats(); + delete g; + } + +void DoTMX(MLock* aLock, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime) + { + TInt n; + for (n=1; n<=4; ++n) + { + TUint32 l = (n<2) ? aLambda : (aLambda/(n-1)); + DoTMX(aLock, n, l, aDummySteps, aTime); + } + aLock->Release(); + } + + +void TestMutualExclusion() + { + TInt ntp; + TInt r = HAL::Get(HAL::ENanoTickPeriod, ntp); + test_KErrNone(r); + test.Printf(_L("Nanokernel tick period = %dus\n"), ntp); + TUint32 sps = Calibrate(); + TUint32 lambda = sps/2000; + TUint32 dummy = sps/2000; + TUint32 time = 5000000; + do { + test.Printf(_L("TestMutualExclusion - RSemaphore\n")); + LockS ls; + DoTMX(&ls, lambda, dummy, time); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RSemaphore init=2\n")); + LockS ls2; + ls2.Signal(); // count=2 + DoTMX(&ls2, 4, lambda, dummy, time, ETrue); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RMutex\n")); + LockM lm; + DoTMX(&lm, lambda, dummy, time); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RFastLock\n")); + LockFL fl; + DoTMX(&fl, lambda, dummy, time); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RCriticalSection\n")); + LockCS cs; + DoTMX(&cs, lambda, dummy, time); + } while(NoRepeat); + } + + + + +/*----------------------------------------------------------------------------*/ void TestSemaphore() { /*********** TO DO ************/ @@ -417,23 +1479,23 @@ test.Next(_L("Producer/Consumer scenario")); // Test Rsemaphore with the producer/consumer scenario RThread thread1, thread2; TRequestStatus stat1, stat2; - test_KErrNone(mutex.CreateLocal()); - test_KErrNone(slotAvailable.CreateLocal(KMaxBufferSize)); - test_KErrNone(itemAvailable.CreateLocal(0)); - test_KErrNone(thread1.Create(_L("Thread1"),Producer,KDefaultStackSize,0x200,0x200,NULL)); - test_KErrNone(thread2.Create(_L("Thread2"),Consumer,KDefaultStackSize,0x200,0x200,NULL)); + test(mutex.CreateLocal()==KErrNone); + test(slotAvailable.CreateLocal(KMaxBufferSize)==KErrNone); + test(itemAvailable.CreateLocal(0)==KErrNone); + test(thread1.Create(_L("Thread1"),Producer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); + test(thread2.Create(_L("Thread2"),Consumer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); thread1.Logon(stat1); thread2.Logon(stat2); - test_Equal(KRequestPending, stat1.Int()); - test_Equal(KRequestPending, stat2.Int()); + test(stat1==KRequestPending); + test(stat2==KRequestPending); thread1.Resume(); thread2.Resume(); User::WaitForRequest(stat1); User::WaitForRequest(stat2); - test_KErrNone(stat1.Int()); - test_KErrNone(stat2.Int()); + test(stat1==KErrNone); + test(stat2==KErrNone); for(TInt jj=0;jj>1), thread1Count); + test.Printf(_L("T1 %d T1ACT %d T2 %d T2ACT %d\n"),thread1Count,thread1ActualCount,thread2Count,thread2ActualCount); + test(thread1ActualCount==thread1Count); + test(thread2ActualCount==thread2Count); + test(thread1Count==thread2Count); + test(thread1Count==(KMaxArraySize>>1)); test.Next(_L("Close")); CLOSE_AND_WAIT(thread1); @@ -524,7 +1586,7 @@ { test.Start(_L("Create")); - test_KErrNone(criticalSn.CreateLocal()); + test(criticalSn.CreateLocal()==KErrNone); /***************** TO DO *********************** @@ -553,20 +1615,21 @@ // threads think. // arrayIndex=0; + RThread thread1,thread2; - test_KErrNone(thread1.Create(_L("Thread1"),CriticalSnThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)); - test_KErrNone(thread2.Create(_L("Thread2"),CriticalSnThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)); + test(thread1.Create(_L("Thread1"),CriticalSnThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone); + test(thread2.Create(_L("Thread2"),CriticalSnThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone); TRequestStatus stat1,stat2; thread1.Logon(stat1); thread2.Logon(stat2); - test_Equal(KRequestPending, stat1.Int()); - test_Equal(KRequestPending, stat2.Int()); + test(stat1==KRequestPending); + test(stat2==KRequestPending); thread1.Resume(); thread2.Resume(); User::WaitForRequest(stat1); User::WaitForRequest(stat2); - test_KErrNone(stat1.Int()); - test_KErrNone(stat2.Int()); + test(stat1==KErrNone); + test(stat2==KErrNone); TInt thread1ActualCount=0; TInt thread2ActualCount=0; TInt ii=0; @@ -578,10 +1641,10 @@ thread2ActualCount++; ii++; } - test_Equal(thread1Count, thread1ActualCount); - test_Equal(thread2Count, thread2ActualCount); - test_Equal(thread2Count, thread1Count); - test_Equal((KMaxArraySize>>1), thread1Count); + test(thread1ActualCount==thread1Count); + test(thread2ActualCount==thread2Count); + test(thread1Count==thread2Count); + test(thread1Count==(KMaxArraySize>>1)); test.Next(_L("Close")); CLOSE_AND_WAIT(thread1); @@ -593,22 +1656,13 @@ GLDEF_C TInt E32Main() { - TInt cpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); - if (cpus != 1) - { - test(cpus>1); - // This test will require compatibility mode (and probably other changes) - // to work on SMP - it depends on explicit scheduling order. - test.Printf(_L("T_SEMUTX skipped, does not work on SMP\n")); - return KErrNone; - } - test.Title(); __UHEAP_MARK; + TestMutualExclusion(); + TestPollTimeout(); test.Start(_L("Test RSemaphore")); TestSemaphore(); - TestSemaphore2(); test.Next(_L("Test RMutex")); TestMutex(); TestMutex2();