os/kernelhwsrv/kerneltest/e32test/nkernsa/tiedevents.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}