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