sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\nkernsa\testdfc.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: sl@0: #ifndef __SMP__ sl@0: #define iNThreadBaseSpare7 iSpare7 sl@0: class NSchedulable; sl@0: #endif sl@0: sl@0: extern "C" TUint32 set_bit0_if_nonnull(TUint32&); sl@0: extern "C" void flip_bit0(TUint32&); sl@0: extern "C" TUint32 swap_out_if_bit0_clear(TUint32&); sl@0: sl@0: #ifdef __SMP__ sl@0: class TAddDfc : public TGenericIPI sl@0: #else sl@0: class TAddDfc : public NTimer sl@0: #endif sl@0: { sl@0: public: sl@0: TAddDfc(); sl@0: TDfc* Add(TDfc* aDfc, TUint32 aCpuMask); sl@0: static TAddDfc* New(); sl@0: #ifdef __SMP__ sl@0: static void Isr(TGenericIPI*); sl@0: #else sl@0: static void TimerCallBack(TAny*); sl@0: void WaitCompletion(); sl@0: #endif sl@0: public: sl@0: TDfc* iDfc; sl@0: }; sl@0: sl@0: TAddDfc::TAddDfc() sl@0: #ifdef __SMP__ sl@0: : iDfc(0) sl@0: #else sl@0: : NTimer(&TimerCallBack, this), sl@0: iDfc(0) sl@0: #endif sl@0: { sl@0: } sl@0: sl@0: TAddDfc* TAddDfc::New() sl@0: { sl@0: TAddDfc* p = new TAddDfc; sl@0: TEST_OOM(p); sl@0: return p; sl@0: } sl@0: sl@0: #ifdef __SMP__ sl@0: void TAddDfc::Isr(TGenericIPI* a) sl@0: #else sl@0: void TAddDfc::TimerCallBack(TAny* a) sl@0: #endif sl@0: { sl@0: TAddDfc& adder = *(TAddDfc*)a; sl@0: TDfc* dfc = (TDfc*)__e32_atomic_swp_ord_ptr(&adder.iDfc, 0); sl@0: if (dfc) sl@0: dfc->Add(); sl@0: } sl@0: sl@0: TDfc* TAddDfc::Add(TDfc* aDfc, TUint32 aCpuMask) sl@0: { sl@0: TDfc* old = (TDfc*)__e32_atomic_swp_ord_ptr(&iDfc, aDfc); sl@0: #ifdef __SMP__ sl@0: Queue(&Isr, aCpuMask); sl@0: #else sl@0: (void)aCpuMask; sl@0: OneShot(1); sl@0: #endif sl@0: return old; sl@0: } sl@0: sl@0: #ifndef __SMP__ sl@0: void TAddDfc::WaitCompletion() sl@0: { sl@0: while (iDfc) sl@0: {} sl@0: } sl@0: #endif sl@0: sl@0: class TTestDfc : public TDfc sl@0: { sl@0: public: sl@0: TTestDfc(TUint aId); sl@0: TTestDfc(TUint aId, TDfcQue* aQ, TInt aPri); sl@0: static void Run(TAny* aPtr); sl@0: sl@0: static void CheckEmpty(TInt aLine); sl@0: static void CheckFirstEntry(TInt aLine, TUint32 aCpu, TUint32 aContext, TDfcQue* aQ, TUint32 aId); sl@0: sl@0: static CircBuf* Buffer; sl@0: static volatile TBool Full; sl@0: static volatile TUint32 Last; sl@0: sl@0: enum {EBufferSlots=1024}; sl@0: }; sl@0: sl@0: #define CHECK_EMPTY() TTestDfc::CheckEmpty(__LINE__) sl@0: #define CHECK_FIRST_ENTRY(cpu, ctx, q, id) TTestDfc::CheckFirstEntry(__LINE__, cpu, ctx, q, id) sl@0: sl@0: CircBuf* TTestDfc::Buffer; sl@0: volatile TBool TTestDfc::Full = FALSE; sl@0: volatile TUint32 TTestDfc::Last; sl@0: sl@0: TTestDfc::TTestDfc(TUint aId) sl@0: : TDfc(&Run, (TAny*)aId) sl@0: { sl@0: } sl@0: sl@0: TTestDfc::TTestDfc(TUint aId, TDfcQue* aQ, TInt aPri) sl@0: : TDfc(&Run, (TAny*)aId, aQ, aPri) sl@0: { sl@0: } sl@0: sl@0: void TTestDfc::Run(TAny* aPtr) sl@0: { sl@0: TUint32 id = (TUint32)aPtr; sl@0: TUint32 tid = 0; sl@0: TUint32 ctx = NKern::CurrentContext(); sl@0: TUint32 cpu = NKern::CurrentCpu(); sl@0: if (ctx == NKern::EThread) sl@0: { sl@0: NThread* t = NKern::CurrentThread(); sl@0: tid = t->iNThreadBaseSpare7; sl@0: } sl@0: TUint32 x = (cpu<<24) | (ctx<<16) | (tid<<8) | id; sl@0: TInt r = Buffer->TryPut(x); sl@0: if (r != KErrNone) sl@0: Full = TRUE; sl@0: Last = id; sl@0: } sl@0: sl@0: void TTestDfc::CheckEmpty(TInt aLine) sl@0: { sl@0: TInt c = Buffer->Count(); sl@0: TUint32 x; sl@0: Buffer->TryGet(x); sl@0: if (c!=0) sl@0: { sl@0: TEST_PRINT3("Line %d Buffer not empty C:%d X:%08x", aLine, c, x); sl@0: } sl@0: } sl@0: sl@0: void TTestDfc::CheckFirstEntry(TInt aLine, TUint32 aCpu, TUint32 aContext, TDfcQue* aQ, TUint32 aId) sl@0: { sl@0: TUint32 tid = aQ ? aQ->iThread->iNThreadBaseSpare7 : 0; sl@0: TUint32 expected = (aCpu<<24) | (aContext<<16) | (tid << 8) | aId; sl@0: TUint32 x; sl@0: TInt r = Buffer->TryGet(x); sl@0: if (r!=KErrNone) sl@0: { sl@0: TEST_PRINT2("Line %d Buffer empty, Expected %08x", aLine, expected); sl@0: } sl@0: else if (x != expected) sl@0: { sl@0: TEST_PRINT3("Line %d Got %08x Expected %08x", aLine, x, expected); sl@0: } sl@0: } sl@0: sl@0: class TPauseIDFC : public TDfc sl@0: { sl@0: public: sl@0: TPauseIDFC(); sl@0: void Pause(TInt aCpu); sl@0: void Release(); sl@0: static void Run(TAny*); sl@0: public: sl@0: volatile TInt iFlag; sl@0: }; sl@0: sl@0: TPauseIDFC::TPauseIDFC() sl@0: : TDfc(&Run, this), sl@0: iFlag(-1) sl@0: { sl@0: } sl@0: sl@0: void TPauseIDFC::Pause(TInt aCpu) sl@0: { sl@0: TAddDfc adder; sl@0: iFlag = -1; sl@0: __e32_memory_barrier(); sl@0: adder.Add(this, 1u<iFlag, 0); sl@0: while (__e32_atomic_load_acq32(&p->iFlag) == 0) sl@0: {} sl@0: } sl@0: sl@0: class TPauseDFC : public TDfc sl@0: { sl@0: public: sl@0: TPauseDFC(TDfcQue* aQ); sl@0: void Pause(TInt aWait=0); sl@0: void BusyPause(); sl@0: void Release(); sl@0: static void Run(TAny*); sl@0: public: sl@0: NFastSemaphore* volatile iSem; sl@0: volatile TInt iWait; sl@0: }; sl@0: sl@0: TPauseDFC::TPauseDFC(TDfcQue* aQ) sl@0: : TDfc(&Run, this, aQ, 0), sl@0: iSem(0) sl@0: { sl@0: } sl@0: sl@0: void TPauseDFC::Pause(TInt aWait) sl@0: { sl@0: iWait = aWait; sl@0: NFastSemaphore entrySem(0); sl@0: iSem = &entrySem; sl@0: Enque(); sl@0: NKern::FSWait(&entrySem); sl@0: } sl@0: sl@0: void TPauseDFC::BusyPause() sl@0: { sl@0: volatile TInt& flag = (volatile TInt&)iSem; sl@0: __e32_atomic_store_ord32(&flag, 0xfffffffe); sl@0: Enque(); sl@0: while (__e32_atomic_load_acq32(&flag) == 0xfffffffe) sl@0: {} sl@0: } sl@0: sl@0: void TPauseDFC::Release() sl@0: { sl@0: NFastSemaphore* s = (NFastSemaphore*)__e32_atomic_swp_ord_ptr(&iSem, 0); sl@0: if (((TInt)s)==-1) sl@0: { sl@0: volatile TInt& flag = (volatile TInt&)iSem; sl@0: __e32_atomic_store_ord32(&flag, 0); sl@0: } sl@0: else sl@0: NKern::FSSignal(s); sl@0: } sl@0: sl@0: void TPauseDFC::Run(TAny* aPtr) sl@0: { sl@0: TPauseDFC* p = (TPauseDFC*)aPtr; sl@0: volatile TInt& flag = (volatile TInt&)p->iSem; sl@0: if (flag == -2) sl@0: { sl@0: flag = -1; sl@0: __e32_memory_barrier(); sl@0: while (flag == -1) sl@0: {} sl@0: } sl@0: else sl@0: { sl@0: NFastSemaphore exitSem(0); sl@0: NFastSemaphore* s = (NFastSemaphore*)__e32_atomic_swp_ord_ptr(&p->iSem, &exitSem); sl@0: if (p->iWait) sl@0: { sl@0: nfcfspin(__microseconds_to_norm_fast_counter(10000)); sl@0: NKern::Sleep(p->iWait); sl@0: } sl@0: NKern::FSSignal(s); sl@0: NKern::FSWait(&exitSem); sl@0: } sl@0: } sl@0: sl@0: void DoDFCTest1() sl@0: { sl@0: TEST_PRINT("DFCTest1"); sl@0: TInt cpu; sl@0: for_each_cpu(cpu) sl@0: { sl@0: TDfcQue* q = CreateDfcQ("DfcQ0", 1, cpu); sl@0: DestroyDfcQ(q); sl@0: q = CreateDfcQ("DfcQ1", 32, cpu); sl@0: DestroyDfcQ(q); sl@0: } sl@0: } sl@0: sl@0: TBool QueueDfc(TDfc* aDfc, TInt aMode, TBool aExRet) sl@0: { sl@0: if (aMode==0) sl@0: return !aExRet == !aDfc->Enque(); sl@0: else if (aMode>0) sl@0: { sl@0: TAddDfc adder; sl@0: TInt cpu = aMode - 1; sl@0: adder.Add(aDfc, 1u<Add(); sl@0: NKern::Unlock(); sl@0: return !aExRet == !ret; sl@0: } sl@0: return FALSE; sl@0: } sl@0: sl@0: #define QUEUE_DFC(dfc, mode, exret) TEST_RESULT(QueueDfc(dfc,mode,exret),"") sl@0: sl@0: void DoDFCTest2() sl@0: { sl@0: TEST_PRINT("DFCTest2"); sl@0: TInt num_cpus = NKern::NumberOfCpus(); sl@0: TInt this_cpu = NKern::CurrentCpu(); sl@0: TDfcQue* q; sl@0: q = CreateDfcQ("DfcQ2", 1, this_cpu); sl@0: TEST_OOM(q); sl@0: q->iThread->iNThreadBaseSpare7 = 1; sl@0: sl@0: TTestDfc* d1 = new TTestDfc(1, q, 1); sl@0: TEST_OOM(d1); sl@0: TEST_RESULT(!d1->IsIDFC(), ""); sl@0: TTestDfc* d2 = new TTestDfc(2, q, 2); sl@0: TEST_OOM(d2); sl@0: TEST_RESULT(!d2->IsIDFC(), ""); sl@0: TTestDfc* d3 = new TTestDfc(3, q, 2); sl@0: TEST_OOM(d3); sl@0: TEST_RESULT(!d3->IsIDFC(), ""); sl@0: TTestDfc* d4 = new TTestDfc(4, q, 3); sl@0: TEST_OOM(d4); sl@0: TEST_RESULT(!d4->IsIDFC(), ""); sl@0: sl@0: TInt mode; sl@0: for (mode=-1; mode<=num_cpus; ++mode) sl@0: { sl@0: TEST_PRINT1("Mode %d", mode); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, FALSE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(30); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(30); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d4->Queued(), ""); sl@0: TEST_RESULT(d4->Cancel(), ""); sl@0: TEST_RESULT(!d4->Cancel(), ""); sl@0: TEST_RESULT(!d4->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(30); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d3->Queued(), ""); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: TEST_RESULT(!d3->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(30); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d3->Queued(), ""); sl@0: TEST_RESULT(d2->Queued(), ""); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: TEST_RESULT(d2->Cancel(), ""); sl@0: TEST_RESULT(!d3->Queued(), ""); sl@0: TEST_RESULT(!d2->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(30); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: TEST_RESULT(d2->Cancel(), ""); sl@0: TEST_RESULT(d4->Cancel(), ""); sl@0: TEST_RESULT(d1->Cancel(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(30); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: TEST_RESULT(d2->Cancel(), ""); sl@0: TEST_RESULT(d4->Cancel(), ""); sl@0: TEST_RESULT(d1->Cancel(), ""); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, FALSE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(30); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: } sl@0: sl@0: delete d4; sl@0: delete d3; sl@0: delete d2; sl@0: delete d1; sl@0: DestroyDfcQ(q); sl@0: } sl@0: sl@0: void DoDFCTest3(TInt aCpu) sl@0: { sl@0: TEST_PRINT1("DFCTest3 CPU %d", aCpu); sl@0: TInt num_cpus = NKern::NumberOfCpus(); sl@0: TInt this_cpu = NKern::CurrentCpu(); sl@0: TBool same_cpu = (aCpu==this_cpu); sl@0: TDfcQue* q; sl@0: q = CreateDfcQ("DfcQ2", 32, aCpu); sl@0: TEST_OOM(q); sl@0: q->iThread->iNThreadBaseSpare7 = 1; sl@0: TPauseDFC pauser(q); sl@0: sl@0: TTestDfc* d1 = new TTestDfc(1, q, 1); sl@0: TEST_OOM(d1); sl@0: TEST_RESULT(!d1->IsIDFC(), ""); sl@0: TTestDfc* d2 = new TTestDfc(2, q, 2); sl@0: TEST_OOM(d2); sl@0: TEST_RESULT(!d2->IsIDFC(), ""); sl@0: TTestDfc* d3 = new TTestDfc(3, q, 2); sl@0: TEST_OOM(d3); sl@0: TEST_RESULT(!d3->IsIDFC(), ""); sl@0: TTestDfc* d4 = new TTestDfc(4, q, 3); sl@0: TEST_OOM(d4); sl@0: TEST_RESULT(!d4->IsIDFC(), ""); sl@0: sl@0: TInt mode; sl@0: for (mode=-1; mode<=num_cpus; ++mode) sl@0: { sl@0: TEST_PRINT1("Mode %d", mode); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: if (!same_cpu) sl@0: while (d1->Queued()) {} sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: if (!same_cpu) sl@0: while (d1->Queued()) {} sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: if (!same_cpu) sl@0: while (d2->Queued()) {} sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: if (!same_cpu) sl@0: while (d3->Queued()) {} sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: if (!same_cpu) sl@0: while (d4->Queued()) {} sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: if (!same_cpu) sl@0: while (d1->Queued()) {} sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: if (!same_cpu) sl@0: while (d1->Queued()) {} sl@0: TEST_RESULT(!d4->Queued(), ""); sl@0: TEST_RESULT(!d4->Cancel(), ""); sl@0: TEST_RESULT(!d4->Queued(), ""); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: pauser.Pause(); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, FALSE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d4, mode, FALSE); sl@0: CHECK_EMPTY(); sl@0: pauser.Release(); sl@0: pauser.Pause(); sl@0: pauser.Release(); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: pauser.Pause(); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, FALSE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: CHECK_EMPTY(); sl@0: pauser.Release(); sl@0: pauser.Pause(); sl@0: pauser.Release(); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); sl@0: CHECK_EMPTY(); sl@0: pauser.Pause(); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d1, mode, FALSE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_DFC(d2, mode, TRUE); sl@0: QUEUE_DFC(d3, mode, TRUE); sl@0: QUEUE_DFC(d4, mode, TRUE); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(d1->Cancel(), ""); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: pauser.Release(); sl@0: pauser.Pause(); sl@0: pauser.Release(); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); sl@0: CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); sl@0: CHECK_EMPTY(); sl@0: } sl@0: sl@0: delete d4; sl@0: delete d3; sl@0: delete d2; sl@0: delete d1; sl@0: DestroyDfcQ(q); sl@0: } sl@0: sl@0: TBool QueueIDfc(TDfc* aDfc, TInt aMode, TBool aExRet) sl@0: { sl@0: if (aMode==0) sl@0: return !aExRet == !aDfc->RawAdd(); sl@0: else if (aMode>0) sl@0: { sl@0: TTestDfc::Last = 0xffffffffu; sl@0: TAddDfc adder; sl@0: TInt cpu = (aMode&0xff) - 1; sl@0: adder.Add(aDfc, 1u<iPtr) sl@0: {} sl@0: } sl@0: return TRUE; sl@0: } sl@0: else if (aMode==-1) sl@0: { sl@0: NKern::Lock(); sl@0: TBool ret = aDfc->Add(); sl@0: NKern::Unlock(); sl@0: return !aExRet == !ret; sl@0: } sl@0: return FALSE; sl@0: } sl@0: sl@0: #define QUEUE_IDFC(dfc, mode, exret) TEST_RESULT(QueueIDfc(dfc,mode,exret),"") sl@0: sl@0: void DoIDFCTest1() sl@0: { sl@0: TEST_PRINT("IDFCTest1"); sl@0: sl@0: TInt num_cpus = NKern::NumberOfCpus(); sl@0: TInt this_cpu = NKern::CurrentCpu(); sl@0: sl@0: TTestDfc* d1 = new TTestDfc(1); sl@0: TEST_OOM(d1); sl@0: TEST_RESULT(d1->IsIDFC(), ""); sl@0: TTestDfc* d2 = new TTestDfc(2); sl@0: TEST_OOM(d2); sl@0: TEST_RESULT(d2->IsIDFC(), ""); sl@0: TTestDfc* d3 = new TTestDfc(3); sl@0: TEST_OOM(d3); sl@0: TEST_RESULT(d3->IsIDFC(), ""); sl@0: TTestDfc* d4 = new TTestDfc(4); sl@0: TEST_OOM(d4); sl@0: TEST_RESULT(d4->IsIDFC(), ""); sl@0: sl@0: TInt mode; sl@0: for (mode=-1; mode<=num_cpus; ++mode) sl@0: { sl@0: TInt xcpu = (mode>0) ? (mode-1) : this_cpu; sl@0: TEST_PRINT1("Mode %d", mode); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_IDFC(d1, mode, TRUE); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_IDFC(d1, mode, TRUE); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_IDFC(d2, mode, TRUE); sl@0: QUEUE_IDFC(d3, mode, TRUE); sl@0: QUEUE_IDFC(d4, mode, TRUE); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 3); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4); sl@0: CHECK_EMPTY(); sl@0: QUEUE_IDFC(d4, mode, TRUE); sl@0: QUEUE_IDFC(d3, mode, TRUE); sl@0: QUEUE_IDFC(d2, mode, TRUE); sl@0: QUEUE_IDFC(d1, mode, TRUE); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 3); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); sl@0: CHECK_EMPTY(); sl@0: } sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: TEST_RESULT(d1->RawAdd(), ""); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::RestoreInterrupts(irq); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); sl@0: sl@0: NKern::Lock(); sl@0: TEST_RESULT(d1->Add(), ""); sl@0: TEST_RESULT(d3->Add(), ""); sl@0: TEST_RESULT(d2->Add(), ""); sl@0: TEST_RESULT(d4->Add(), ""); sl@0: TEST_RESULT(!d1->Add(), ""); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: TEST_RESULT(d2->Queued(), ""); sl@0: TEST_RESULT(d3->Queued(), ""); sl@0: TEST_RESULT(d4->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Unlock(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: TEST_RESULT(!d2->Queued(), ""); sl@0: TEST_RESULT(!d3->Queued(), ""); sl@0: TEST_RESULT(!d4->Queued(), ""); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 3); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 2); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4); sl@0: CHECK_EMPTY(); sl@0: sl@0: NKern::Lock(); sl@0: TEST_RESULT(d1->Add(), ""); sl@0: TEST_RESULT(d3->Add(), ""); sl@0: TEST_RESULT(d2->Add(), ""); sl@0: TEST_RESULT(d4->Add(), ""); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: TEST_RESULT(d2->Queued(), ""); sl@0: TEST_RESULT(d3->Queued(), ""); sl@0: TEST_RESULT(d4->Queued(), ""); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: TEST_RESULT(!d3->Queued(), ""); sl@0: TEST_RESULT(!d3->Cancel(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Unlock(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: TEST_RESULT(!d2->Queued(), ""); sl@0: TEST_RESULT(!d4->Queued(), ""); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 2); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4); sl@0: CHECK_EMPTY(); sl@0: sl@0: NKern::Lock(); sl@0: TEST_RESULT(d1->Add(), ""); sl@0: TEST_RESULT(d3->Add(), ""); sl@0: TEST_RESULT(d2->Add(), ""); sl@0: TEST_RESULT(d4->Add(), ""); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: TEST_RESULT(d2->Queued(), ""); sl@0: TEST_RESULT(d3->Queued(), ""); sl@0: TEST_RESULT(d4->Queued(), ""); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: TEST_RESULT(d1->Cancel(), ""); sl@0: TEST_RESULT(d2->Cancel(), ""); sl@0: TEST_RESULT(d4->Cancel(), ""); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: TEST_RESULT(!d2->Queued(), ""); sl@0: TEST_RESULT(!d3->Queued(), ""); sl@0: TEST_RESULT(!d4->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Unlock(); sl@0: CHECK_EMPTY(); sl@0: sl@0: TPauseIDFC pauser; sl@0: TInt cpu; sl@0: for_each_cpu(cpu) sl@0: { sl@0: if (cpu == this_cpu) sl@0: continue; sl@0: mode = cpu + 0x101; sl@0: TEST_PRINT1("CPU %d", cpu); sl@0: pauser.Pause(cpu); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_IDFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_IDFC(d1, mode, FALSE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_IDFC(d2, mode, TRUE); sl@0: QUEUE_IDFC(d3, mode, TRUE); sl@0: QUEUE_IDFC(d4, mode, TRUE); sl@0: CHECK_EMPTY(); sl@0: pauser.Release(); sl@0: pauser.Pause(cpu); sl@0: pauser.Release(); sl@0: CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 1); sl@0: CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 2); sl@0: CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 3); sl@0: CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 4); sl@0: CHECK_EMPTY(); sl@0: pauser.Pause(cpu); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_IDFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_IDFC(d2, mode, TRUE); sl@0: QUEUE_IDFC(d3, mode, TRUE); sl@0: QUEUE_IDFC(d4, mode, TRUE); sl@0: TEST_RESULT(d1->Cancel(), ""); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: TEST_RESULT(!d1->Cancel(), ""); sl@0: CHECK_EMPTY(); sl@0: pauser.Release(); sl@0: pauser.Pause(cpu); sl@0: pauser.Release(); sl@0: CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 2); sl@0: CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 3); sl@0: CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 4); sl@0: CHECK_EMPTY(); sl@0: pauser.Pause(cpu); sl@0: CHECK_EMPTY(); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: QUEUE_IDFC(d1, mode, TRUE); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: QUEUE_IDFC(d2, mode, TRUE); sl@0: QUEUE_IDFC(d3, mode, TRUE); sl@0: QUEUE_IDFC(d4, mode, TRUE); sl@0: TEST_RESULT(d1->Cancel(), ""); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: TEST_RESULT(d4->Cancel(), ""); sl@0: TEST_RESULT(d2->Cancel(), ""); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: CHECK_EMPTY(); sl@0: pauser.Release(); sl@0: pauser.Pause(cpu); sl@0: pauser.Release(); sl@0: CHECK_EMPTY(); sl@0: } sl@0: sl@0: delete d4; sl@0: delete d3; sl@0: delete d2; sl@0: delete d1; sl@0: } sl@0: sl@0: void DoIdleDFCTest1(TInt aCpu) sl@0: { sl@0: #ifdef __SMP__ sl@0: TEST_PRINT2("IdleDFCTest1 CPU %d (%08x)", aCpu, TheScheduler.iCpusNotIdle); sl@0: #else sl@0: TEST_PRINT1("IdleDFCTest1 CPU %d (%08x)", aCpu); sl@0: #endif sl@0: // TInt num_cpus = NKern::NumberOfCpus(); sl@0: TInt this_cpu = NKern::CurrentCpu(); sl@0: TBool same_cpu = (aCpu==this_cpu); sl@0: TDfcQue* q = 0; sl@0: TPauseDFC* pauser = 0; sl@0: if (!same_cpu) sl@0: { sl@0: q = CreateDfcQ("DfcQ3", 1, aCpu); sl@0: TEST_OOM(q); sl@0: pauser = new TPauseDFC(q); sl@0: TEST_OOM(pauser); sl@0: } sl@0: sl@0: TTestDfc* d1 = new TTestDfc(1); sl@0: TEST_OOM(d1); sl@0: TEST_RESULT(d1->IsIDFC(), ""); sl@0: TTestDfc* d2 = new TTestDfc(2); sl@0: TEST_OOM(d2); sl@0: TEST_RESULT(d2->IsIDFC(), ""); sl@0: TTestDfc* d3 = new TTestDfc(3); sl@0: TEST_OOM(d3); sl@0: TEST_RESULT(d3->IsIDFC(), ""); sl@0: TTestDfc* d4 = new TTestDfc(4); sl@0: TEST_OOM(d4); sl@0: TEST_RESULT(d4->IsIDFC(), ""); sl@0: sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: TEST_RESULT(d1->QueueOnIdle(), ""); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: TEST_RESULT(!d1->QueueOnIdle(), ""); sl@0: CHECK_EMPTY(); sl@0: if (pauser) sl@0: pauser->BusyPause(); sl@0: NKern::Sleep(1); sl@0: if (pauser) sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: else sl@0: { sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); sl@0: } sl@0: CHECK_EMPTY(); sl@0: TBool ret = d1->QueueOnIdle(); sl@0: TEST_RESULT(pauser?!ret:ret, ""); sl@0: TEST_RESULT(d1->Queued(), ""); sl@0: TEST_RESULT(d1->Cancel(), ""); sl@0: TEST_RESULT(!d1->Queued(), ""); sl@0: CHECK_EMPTY(); sl@0: NKern::Sleep(1); sl@0: CHECK_EMPTY(); sl@0: if (pauser) sl@0: pauser->Release(); sl@0: TEST_RESULT(d4->QueueOnIdle(), ""); sl@0: TEST_RESULT(d3->QueueOnIdle(), ""); sl@0: TEST_RESULT(d1->QueueOnIdle(), ""); sl@0: TEST_RESULT(d2->QueueOnIdle(), ""); sl@0: TEST_RESULT(d3->Cancel(), ""); sl@0: CHECK_EMPTY(); sl@0: TInt xcpu = this_cpu; sl@0: if (pauser) sl@0: { sl@0: xcpu = aCpu; sl@0: pauser->Pause(1); sl@0: pauser->Release(); sl@0: } sl@0: else sl@0: NKern::Sleep(1); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); sl@0: CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2); sl@0: CHECK_EMPTY(); sl@0: sl@0: delete d4; sl@0: delete d3; sl@0: delete d2; sl@0: delete d1; sl@0: delete pauser; sl@0: if (q) sl@0: DestroyDfcQ(q); sl@0: } sl@0: sl@0: TDfc* Dfcs[6]; sl@0: NFastSemaphore* IdleDFCTest2Fs; sl@0: sl@0: void IdleDFCTest2Fn(TAny* a) sl@0: { sl@0: TUint32 id = (TUint32)a; sl@0: if (id==1) sl@0: { sl@0: TEST_RESULT(Dfcs[1]->Cancel(), ""); sl@0: TEST_RESULT(Dfcs[3]->QueueOnIdle(), ""); sl@0: TEST_RESULT(Dfcs[4]->QueueOnIdle(), ""); sl@0: TEST_RESULT(Dfcs[5]->QueueOnIdle(), ""); sl@0: } sl@0: if (id==1 || id==4) sl@0: IdleDFCTest2Fs->Signal(); sl@0: if (id==3) sl@0: { sl@0: TEST_RESULT(Dfcs[5]->Cancel(), ""); sl@0: } sl@0: TTestDfc::Run(a); sl@0: } sl@0: sl@0: void DoIdleDFCTest2() sl@0: { sl@0: TEST_PRINT("IdleDFCTest2"); sl@0: NFastSemaphore sem(0); sl@0: TInt this_cpu = NKern::CurrentCpu(); sl@0: TInt i; sl@0: for (i=0; i<6; ++i) sl@0: { sl@0: Dfcs[i] = new TDfc(&IdleDFCTest2Fn, (TAny*)(i+1)); sl@0: TEST_OOM(Dfcs[i]); sl@0: } sl@0: TEST_RESULT(Dfcs[0]->QueueOnIdle(), ""); sl@0: TEST_RESULT(Dfcs[1]->QueueOnIdle(), ""); sl@0: TEST_RESULT(Dfcs[2]->QueueOnIdle(), ""); sl@0: IdleDFCTest2Fs = &sem; sl@0: CHECK_EMPTY(); sl@0: NKern::FSWait(&sem); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 3); sl@0: CHECK_EMPTY(); sl@0: NKern::FSWait(&sem); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4); sl@0: CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 5); sl@0: CHECK_EMPTY(); sl@0: for (i=0; i<6; ++i) sl@0: delete Dfcs[i]; sl@0: } sl@0: sl@0: #ifdef __SMP__ sl@0: sl@0: class TDfcStress; sl@0: class TDfcX sl@0: { sl@0: public: sl@0: enum sl@0: { sl@0: EFlag_IdleDFC=1, sl@0: EFlag_IDFC=2, sl@0: EFlag_DFC=4, sl@0: EFlag_Timer=8, sl@0: EFlag_Tied=16 sl@0: }; sl@0: public: sl@0: TDfcX(); sl@0: ~TDfcX(); sl@0: static void IDfcFn(TAny*); sl@0: static void DfcFn(TAny*); sl@0: static void TimerIsrFn(TAny*); sl@0: static void TimerDfcFn(TAny*); sl@0: void Update(); sl@0: TBool Add(TAny* a=0); sl@0: TBool Cancel(TAny* a=0); sl@0: TBool Enque(TAny* a=0); sl@0: TBool QueueOnIdle(TAny* a=0); sl@0: TBool SafeAdd(); sl@0: TBool SafeCancel(); sl@0: TBool SafeEnque(); sl@0: TBool SafeQueueOnIdle(); sl@0: void CreateDfcOrTimer(); sl@0: void GetDesc(char* aDesc); sl@0: inline TBool IsIDFC() sl@0: {return (iFlags & (EFlag_IDFC|EFlag_Timer)) == EFlag_IDFC;} sl@0: inline TBool IsIdler() sl@0: {return iFlags & EFlag_IdleDFC;} sl@0: void ThreadActivity(); sl@0: public: sl@0: union sl@0: { sl@0: TDfc* volatile iDfc; sl@0: NTimer* volatile iTimer; sl@0: }; sl@0: TDfcQue* iDfcQ; sl@0: TUint32 iQueueCount; sl@0: TUint32 iRunCount[KMaxCpus]; sl@0: TUint32 iCancelCount; sl@0: TUint32 iExclusionFailCount; sl@0: TUint32 iId; sl@0: TUint32 iFlags; sl@0: TDfcStress* iS; sl@0: TUint64 iTimeQueued; sl@0: TUint64 iMaxTime; sl@0: TUint64 iSumTime; sl@0: TSpinLock iSpinLock; sl@0: NSchedulable* iXTied; sl@0: volatile TUint32* iExclusionCheck; sl@0: }; sl@0: sl@0: TDfcX::TDfcX() sl@0: : iSpinLock(TSpinLock::EOrderGenericIrqLow1) sl@0: { sl@0: memclr(this,sizeof(TDfcX)); sl@0: new (&iSpinLock) TSpinLock(TSpinLock::EOrderGenericIrqLow1); sl@0: } sl@0: sl@0: TDfcX::~TDfcX() sl@0: { sl@0: TAny* p = __e32_atomic_swp_ord_ptr(&iDfc, 0); sl@0: if (p) sl@0: { sl@0: if (iFlags & EFlag_Timer) sl@0: delete ((NTimer*)p); sl@0: else sl@0: delete ((TDfc*)p); sl@0: } sl@0: } sl@0: sl@0: class TDfcStress sl@0: { sl@0: public: sl@0: enum sl@0: { sl@0: EMode_Wait =0x00000001u, sl@0: EMode_AllowCancel =0x00000002u, sl@0: EMode_AllowIdle =0x00000004u, sl@0: EMode_AllowEnque =0x00000008u, sl@0: EMode_Recycle =0x00000010u, sl@0: EMode_UseTied =0x00000020u, sl@0: EMode_Migrate =0x00000040u, sl@0: EMode_SelfMigrate =0x00000080u, sl@0: EMode_Exit =0x80000000u sl@0: }; sl@0: public: sl@0: enum {EMaxDfc=48, EMaxDfcQ=8}; sl@0: sl@0: TDfcStress(); sl@0: static TDfcStress* New(TInt aNumDfc, TInt aNumDfcQ, TBool aTimerTest); sl@0: void Create(); sl@0: static void DoThreadFn(TAny*); sl@0: void ThreadFn(); sl@0: static void BackStopFn(TAny*); sl@0: void Run(); sl@0: void Close(); sl@0: void DoTestPhase(TInt aMode, TInt aTime, TInt aCount); sl@0: void GetModeText(char* aName); sl@0: public: sl@0: TDfcX* NewDfc(TUint32 aId, TUint32 aFlags, TInt aDfcQ); sl@0: TDfcX* NewIDfc(TUint32 aId, TUint32 aFlags, NSchedulable* aTied=0); sl@0: TDfcX* NewTimer(TUint32 aId, TUint32 aFlags, TInt aDfcQ, NSchedulable* aTied); sl@0: void CreateDfc(TUint32 aId); sl@0: public: sl@0: TInt iNumDfc; sl@0: TDfcX* iDfcX[EMaxDfc]; sl@0: TInt iNumDfcQ; sl@0: TBool iTimerTest; sl@0: TDfcQue* iDfcQ[EMaxDfcQ]; sl@0: NThread* iThread[KMaxCpus]; sl@0: volatile TBool iStop; sl@0: volatile TInt iRunning; sl@0: volatile TInt iMode; sl@0: NFastSemaphore* iExitSem; sl@0: TDfcX* volatile iGarbage; sl@0: TUint32 iRandomTimeLimit; sl@0: TDfc* iBackStopIdleDfc; sl@0: TDfcQue* iBackStopIdleDfcQ; sl@0: }; sl@0: sl@0: void TDfcX::Update() sl@0: { sl@0: TUint32 exc0 = 0; sl@0: TUint32 exc1 = 0; sl@0: if (iExclusionCheck) sl@0: exc0 = *iExclusionCheck; sl@0: TInt cpu = NKern::CurrentCpu(); sl@0: __e32_atomic_add_ord32(&iRunCount[cpu], 1); sl@0: TInt ctx = NKern::CurrentContext(); sl@0: TBool is_idfc = IsIDFC(); sl@0: TBool is_timer = iFlags & EFlag_Timer; sl@0: TBool is_tied = iFlags & EFlag_Tied; sl@0: if ((is_idfc||is_timer) && is_tied && !(iS->iMode & (TDfcStress::EMode_Migrate|TDfcStress::EMode_SelfMigrate))) sl@0: { sl@0: TInt cpu = NKern::CurrentCpu(); sl@0: TInt xcpu = iXTied->iCpuAffinity; sl@0: if (cpu != xcpu) sl@0: { sl@0: __crash(); sl@0: } sl@0: } sl@0: TInt irq=0; sl@0: if ((ctx!=NKern::EThread) && (iS->iMode & TDfcStress::EMode_AllowCancel)) sl@0: irq = iSpinLock.LockIrqSave(); sl@0: TUint64 now = fast_counter(); sl@0: TUint64 delta = now - iTimeQueued; sl@0: if (TInt64(delta)>=0) sl@0: { sl@0: if (delta > iMaxTime) sl@0: iMaxTime = delta; sl@0: iSumTime += delta; sl@0: } sl@0: if ((ctx!=NKern::EThread) && (iS->iMode & TDfcStress::EMode_AllowCancel)) sl@0: iSpinLock.UnlockIrqRestore(irq); sl@0: if (IsIdler()) sl@0: { sl@0: TInt i; sl@0: NKern::Lock(); sl@0: for (i=0; iiThread[i]; sl@0: if (t) sl@0: t->iRequestSemaphore.Reset(); sl@0: } sl@0: NKern::Unlock(); sl@0: iS->iBackStopIdleDfc->Cancel(); sl@0: } sl@0: if (iExclusionCheck) sl@0: exc1 = *iExclusionCheck; sl@0: if (exc0!=exc1) sl@0: __e32_atomic_add_ord32(&iExclusionFailCount, 1); sl@0: } sl@0: sl@0: void TDfcStress::BackStopFn(TAny* a) sl@0: { sl@0: TDfcStress* s = (TDfcStress*)a; sl@0: TInt i; sl@0: NKern::Lock(); sl@0: for (i=0; iiThread[i]; sl@0: if (t) sl@0: t->iRequestSemaphore.Reset(); sl@0: } sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: void TDfcX::IDfcFn(TAny* a) sl@0: { sl@0: TDfcX* d = (TDfcX*)a; sl@0: d->Update(); sl@0: } sl@0: sl@0: void TDfcX::DfcFn(TAny* a) sl@0: { sl@0: TDfcX* d = (TDfcX*)a; sl@0: d->ThreadActivity(); sl@0: d->Update(); sl@0: d->ThreadActivity(); sl@0: } sl@0: sl@0: void TDfcX::TimerDfcFn(TAny* a) sl@0: { sl@0: TDfcX* d = (TDfcX*)a; sl@0: d->ThreadActivity(); sl@0: d->Update(); sl@0: d->ThreadActivity(); sl@0: } sl@0: sl@0: void TDfcX::TimerIsrFn(TAny* a) sl@0: { sl@0: TDfcX* d = (TDfcX*)a; sl@0: d->Update(); sl@0: } sl@0: sl@0: void TDfcX::ThreadActivity() sl@0: { sl@0: TInt ncpus = NKern::NumberOfCpus(); sl@0: TInt ocpu = NKern::CurrentCpu(); sl@0: NThread* pC = NKern::CurrentThread(); sl@0: volatile TUint32* pX = (volatile TUint32*)&pC->iRunCount32[1]; // HACK! sl@0: TInt cpu = ocpu; sl@0: TInt i; sl@0: if ((iS->iMode & TDfcStress::EMode_SelfMigrate) && !pC->iEvents.IsEmpty()) sl@0: { sl@0: for (i=0; iOneShot(1) == KErrNone; sl@0: else sl@0: ok = ((TDfc*)a)->Add(); sl@0: if (ok) sl@0: { sl@0: iTimeQueued = time; sl@0: __e32_atomic_add_ord32(&iQueueCount, 1); sl@0: } sl@0: return ok; sl@0: } sl@0: sl@0: TBool TDfcX::Cancel(TAny* a) sl@0: { sl@0: TBool is_timer = iFlags & EFlag_Timer; sl@0: if (!a) sl@0: a = iDfc; sl@0: TBool ok; sl@0: if (is_timer) sl@0: ok = ((NTimer*)a)->Cancel(); sl@0: else sl@0: ok = ((TDfc*)a)->Cancel(); sl@0: if (ok) sl@0: __e32_atomic_add_ord32(&iCancelCount, 1); sl@0: return ok; sl@0: } sl@0: sl@0: TBool TDfcX::Enque(TAny* a) sl@0: { sl@0: TBool is_timer = iFlags & EFlag_Timer; sl@0: if (!a) sl@0: a = iDfc; sl@0: TUint64 time = fast_counter(); sl@0: TBool ok; sl@0: if (is_timer) sl@0: ok = ((NTimer*)a)->Again(2) == KErrNone; sl@0: else sl@0: ok = ((TDfc*)a)->Enque(); sl@0: if (ok) sl@0: { sl@0: iTimeQueued = time; sl@0: __e32_atomic_add_ord32(&iQueueCount, 1); sl@0: } sl@0: return ok; sl@0: } sl@0: sl@0: TBool TDfcX::QueueOnIdle(TAny* a) sl@0: { sl@0: TBool is_timer = iFlags & EFlag_Timer; sl@0: if (is_timer) sl@0: return FALSE; sl@0: if (!a) sl@0: a = iDfc; sl@0: TUint64 time = fast_counter(); sl@0: TBool ok = ((TDfc*)a)->QueueOnIdle(); sl@0: if (ok) sl@0: { sl@0: iTimeQueued = time; sl@0: __e32_atomic_add_ord32(&iQueueCount, 1); sl@0: } sl@0: return ok; sl@0: } sl@0: sl@0: TBool TDfcX::SafeAdd() sl@0: { sl@0: TBool ret = FALSE; sl@0: TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc); sl@0: if (x && !(x&1)) sl@0: { sl@0: TDfc* p = (TDfc*)x; sl@0: ret = Add(p); sl@0: flip_bit0((TUint32&)iDfc); sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: TBool TDfcX::SafeEnque() sl@0: { sl@0: TBool ret = FALSE; sl@0: TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc); sl@0: if (x && !(x&1)) sl@0: { sl@0: TDfc* p = (TDfc*)x; sl@0: ret = Enque(p); sl@0: flip_bit0((TUint32&)iDfc); sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: TBool TDfcX::SafeQueueOnIdle() sl@0: { sl@0: TBool ret = FALSE; sl@0: TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc); sl@0: if (x && !(x&1)) sl@0: { sl@0: TDfc* p = (TDfc*)x; sl@0: ret = QueueOnIdle(p); sl@0: flip_bit0((TUint32&)iDfc); sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: TBool TDfcX::SafeCancel() sl@0: { sl@0: TBool ret = FALSE; sl@0: TUint32 x = swap_out_if_bit0_clear((TUint32&)iDfc); sl@0: if (x && !(x&1)) sl@0: { sl@0: if (iFlags & EFlag_Timer) sl@0: { sl@0: NTimer* p = (NTimer*)x; sl@0: ret = Cancel(p); sl@0: p->~NTimer(); sl@0: memset(p, 0xbb, sizeof(NTimer)); sl@0: free(p); sl@0: } sl@0: else sl@0: { sl@0: TDfc* p = (TDfc*)x; sl@0: ret = Cancel(p); sl@0: p->~TDfc(); sl@0: memset(p, 0xbb, sizeof(TDfc)); sl@0: free(p); sl@0: } sl@0: CreateDfcOrTimer(); sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: void TDfcX::GetDesc(char* a) sl@0: { sl@0: memset(a, 0x20, 8); sl@0: if (iFlags & EFlag_Timer) sl@0: *a++ = 'T'; sl@0: if (iFlags & EFlag_IDFC) sl@0: *a++ = 'I'; sl@0: if (iFlags & EFlag_DFC) sl@0: *a++ = 'D'; sl@0: if (iFlags & EFlag_IdleDFC) sl@0: *a++ = 'i'; sl@0: if (iFlags & EFlag_Tied) sl@0: *a++ = 't'; sl@0: } sl@0: sl@0: TDfcStress::TDfcStress() sl@0: { sl@0: memclr(this, sizeof(*this)); sl@0: } sl@0: sl@0: TDfcX* TDfcStress::NewDfc(TUint32 aId, TUint32 aFlags, TInt aDfcQ) sl@0: { sl@0: TDfcX* d = new TDfcX; sl@0: TEST_OOM(d); sl@0: d->iId = aId; sl@0: d->iFlags = aFlags; sl@0: d->iS = this; sl@0: sl@0: d->iDfcQ = iDfcQ[aDfcQ]; sl@0: d->CreateDfcOrTimer(); sl@0: return d; sl@0: } sl@0: sl@0: TDfcX* TDfcStress::NewIDfc(TUint32 aId, TUint32 aFlags, NSchedulable* aTied) sl@0: { sl@0: TDfcX* d = new TDfcX; sl@0: TEST_OOM(d); sl@0: d->iId = aId; sl@0: d->iFlags = aFlags; sl@0: d->iS = this; sl@0: sl@0: d->iXTied = aTied; sl@0: d->CreateDfcOrTimer(); sl@0: return d; sl@0: } sl@0: sl@0: TDfcX* TDfcStress::NewTimer(TUint32 aId, TUint32 aFlags, TInt aDfcQ, NSchedulable* aTied) sl@0: { sl@0: TDfcX* d = new TDfcX; sl@0: TEST_OOM(d); sl@0: d->iId = aId; sl@0: d->iFlags = aFlags; sl@0: d->iS = this; sl@0: sl@0: d->iDfcQ = (aFlags & TDfcX::EFlag_DFC) ? iDfcQ[aDfcQ] : 0; sl@0: d->iXTied = (aFlags & TDfcX::EFlag_Tied) ? aTied : 0; sl@0: d->CreateDfcOrTimer(); sl@0: return d; sl@0: } sl@0: sl@0: sl@0: void TDfcX::CreateDfcOrTimer() sl@0: { sl@0: // volatile TUint32* xc = 0; sl@0: NThreadBase* t = iS->iDfcQ[0]->iThread; sl@0: volatile TUint32* xc = &t->iRunCount32[1]; // HACK! sl@0: if (!(iFlags & EFlag_Timer)) sl@0: { sl@0: TDfc* d = 0; sl@0: if (!(iFlags & EFlag_IDFC)) sl@0: { sl@0: d = new TDfc(&TDfcX::DfcFn, this, iDfcQ, 1); sl@0: xc = (volatile TUint32*)&iDfcQ->iThread->iRunCount32[1]; sl@0: } sl@0: else if (iFlags & EFlag_Tied) sl@0: { sl@0: d = new TDfc(iXTied, &TDfcX::IDfcFn, this); sl@0: xc = (volatile TUint32*)&iXTied->iRunCount32[1]; sl@0: } sl@0: else sl@0: d = new TDfc(&TDfcX::IDfcFn, this); sl@0: __NK_ASSERT_ALWAYS(d!=0); sl@0: __e32_atomic_store_rel_ptr(&iDfc, d); sl@0: } sl@0: else sl@0: { sl@0: NTimer* tmr = 0; sl@0: if (iFlags & EFlag_DFC) sl@0: { sl@0: tmr = new NTimer(&TDfcX::TimerDfcFn, this, iDfcQ, 1); sl@0: xc = (volatile TUint32*)&iDfcQ->iThread->iRunCount32[1]; sl@0: } sl@0: else if (iFlags & EFlag_Tied) sl@0: { sl@0: tmr = new NTimer(iXTied, &TDfcX::TimerIsrFn, this); sl@0: xc = (volatile TUint32*)&iXTied->iRunCount32[1]; sl@0: } sl@0: else sl@0: tmr = new NTimer(&TDfcX::TimerIsrFn, this); sl@0: __NK_ASSERT_ALWAYS(tmr!=0); sl@0: __e32_atomic_store_rel_ptr(&iTimer, tmr); sl@0: } sl@0: iExclusionCheck = xc; sl@0: } sl@0: sl@0: TDfcStress* TDfcStress::New(TInt aNumDfc, TInt aNumDfcQ, TBool aTimerTest) sl@0: { sl@0: TDfcStress* p = new TDfcStress; sl@0: TEST_OOM(p); sl@0: p->iTimerTest = aTimerTest; sl@0: p->iNumDfc = aNumDfc; sl@0: p->iNumDfcQ = aNumDfcQ; sl@0: p->Create(); sl@0: return p; sl@0: } sl@0: sl@0: void TDfcStress::Create() sl@0: { sl@0: DEBUGPRINT("TDfcStress @ %08x", this); sl@0: TInt i; sl@0: TInt num_cpus = NKern::NumberOfCpus(); sl@0: TInt cpu = 0; sl@0: iExitSem = new NFastSemaphore(0); sl@0: TEST_OOM(iExitSem); sl@0: for (i=0; iiThread; sl@0: DEBUGPRINT("DfcQ %2d @ %08x Thread @%08x Stack %08x+%08x", i, iDfcQ[i], t, t->iStackBase, t->iStackSize); sl@0: } sl@0: iBackStopIdleDfcQ = CreateDfcQ("BackStop", 1, 0); sl@0: TEST_OOM(iBackStopIdleDfcQ); sl@0: iBackStopIdleDfc = new TDfc(&BackStopFn, this, iBackStopIdleDfcQ, 1); sl@0: TEST_OOM(iBackStopIdleDfc); sl@0: for (i=0; iiStackBase, t->iStackSize); sl@0: } sl@0: for (i=0; iiDfc); sl@0: } sl@0: } sl@0: sl@0: void TDfcStress::CreateDfc(TUint32 aId) sl@0: { sl@0: TUint32 type = aId & 7; sl@0: TUint32 q = aId % iNumDfcQ; sl@0: TDfcX* d = 0; sl@0: switch (type) sl@0: { sl@0: case 0: sl@0: case 1: sl@0: case 2: sl@0: case 3: sl@0: if (iTimerTest) sl@0: d = NewTimer(aId, TDfcX::EFlag_Timer|TDfcX::EFlag_DFC, q, 0); sl@0: else sl@0: d = NewDfc(aId, TDfcX::EFlag_DFC, q); sl@0: break; sl@0: case 4: sl@0: case 5: sl@0: if (iTimerTest) sl@0: d = NewTimer(aId, TDfcX::EFlag_Timer|TDfcX::EFlag_Tied, 0, iDfcQ[iNumDfcQ-1-(type&1)]->iThread); sl@0: else sl@0: { sl@0: if (aId>=16 && aId<32 && iNumDfcQ>2) sl@0: d = NewIDfc(aId, TDfcX::EFlag_IDFC|TDfcX::EFlag_Tied, iDfcQ[2]->iThread); sl@0: else sl@0: d = NewIDfc(aId, TDfcX::EFlag_IDFC); sl@0: } sl@0: break; sl@0: case 6: sl@0: case 7: sl@0: if (iTimerTest) sl@0: d = NewTimer(aId, TDfcX::EFlag_Timer, 0, 0); sl@0: else sl@0: d = NewDfc(aId, TDfcX::EFlag_DFC|TDfcX::EFlag_IdleDFC, q); sl@0: break; sl@0: }; sl@0: __e32_atomic_store_rel_ptr(&iDfcX[aId], d); sl@0: } sl@0: sl@0: void TDfcStress::Close() sl@0: { sl@0: TInt i; sl@0: sl@0: // delete DFCs before the DFC queues they might be on sl@0: for (i=0; iThreadFn(); sl@0: } sl@0: sl@0: void append(char*& a, const char* s) sl@0: { sl@0: while(*s) sl@0: *a++ = *s++; sl@0: *a=0; sl@0: } sl@0: sl@0: void TDfcStress::GetModeText(char* a) sl@0: { sl@0: memclr(a,128); sl@0: if (iMode==0) sl@0: { sl@0: append(a, "Add only"); sl@0: return; sl@0: } sl@0: if (iMode & EMode_Wait) sl@0: append(a, "Wait "); sl@0: if (iMode & EMode_AllowCancel) sl@0: append(a, "Cancel "); sl@0: if (iMode & EMode_AllowIdle) sl@0: append(a, "Idle "); sl@0: if (iMode & EMode_AllowEnque) sl@0: append(a, "Enque "); sl@0: if (iMode & EMode_Recycle) sl@0: append(a, "Recycle "); sl@0: if (iMode & EMode_Migrate) sl@0: append(a, "Migrate "); sl@0: if (iMode & EMode_SelfMigrate) sl@0: append(a, "SelfMigrate "); sl@0: } sl@0: sl@0: /* sl@0: Test Mode: sl@0: sl@0: Bit 31 If set causes thread to exit sl@0: Bit 0 If set does random wait after each operation sl@0: Bit 1 Allows Cancel operations if set sl@0: Bit 2 Allows idle operations if set sl@0: Bit 3 Test Enque() as well as Add() sl@0: Bit 4 Use SafeXXX operations sl@0: Bit 5 Use tied IDFCs sl@0: Bit 6 Migrate threads with things tied to them sl@0: Bit 7 Threads with things tied to them migrate themselves during execution sl@0: sl@0: */ sl@0: void TDfcStress::ThreadFn() sl@0: { sl@0: TBool finish = FALSE; sl@0: TUint32 seed[2]; sl@0: seed[0] = NKern::CurrentCpu() ^ 0xddb3d743; sl@0: seed[1] = 0; sl@0: FOREVER sl@0: { sl@0: if (iStop) sl@0: { sl@0: __e32_atomic_add_ord32(&iRunning, (TUint32)(-1)); sl@0: while (iStop) sl@0: { sl@0: if (iMode<0) sl@0: { sl@0: finish = TRUE; sl@0: break; sl@0: } sl@0: } sl@0: if (finish) sl@0: break; sl@0: else sl@0: __e32_atomic_add_ord32(&iRunning, 1); sl@0: } sl@0: if (iMode & EMode_Wait) sl@0: { sl@0: TUint32 wait = random(seed); sl@0: wait %= iRandomTimeLimit; sl@0: wait += 1; sl@0: fcfspin(wait); sl@0: } sl@0: TUint32 action = random(seed); sl@0: TUint32 action2 = random(seed); sl@0: if (action & 0xff000000) sl@0: { sl@0: // queue or cancel a DFC or timer sl@0: TBool cancel = action2 & 2; sl@0: TUint32 id = action % iNumDfc; sl@0: TDfcX* d = iDfcX[id]; sl@0: if (iMode & EMode_Recycle) sl@0: { sl@0: TBool isIDFC = d->IsIDFC(); sl@0: TBool isIdler = d->IsIdler(); sl@0: if (cancel) sl@0: d->SafeCancel(); sl@0: else if (isIdler) sl@0: d->SafeQueueOnIdle(); sl@0: else if ((iMode & EMode_AllowEnque) && (action2 & 1) && !isIDFC) sl@0: d->SafeEnque(); sl@0: else sl@0: { sl@0: NKern::Lock(); sl@0: d->SafeAdd(); sl@0: NKern::Unlock(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (cancel && (iMode & EMode_AllowCancel)) sl@0: { sl@0: d->Cancel(); sl@0: } sl@0: else if (!d->IsIdler()) sl@0: { sl@0: if ((iMode & EMode_AllowEnque) && (action2 & 1) && !d->IsIDFC()) sl@0: { sl@0: d->Enque(); sl@0: } sl@0: else sl@0: { sl@0: NKern::Lock(); sl@0: d->Add(); sl@0: NKern::Unlock(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: d->QueueOnIdle(); sl@0: } sl@0: } sl@0: continue; sl@0: } sl@0: if (iMode & EMode_AllowIdle) sl@0: { sl@0: iBackStopIdleDfc->QueueOnIdle(); sl@0: NKern::WaitForAnyRequest(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void StopTimeout(TAny*) sl@0: { sl@0: __crash(); sl@0: } sl@0: sl@0: void TDfcStress::DoTestPhase(TInt aMode, TInt aTime, TInt aCount) sl@0: { sl@0: char mode_text[128]; sl@0: TInt i; sl@0: TUint32 maxavg = 0; sl@0: TInt n; sl@0: iMode = aMode; sl@0: iStop = FALSE; sl@0: GetModeText(mode_text); sl@0: TEST_PRINT1("Testing with: %s", mode_text); sl@0: for (i=0; iCancel(); sl@0: timer.Cancel(); sl@0: TEST_PRINT("Threads stopped"); sl@0: for (i=0; iiThread->iEventState; sl@0: DEBUGPRINT("DfcThread %d EventState = %08x", i, ev); sl@0: TEST_RESULT(!(ev & NSchedulable::EEventCountMask), ""); sl@0: } sl@0: for (i=0; iiEventState; sl@0: DEBUGPRINT("Thread %d EventState = %08x", i, ev); sl@0: TEST_RESULT(!(ev & NSchedulable::EEventCountMask), ""); sl@0: } sl@0: NKern::Sleep(10); sl@0: for (i=0; iCancel(); sl@0: TUint32 qc = d->iQueueCount; sl@0: TUint32* rc = d->iRunCount; sl@0: TUint32 totrc = rc[0] + rc[1] + rc[2] + rc[3] + rc[4] + rc[5] + rc[6] + rc[7]; sl@0: TUint32 cc = d->iCancelCount; sl@0: TUint32 f = d->iFlags; sl@0: // TUint32 imm = d->IsIDFC()?1:0; sl@0: TUint32 max = d->iMaxTime; sl@0: TUint32 avg = 0; sl@0: TUint32 xfc = d->iExclusionFailCount; sl@0: if (totrc) sl@0: avg = TUint32(d->iSumTime / TUint64(totrc)); sl@0: if (avg > maxavg) sl@0: maxavg = avg; sl@0: char desc[16]; sl@0: memclr(desc,16); sl@0: d->GetDesc(desc); sl@0: DEBUGPRINT("%2d: %s QC %9d RC %9d CC %9d MAX %9d AVG %9d XFC %9d RC %9d %9d %9d %9d %9d %9d %9d %9d", i, desc, qc, totrc, cc, max, avg, xfc, rc[0], rc[1], rc[2], rc[3], rc[4], rc[5], rc[6], rc[7]); sl@0: TInt diff = (TInt)(qc - (totrc+cc)); sl@0: TEST_RESULT1(diff==0, "Counts mismatched, diff=%d", diff); sl@0: TEST_RESULT(!(f&TDfcX::EFlag_Tied) || xfc==0, "Exclusion Failure!"); sl@0: d->iQueueCount = 0; sl@0: memclr(d->iRunCount, sizeof(d->iRunCount)); sl@0: d->iCancelCount = 0; sl@0: d->iMaxTime = 0; sl@0: d->iSumTime = 0; sl@0: } sl@0: if (!iRandomTimeLimit) sl@0: iRandomTimeLimit = maxavg + (maxavg>>1); sl@0: } sl@0: sl@0: void TDfcStress::Run() sl@0: { sl@0: TInt i; sl@0: NThread* t; sl@0: iStop = FALSE; sl@0: iMode = 0; sl@0: TInt num_cpus = NKern::NumberOfCpus(); sl@0: iRunning = num_cpus; sl@0: for (i=0; iRun(); sl@0: ds->Close(); sl@0: } sl@0: sl@0: #endif sl@0: sl@0: void TestDFCs() sl@0: { sl@0: TEST_PRINT("Testing DFCs..."); sl@0: sl@0: TTestDfc::Buffer = CircBuf::New(TTestDfc::EBufferSlots); sl@0: TInt cpu; sl@0: (void)cpu; sl@0: #ifdef __SMP__ sl@0: DoStressTest(TRUE); sl@0: #endif sl@0: sl@0: DoDFCTest1(); sl@0: DoDFCTest2(); sl@0: for_each_cpu(cpu) sl@0: { sl@0: DoDFCTest3(cpu); sl@0: } sl@0: DoIDFCTest1(); sl@0: for_each_cpu(cpu) sl@0: { sl@0: DoIdleDFCTest1(cpu); sl@0: } sl@0: DoIdleDFCTest2(); sl@0: sl@0: #ifdef __SMP__ sl@0: DoStressTest(FALSE); sl@0: #endif sl@0: sl@0: delete TTestDfc::Buffer; sl@0: TTestDfc::Buffer = 0; sl@0: }