kerneltest/e32test/nkernsa/tiedevents.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\nkernsa\tiedevents.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <nktest/nkutils.h>
       
    19 
       
    20 //---------------------------------------------------------------------------------------------------------------------
       
    21 //! @SYMTestCaseID				KBASE-tiedevents-2448
       
    22 //! @SYMTestType				UT
       
    23 //! @SYMTestCaseDesc			Verifying tied events
       
    24 //! @SYMPREQ					PREQ2094
       
    25 //! @SYMTestPriority			High
       
    26 //! @SYMTestActions				
       
    27 //! 	1. 	TiedEventTest: run a reader thread (or several in a group) accessing a
       
    28 //! 		common data block. A timer, IDFC, or interrupt handler writes to the
       
    29 //!			data block concurrently - first incrementing all data from 0 to 1 then
       
    30 //!			decrementing it again.
       
    31 //! 		
       
    32 //! @SYMTestExpectedResults
       
    33 //! 	1.	When the timer/IDFC/interrupt is tied to the thread/group, then the
       
    34 //!			execution of the event should prevent the thread/group from running on
       
    35 //!			any processor, and thus readers should never be able to observe the
       
    36 //!			data being 1. When the event is not tied, the reader should observe
       
    37 //!			the data as being 1 at least some of the time.
       
    38 //---------------------------------------------------------------------------------------------------------------------
       
    39 
       
    40 #ifdef __SMP__
       
    41 
       
    42 extern "C" void HijackSystemTimer(NSchedulable* aTieTo);
       
    43 
       
    44 const TInt FlagCount = 2048;
       
    45 const TInt LoopCount = 100;
       
    46 
       
    47 volatile TUint32 Flags[FlagCount];
       
    48 volatile TBool Done;
       
    49 volatile TUint32 FlagsSet;
       
    50 NTimer* Timer;
       
    51 TDfc* IDfc;
       
    52 NThreadGroup TG;
       
    53 NFastSemaphore* DoneSem;
       
    54 
       
    55 enum TTiedMode
       
    56 	{
       
    57 	ETimer,
       
    58 	EInterrupt,
       
    59 	EIDFC
       
    60 	};
       
    61 
       
    62 // Used directly as the IDFC, also called by the timer function
       
    63 void FiddleFlags(TAny*)
       
    64 	{
       
    65 	TInt i;
       
    66 	for (i=0; i<FlagCount; ++i)
       
    67 		__e32_atomic_add_ord32(&Flags[i], 1);
       
    68 	for (i=0; i<FlagCount; ++i)
       
    69 		__e32_atomic_add_ord32(&Flags[i], (TUint32)-1);
       
    70 	}
       
    71 
       
    72 // Used for timer/interrupt cases as the timer function
       
    73 void TimerFn(TAny*)
       
    74 	{
       
    75 	FiddleFlags(NULL);
       
    76 	if (!__e32_atomic_load_acq32(&Done))
       
    77 		Timer->OneShot(10);
       
    78 	}
       
    79 
       
    80 // Used for IDFC case as the timer function
       
    81 void IDfcQFn(TAny*)
       
    82 	{
       
    83 	IDfc->Add();
       
    84 	if (!__e32_atomic_load_acq32(&Done))
       
    85 		Timer->OneShot(10);
       
    86 	}
       
    87 
       
    88 // Test thread, just looks for flags being set
       
    89 void TiedEventThread(TAny*)
       
    90 	{
       
    91 	TInt cpu, i, j;
       
    92 	TUint32 set=0;
       
    93 
       
    94 	for_each_cpu(cpu)
       
    95 		{
       
    96 		NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), cpu);
       
    97 
       
    98 		for (i=0; i<LoopCount; ++i)
       
    99 			{
       
   100 			for (j=0; j<FlagCount; ++j)
       
   101 				if (__e32_atomic_load_acq32(&Flags[j]))
       
   102 					++set;
       
   103 			}
       
   104 		}
       
   105 
       
   106 	__e32_atomic_add_ord32(&FlagsSet, set);
       
   107 
       
   108 	NKern::FSSignal(DoneSem);
       
   109 	NKern::WaitForAnyRequest();
       
   110 	}
       
   111 
       
   112 void TiedEventTest(TBool aTied, TInt aThreads, TTiedMode aMode)
       
   113 	{
       
   114 	TEST_PRINT3("TiedEventTest aTied=%d aThreads=%d aMode=%d", aTied, aThreads, aMode);
       
   115 
       
   116 	// Set up shared parameters
       
   117 	memclr((void*)&Flags,sizeof(Flags));
       
   118 	Done = EFalse;
       
   119 	FlagsSet = 0;
       
   120 
       
   121 	// Create test threads to check data
       
   122 	NFastSemaphore exitSem(0);
       
   123 	NFastSemaphore doneSem(0);
       
   124 	DoneSem = &doneSem;
       
   125 	char name[5]={0x54, 0x45, 0x54, 0x31, 0};
       
   126 	TInt i;
       
   127 	NSchedulable* tieTo = NULL;
       
   128 	NThread* t[16];
       
   129 	NThreadGroup* group = NULL;
       
   130 	if (aThreads == 1)
       
   131 		{
       
   132 		t[0] = CreateUnresumedThreadSignalOnExit(name, TiedEventThread, 10, NULL, 0, KSmallTimeslice, &exitSem, KCpuAffinityAny);
       
   133 		if (aTied)
       
   134 			tieTo = t[0];
       
   135 		}
       
   136 	else
       
   137 		{
       
   138 		group = &TG;
       
   139 		if (aTied)
       
   140 			tieTo = group;
       
   141 		SNThreadGroupCreateInfo ginfo;
       
   142 		ginfo.iCpuAffinity = KCpuAffinityAny;
       
   143 		TInt r = NKern::GroupCreate(group, ginfo);
       
   144 		TEST_RESULT(r==KErrNone, "Failed creating group");
       
   145 		for (i=0; i<aThreads; ++i)
       
   146 			{
       
   147 			t[i] = CreateUnresumedThreadSignalOnExit(name, TiedEventThread, 10, NULL, 0, KSmallTimeslice, &exitSem, KCpuAffinityAny, group);
       
   148 			++name[3];
       
   149 			}
       
   150 		}
       
   151 
       
   152 #ifndef __X86__
       
   153 	// Tie the system timer interrupt to the thread if we're testing interrupts
       
   154 	// This means the timer function should always be exclusive with the theads
       
   155 	// even though it's not tied itself.
       
   156 	if (aMode == EInterrupt && tieTo)
       
   157 		HijackSystemTimer(tieTo);
       
   158 #endif
       
   159 
       
   160 	// Create the IDFC
       
   161 	NSchedulable* tieDFC = aMode == EIDFC ? tieTo : NULL;
       
   162 	TDfc idfc(tieDFC, FiddleFlags, NULL);
       
   163 	IDfc = &idfc;
       
   164 
       
   165 	// Create and start NTimer
       
   166 	// If we're testing timers it will be tied itself
       
   167 	// If we're testing interrupts it will not be tied itself but will still run
       
   168 	// exclusively because the interrupt is tied
       
   169 	// If we're testing IDFCs it's just used to repeatedly queue the IDFC and
       
   170 	// where the timer itself runs is irrelevant.
       
   171 	NSchedulable* tieTimer = aMode == ETimer ? tieTo : NULL;
       
   172 	NTimerFn timerfn = aMode == EIDFC ? IDfcQFn : TimerFn;
       
   173 	NTimer timer(tieTimer, timerfn, NULL);
       
   174 	Timer = &timer;
       
   175 	timer.OneShot(10);
       
   176 
       
   177 	// Resume threads
       
   178 	for (i=0; i<aThreads; ++i)
       
   179 		NKern::ThreadResume(t[i]);
       
   180 
       
   181 	// Wait for threads to be done
       
   182 	for (i=0; i<aThreads; ++i)
       
   183 		NKern::FSWait(&doneSem);
       
   184 
       
   185 	// Tell timer to stop requeueing itself
       
   186 	__e32_atomic_store_rel32(&Done, ETrue);
       
   187 	NKern::Sleep(100);
       
   188 
       
   189 #ifndef __X86__
       
   190 	// Restart the normal system timer if we're testing interrupts
       
   191 	// as otherwise it will get unbound when the thing it's tied to
       
   192 	// dies.
       
   193 	if (aMode == EInterrupt && tieTo)
       
   194 		HijackSystemTimer(NULL);
       
   195 #endif
       
   196 
       
   197 	// Clean up threads/group
       
   198 	for (i=0; i<aThreads; ++i)
       
   199 		{
       
   200 		NKern::ThreadRequestSignal(t[i]);
       
   201 		NKern::FSWait(&exitSem);
       
   202 		}
       
   203 	if (group)
       
   204 		NKern::GroupDestroy(group);
       
   205 
       
   206 	// Check that the flag was ok
       
   207 	TEST_PRINT1("Flag was set %d times", FlagsSet);
       
   208 	if (aTied)
       
   209 		TEST_RESULT(FlagsSet == 0, "Flag was set, shouldn't be");
       
   210 	else
       
   211 		TEST_RESULT(FlagsSet > 0, "Flag wasn't set, test broken?");
       
   212 	}
       
   213 #endif
       
   214 
       
   215 void TestTiedEvents()
       
   216 	{
       
   217 #ifdef __SMP__
       
   218 	TiedEventTest(EFalse, 1, ETimer);
       
   219 	TiedEventTest(ETrue, 1, ETimer);
       
   220 	TiedEventTest(EFalse, 2, ETimer);
       
   221 	TiedEventTest(ETrue, 2, ETimer);
       
   222 
       
   223 #ifndef __X86__
       
   224 	TiedEventTest(EFalse, 1, EInterrupt);
       
   225 	TiedEventTest(ETrue, 1, EInterrupt);
       
   226 	TiedEventTest(EFalse, 2, EInterrupt);
       
   227 	TiedEventTest(ETrue, 2, EInterrupt);
       
   228 #endif
       
   229 
       
   230 	TiedEventTest(EFalse, 1, EIDFC);
       
   231 	TiedEventTest(ETrue, 1, EIDFC);
       
   232 	TiedEventTest(EFalse, 2, EIDFC);
       
   233 	TiedEventTest(ETrue, 2, EIDFC);
       
   234 #endif
       
   235 	}