1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/nkernsa/tiedevents.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,235 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\nkernsa\tiedevents.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <nktest/nkutils.h>
1.22 +
1.23 +//---------------------------------------------------------------------------------------------------------------------
1.24 +//! @SYMTestCaseID KBASE-tiedevents-2448
1.25 +//! @SYMTestType UT
1.26 +//! @SYMTestCaseDesc Verifying tied events
1.27 +//! @SYMPREQ PREQ2094
1.28 +//! @SYMTestPriority High
1.29 +//! @SYMTestActions
1.30 +//! 1. TiedEventTest: run a reader thread (or several in a group) accessing a
1.31 +//! common data block. A timer, IDFC, or interrupt handler writes to the
1.32 +//! data block concurrently - first incrementing all data from 0 to 1 then
1.33 +//! decrementing it again.
1.34 +//!
1.35 +//! @SYMTestExpectedResults
1.36 +//! 1. When the timer/IDFC/interrupt is tied to the thread/group, then the
1.37 +//! execution of the event should prevent the thread/group from running on
1.38 +//! any processor, and thus readers should never be able to observe the
1.39 +//! data being 1. When the event is not tied, the reader should observe
1.40 +//! the data as being 1 at least some of the time.
1.41 +//---------------------------------------------------------------------------------------------------------------------
1.42 +
1.43 +#ifdef __SMP__
1.44 +
1.45 +extern "C" void HijackSystemTimer(NSchedulable* aTieTo);
1.46 +
1.47 +const TInt FlagCount = 2048;
1.48 +const TInt LoopCount = 100;
1.49 +
1.50 +volatile TUint32 Flags[FlagCount];
1.51 +volatile TBool Done;
1.52 +volatile TUint32 FlagsSet;
1.53 +NTimer* Timer;
1.54 +TDfc* IDfc;
1.55 +NThreadGroup TG;
1.56 +NFastSemaphore* DoneSem;
1.57 +
1.58 +enum TTiedMode
1.59 + {
1.60 + ETimer,
1.61 + EInterrupt,
1.62 + EIDFC
1.63 + };
1.64 +
1.65 +// Used directly as the IDFC, also called by the timer function
1.66 +void FiddleFlags(TAny*)
1.67 + {
1.68 + TInt i;
1.69 + for (i=0; i<FlagCount; ++i)
1.70 + __e32_atomic_add_ord32(&Flags[i], 1);
1.71 + for (i=0; i<FlagCount; ++i)
1.72 + __e32_atomic_add_ord32(&Flags[i], (TUint32)-1);
1.73 + }
1.74 +
1.75 +// Used for timer/interrupt cases as the timer function
1.76 +void TimerFn(TAny*)
1.77 + {
1.78 + FiddleFlags(NULL);
1.79 + if (!__e32_atomic_load_acq32(&Done))
1.80 + Timer->OneShot(10);
1.81 + }
1.82 +
1.83 +// Used for IDFC case as the timer function
1.84 +void IDfcQFn(TAny*)
1.85 + {
1.86 + IDfc->Add();
1.87 + if (!__e32_atomic_load_acq32(&Done))
1.88 + Timer->OneShot(10);
1.89 + }
1.90 +
1.91 +// Test thread, just looks for flags being set
1.92 +void TiedEventThread(TAny*)
1.93 + {
1.94 + TInt cpu, i, j;
1.95 + TUint32 set=0;
1.96 +
1.97 + for_each_cpu(cpu)
1.98 + {
1.99 + NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), cpu);
1.100 +
1.101 + for (i=0; i<LoopCount; ++i)
1.102 + {
1.103 + for (j=0; j<FlagCount; ++j)
1.104 + if (__e32_atomic_load_acq32(&Flags[j]))
1.105 + ++set;
1.106 + }
1.107 + }
1.108 +
1.109 + __e32_atomic_add_ord32(&FlagsSet, set);
1.110 +
1.111 + NKern::FSSignal(DoneSem);
1.112 + NKern::WaitForAnyRequest();
1.113 + }
1.114 +
1.115 +void TiedEventTest(TBool aTied, TInt aThreads, TTiedMode aMode)
1.116 + {
1.117 + TEST_PRINT3("TiedEventTest aTied=%d aThreads=%d aMode=%d", aTied, aThreads, aMode);
1.118 +
1.119 + // Set up shared parameters
1.120 + memclr((void*)&Flags,sizeof(Flags));
1.121 + Done = EFalse;
1.122 + FlagsSet = 0;
1.123 +
1.124 + // Create test threads to check data
1.125 + NFastSemaphore exitSem(0);
1.126 + NFastSemaphore doneSem(0);
1.127 + DoneSem = &doneSem;
1.128 + char name[5]={0x54, 0x45, 0x54, 0x31, 0};
1.129 + TInt i;
1.130 + NSchedulable* tieTo = NULL;
1.131 + NThread* t[16];
1.132 + NThreadGroup* group = NULL;
1.133 + if (aThreads == 1)
1.134 + {
1.135 + t[0] = CreateUnresumedThreadSignalOnExit(name, TiedEventThread, 10, NULL, 0, KSmallTimeslice, &exitSem, KCpuAffinityAny);
1.136 + if (aTied)
1.137 + tieTo = t[0];
1.138 + }
1.139 + else
1.140 + {
1.141 + group = &TG;
1.142 + if (aTied)
1.143 + tieTo = group;
1.144 + SNThreadGroupCreateInfo ginfo;
1.145 + ginfo.iCpuAffinity = KCpuAffinityAny;
1.146 + TInt r = NKern::GroupCreate(group, ginfo);
1.147 + TEST_RESULT(r==KErrNone, "Failed creating group");
1.148 + for (i=0; i<aThreads; ++i)
1.149 + {
1.150 + t[i] = CreateUnresumedThreadSignalOnExit(name, TiedEventThread, 10, NULL, 0, KSmallTimeslice, &exitSem, KCpuAffinityAny, group);
1.151 + ++name[3];
1.152 + }
1.153 + }
1.154 +
1.155 +#ifndef __X86__
1.156 + // Tie the system timer interrupt to the thread if we're testing interrupts
1.157 + // This means the timer function should always be exclusive with the theads
1.158 + // even though it's not tied itself.
1.159 + if (aMode == EInterrupt && tieTo)
1.160 + HijackSystemTimer(tieTo);
1.161 +#endif
1.162 +
1.163 + // Create the IDFC
1.164 + NSchedulable* tieDFC = aMode == EIDFC ? tieTo : NULL;
1.165 + TDfc idfc(tieDFC, FiddleFlags, NULL);
1.166 + IDfc = &idfc;
1.167 +
1.168 + // Create and start NTimer
1.169 + // If we're testing timers it will be tied itself
1.170 + // If we're testing interrupts it will not be tied itself but will still run
1.171 + // exclusively because the interrupt is tied
1.172 + // If we're testing IDFCs it's just used to repeatedly queue the IDFC and
1.173 + // where the timer itself runs is irrelevant.
1.174 + NSchedulable* tieTimer = aMode == ETimer ? tieTo : NULL;
1.175 + NTimerFn timerfn = aMode == EIDFC ? IDfcQFn : TimerFn;
1.176 + NTimer timer(tieTimer, timerfn, NULL);
1.177 + Timer = &timer;
1.178 + timer.OneShot(10);
1.179 +
1.180 + // Resume threads
1.181 + for (i=0; i<aThreads; ++i)
1.182 + NKern::ThreadResume(t[i]);
1.183 +
1.184 + // Wait for threads to be done
1.185 + for (i=0; i<aThreads; ++i)
1.186 + NKern::FSWait(&doneSem);
1.187 +
1.188 + // Tell timer to stop requeueing itself
1.189 + __e32_atomic_store_rel32(&Done, ETrue);
1.190 + NKern::Sleep(100);
1.191 +
1.192 +#ifndef __X86__
1.193 + // Restart the normal system timer if we're testing interrupts
1.194 + // as otherwise it will get unbound when the thing it's tied to
1.195 + // dies.
1.196 + if (aMode == EInterrupt && tieTo)
1.197 + HijackSystemTimer(NULL);
1.198 +#endif
1.199 +
1.200 + // Clean up threads/group
1.201 + for (i=0; i<aThreads; ++i)
1.202 + {
1.203 + NKern::ThreadRequestSignal(t[i]);
1.204 + NKern::FSWait(&exitSem);
1.205 + }
1.206 + if (group)
1.207 + NKern::GroupDestroy(group);
1.208 +
1.209 + // Check that the flag was ok
1.210 + TEST_PRINT1("Flag was set %d times", FlagsSet);
1.211 + if (aTied)
1.212 + TEST_RESULT(FlagsSet == 0, "Flag was set, shouldn't be");
1.213 + else
1.214 + TEST_RESULT(FlagsSet > 0, "Flag wasn't set, test broken?");
1.215 + }
1.216 +#endif
1.217 +
1.218 +void TestTiedEvents()
1.219 + {
1.220 +#ifdef __SMP__
1.221 + TiedEventTest(EFalse, 1, ETimer);
1.222 + TiedEventTest(ETrue, 1, ETimer);
1.223 + TiedEventTest(EFalse, 2, ETimer);
1.224 + TiedEventTest(ETrue, 2, ETimer);
1.225 +
1.226 +#ifndef __X86__
1.227 + TiedEventTest(EFalse, 1, EInterrupt);
1.228 + TiedEventTest(ETrue, 1, EInterrupt);
1.229 + TiedEventTest(EFalse, 2, EInterrupt);
1.230 + TiedEventTest(ETrue, 2, EInterrupt);
1.231 +#endif
1.232 +
1.233 + TiedEventTest(EFalse, 1, EIDFC);
1.234 + TiedEventTest(ETrue, 1, EIDFC);
1.235 + TiedEventTest(EFalse, 2, EIDFC);
1.236 + TiedEventTest(ETrue, 2, EIDFC);
1.237 +#endif
1.238 + }