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 |
}
|