|
1 // Copyright (c) 2005-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\emi\d_emitest.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <kernel/kern_priv.h> |
|
19 #include "d_emitest.h" |
|
20 #include "d_emitest_dev.h" |
|
21 #include <kernel/emi.h> |
|
22 |
|
23 // |
|
24 // DEMITestFactory |
|
25 // |
|
26 |
|
27 /* |
|
28 Standard export function for LDDs. This creates a DLogicalDevice derived object, |
|
29 in this case, our DEMITestFactory |
|
30 */ |
|
31 DECLARE_STANDARD_LDD() |
|
32 { |
|
33 return new DEMITestFactory; |
|
34 } |
|
35 |
|
36 DEMITestFactory::DEMITestFactory() |
|
37 { |
|
38 } |
|
39 |
|
40 DEMITestFactory::~DEMITestFactory() |
|
41 { |
|
42 } |
|
43 |
|
44 /* |
|
45 Second stage constructor for DEMITestFactory. |
|
46 This must at least set a name for the driver object. |
|
47 |
|
48 @return KErrNone or standard error code. |
|
49 */ |
|
50 TInt DEMITestFactory::Install() |
|
51 { |
|
52 return SetName(&KEMITestName); |
|
53 } |
|
54 |
|
55 /* |
|
56 Return the drivers capabilities. |
|
57 Called in the response to an RDevice::GetCaps() request. |
|
58 The thread is in a critical section. |
|
59 |
|
60 @param aDes Descriptor to write capabilities information into |
|
61 */ |
|
62 void DEMITestFactory::GetCaps(TDes8&) const |
|
63 { |
|
64 } |
|
65 |
|
66 /* |
|
67 Called by the kernel's device driver framework to create a Logical Channel. |
|
68 This is called in the context of the user thread (client) which requested the creation of a Logical Channel |
|
69 (E.g. through a call to RBusLogicalChannel::DoCreate) |
|
70 The thread is in a critical section. |
|
71 |
|
72 @param aChannel Set to point to the created Logical Channel |
|
73 |
|
74 @return KErrNone or standard error code. |
|
75 */ |
|
76 TInt DEMITestFactory::Create(DLogicalChannelBase*& aChannel) |
|
77 { |
|
78 aChannel=new DEMITestChannel; |
|
79 if(!aChannel) |
|
80 return KErrNoMemory; |
|
81 |
|
82 return KErrNone; |
|
83 } |
|
84 |
|
85 |
|
86 // |
|
87 // Logical Channel |
|
88 // |
|
89 |
|
90 DEMITestChannel::DEMITestChannel() |
|
91 : iTagMaskDFC(TagMaskDFC,NULL,1) |
|
92 { |
|
93 // Get pointer to client threads DThread object |
|
94 iClient=&Kern::CurrentThread(); |
|
95 // Open a reference on client thread so it's control block can't dissapear until |
|
96 // this driver has finished with it. |
|
97 ((DObject*)iClient)->Open(); |
|
98 } |
|
99 |
|
100 DEMITestChannel::~DEMITestChannel() |
|
101 { |
|
102 // Stop EMI, incase it wannt stopped manually. |
|
103 EMI::TaskEventLogging(EFalse,0,NULL,NULL); |
|
104 EMI::SetMask(0); |
|
105 |
|
106 // Close our reference on the client thread |
|
107 Kern::SafeClose((DObject*&)iClient,NULL); |
|
108 } |
|
109 |
|
110 /* |
|
111 Second stage constructor called by the kernel's device driver framework. |
|
112 This is called in the context of the user thread (client) which requested the creation of a Logical Channel |
|
113 (E.g. through a call to RBusLogicalChannel::DoCreate) |
|
114 The thread is in a critical section. |
|
115 |
|
116 @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate |
|
117 @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate |
|
118 @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate |
|
119 |
|
120 @return KErrNone or standard error code. |
|
121 */ |
|
122 TInt DEMITestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion&) |
|
123 { |
|
124 iTagMaskDFC.SetDfcQ(Kern::DfcQue0()); |
|
125 return KErrNone; |
|
126 } |
|
127 |
|
128 /* |
|
129 Normal test monitors |
|
130 */ |
|
131 TInt MyThreadStartMonitor(NThread* aNThread) |
|
132 { |
|
133 TTaskEventRecord rec; |
|
134 rec.iType=128; |
|
135 rec.iPrevious=((TInt*) aNThread)+1; // This stops the event getting killed on thread exit. |
|
136 // This means there is no garantee the thread will still exist when |
|
137 // the record is read. This is only safe here as the test code never |
|
138 // attempts to derefrance this pointer. |
|
139 EMI::AddTaskEvent(rec); |
|
140 return 0; |
|
141 } |
|
142 |
|
143 |
|
144 void MyThreadExitMonitor(NThread* aNThread) |
|
145 { |
|
146 TTaskEventRecord rec; |
|
147 rec.iType=129; |
|
148 rec.iPrevious=aNThread; |
|
149 EMI::AddTaskEvent(rec); |
|
150 } |
|
151 /* |
|
152 Stress test monitors |
|
153 |
|
154 Vems = 1: Passed. |
|
155 0: No monitors called. |
|
156 -1: Wrong Exit monitor callled. |
|
157 -2: Exit call before StartMonitor |
|
158 -3: Jibberish VEMs value. (or anything ending 5-9) |
|
159 -4: Exit called multiple times, 1st time ok. |
|
160 <-9: Exit called multiple times. See last digit for status 1st time. |
|
161 Stops couting after -1000, where its clearly very sick! |
|
162 */ |
|
163 |
|
164 |
|
165 TInt SoakStartMonitor1(NThread* aNThread) |
|
166 { |
|
167 EMI::SetThreadVemsData(aNThread,(TAny*)1000); |
|
168 return 0; |
|
169 } |
|
170 |
|
171 TInt SoakStartMonitor2(NThread* aNThread) |
|
172 { |
|
173 EMI::SetThreadVemsData(aNThread,(TAny*)2000); |
|
174 return 0; |
|
175 } |
|
176 |
|
177 |
|
178 |
|
179 inline void SoakExitMonitor(NThread* aNThread, TInt aOwner) |
|
180 { |
|
181 TInt val = (TInt) EMI::GetThreadVemsData(aNThread); |
|
182 |
|
183 if (val>-1) |
|
184 { |
|
185 TInt notOwner = (aOwner==1000?2000:1000); |
|
186 |
|
187 if (val==aOwner) |
|
188 EMI::SetThreadVemsData(aNThread,(TAny*)1); |
|
189 else if (val==notOwner) |
|
190 EMI::SetThreadVemsData(aNThread,(TAny*)-1); |
|
191 else if (val==0) |
|
192 EMI::SetThreadVemsData(aNThread,(TAny*)-2); |
|
193 else if (val==1) |
|
194 EMI::SetThreadVemsData(aNThread,(TAny*)-4); |
|
195 else |
|
196 EMI::SetThreadVemsData(aNThread,(TAny*)-3); |
|
197 } |
|
198 else |
|
199 { |
|
200 if (val>-1000) |
|
201 EMI::SetThreadVemsData(aNThread,(TAny*)(val-10)); |
|
202 else |
|
203 EMI::SetThreadVemsData(aNThread,(TAny*)val); |
|
204 } |
|
205 } |
|
206 |
|
207 void SoakExitMonitor1(NThread* aNThread) |
|
208 { |
|
209 SoakExitMonitor(aNThread,1000); |
|
210 } |
|
211 void SoakExitMonitor2(NThread* aNThread) |
|
212 { |
|
213 SoakExitMonitor(aNThread,2000); |
|
214 } |
|
215 |
|
216 /* |
|
217 Process synchronous requests |
|
218 */ |
|
219 TInt DEMITestChannel::Request(TInt aFunction, TAny* a1, TAny* a2) |
|
220 { |
|
221 TInt r=KErrNotSupported; |
|
222 TTaskEventRecord rec; |
|
223 |
|
224 switch (aFunction) |
|
225 { |
|
226 case REMITest::ETaskEventLogging: |
|
227 { |
|
228 |
|
229 NKern::ThreadEnterCS(); |
|
230 |
|
231 TMonitors mon = (TMonitors) ((TInt)a1 >> 1); |
|
232 TBool logging = (TBool) ((TInt)a1 & 1); |
|
233 |
|
234 switch (mon) |
|
235 { |
|
236 case ENone: r = EMI::TaskEventLogging(logging,(TInt) a2,NULL,NULL); |
|
237 break; |
|
238 case ENormal: r = EMI::TaskEventLogging(logging,(TInt) a2,&MyThreadStartMonitor,&MyThreadExitMonitor); |
|
239 break; |
|
240 case EStressFirst:r = EMI::TaskEventLogging(logging,(TInt) a2,SoakStartMonitor1,SoakExitMonitor1); |
|
241 break; |
|
242 case EStressSecond:r = EMI::TaskEventLogging(logging,(TInt) a2,SoakStartMonitor2,SoakExitMonitor2); |
|
243 } |
|
244 NKern::ThreadLeaveCS(); |
|
245 return r; |
|
246 } |
|
247 case REMITest::EGetTaskEvent: |
|
248 r = (TInt) EMI::GetTaskEvent(rec); |
|
249 if (r) |
|
250 kumemput(a1,&rec,sizeof(TTaskEventRecord)); |
|
251 return r; |
|
252 case REMITest::EAddTaskEvent: |
|
253 kumemget(&rec,a1,sizeof(TTaskEventRecord)); |
|
254 return (TInt) EMI::AddTaskEvent(rec); |
|
255 case REMITest::EGetIdleThread: |
|
256 return (TInt) EMI::GetIdleThread(); |
|
257 case REMITest::EGetSigmaThread: |
|
258 return (TInt) EMI::GetSigmaThread(); |
|
259 case REMITest::ESetVEMSData: |
|
260 EMI::SetThreadVemsData((NThread*) a1,a2); |
|
261 return KErrNone; |
|
262 case REMITest::EGetVEMSData: |
|
263 return (TInt) EMI::GetThreadVemsData((NThread*) a1); |
|
264 case REMITest::ESetThreadLoggable: |
|
265 EMI::SetThreadLoggable((NThread*) a1,(TBool) a2); |
|
266 return KErrNone; |
|
267 case REMITest::EGetThreadLoggable: |
|
268 return (TInt) EMI::GetThreadLoggable((NThread*) a1); |
|
269 case REMITest::ESetThreadTag: |
|
270 EMI::SetThreadTag((NThread*) a1,(TUint32) a2); |
|
271 return KErrNone; |
|
272 case REMITest::EGetThreadTag: |
|
273 return (TInt) EMI::GetThreadTag((NThread*) a1); |
|
274 case REMITest::ESetMask: |
|
275 EMI::SetMask((TInt) a1); |
|
276 return KErrNone; |
|
277 case REMITest::EGetMask: |
|
278 return EMI::GetMask(); |
|
279 case REMITest::ESetDFC: |
|
280 EMI::SetDfc(&iTagMaskDFC, 0); |
|
281 return KErrNone; |
|
282 case REMITest::ESetState: |
|
283 EMI::SetState((TInt) a1); |
|
284 return KErrNone; |
|
285 case REMITest::EGetState: |
|
286 return EMI::GetState(); |
|
287 case REMITest::EGetNThread: |
|
288 { |
|
289 DThread* myThread; |
|
290 TInt myNThread; |
|
291 NKern::LockSystem(); |
|
292 |
|
293 myThread = (DThread* ) Kern::CurrentThread().ObjectFromHandle((TInt)a1,EThread); |
|
294 myNThread= (TInt) (myThread==NULL?NULL:&myThread->iNThread); |
|
295 NKern::UnlockSystem(); |
|
296 return myNThread; |
|
297 } |
|
298 case REMITest::EAfterIdle: |
|
299 EMI::AfterIdle((TInt) a1); |
|
300 return KErrNone; |
|
301 |
|
302 default: |
|
303 return KErrNotSupported; |
|
304 } |
|
305 } |
|
306 |
|
307 /* |
|
308 DFC callback which gets triggered when the EMI tag anded with thread mask is true. |
|
309 Sets EMI state to be the value returned from GetDfcTriggerTag. |
|
310 */ |
|
311 void DEMITestChannel::TagMaskDFC(TAny*) |
|
312 { |
|
313 EMI::SetState(EMI::GetDfcTriggerTag()); |
|
314 EMI::SetMask(0); |
|
315 } |