|
1 // Copyright (c) 2003-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\debug\t_context.cpp |
|
15 // Overview: |
|
16 // Exercise kernel-side functions to get, set user-side context and |
|
17 // kernel-side exception handlers. |
|
18 // API Information: |
|
19 // RBusLogicalChannel, DLogicalChannel. |
|
20 // Details: |
|
21 // - Load the context logical device driver, open user side handle to |
|
22 // a LDD channel and check software exception scheme when handle is |
|
23 // not created. |
|
24 // - Check user-side handler called when kernel-side handler is not |
|
25 // created and exception is handled as expected. |
|
26 // - Make a synchronous Kernel Executive type request to logical channel |
|
27 // for a specific functionality and check that it is as expected. |
|
28 // - Check that kernel-side handler is not triggered by IsExceptionHandler |
|
29 // method. |
|
30 // - Test user-side, kernel-side handlers are as expected. |
|
31 // - In the context of thread taking hardware exception with synchronous |
|
32 // and asynchronous killing: |
|
33 // - check context captured in hardware exception hook and |
|
34 // context captured in RemoveThread hook are as expected. |
|
35 // - In the context of thread taking software exception with synchronous |
|
36 // and asynchronous killing: |
|
37 // - check context captured in software exception hook and |
|
38 // context captured in RemoveThread hook are as expected. |
|
39 // - In the context of thread blocked on WFAR: |
|
40 // - check context captured while thread is blocked, |
|
41 // context can be modified while thread is blocked, |
|
42 // context captured in RemoveThread hook are as expected. |
|
43 // - In the context of thread killed after being pre-empted by interrupt |
|
44 // while in user mode: |
|
45 // - check context captured while thread is spinning, context can be |
|
46 // modified while thread is blocked, context captured in RemoveThread |
|
47 // hook are as expected. |
|
48 // - Check whether heap has been corrupted by all the tests. |
|
49 // - Check that the system doesn't crash when the context of a dead thread is |
|
50 // set or retrieved. |
|
51 // Platforms/Drives/Compatibility: |
|
52 // Hardware (Automatic). |
|
53 // Assumptions/Requirement/Pre-requisites: |
|
54 // Failures and causes: |
|
55 // Base Port information: |
|
56 // |
|
57 // |
|
58 |
|
59 #define __E32TEST_EXTENSION__ |
|
60 #include <e32test.h> |
|
61 #include <e32svr.h> |
|
62 #include <e32def.h> |
|
63 #include <e32def_private.h> |
|
64 #include <u32hal.h> |
|
65 #include "d_context.h" |
|
66 #include "context.h" |
|
67 |
|
68 enum TKillMode |
|
69 { |
|
70 ESynchronousKill, // thread kills itself in exception handler |
|
71 EAsynchronousKill // thread suspends itself in exception handler and is killed by main thread |
|
72 }; |
|
73 |
|
74 _LIT(KUserExecPanic, "USER-EXEC"); |
|
75 |
|
76 RTest test(_L("T_CONTEXT")); |
|
77 |
|
78 TInt KernelExcCount; // incremented when user-side exception handler called |
|
79 TInt UserExcCount; // incremented when kernel-side exception handler called |
|
80 TExcType LastUserExcType; // set by user-side exception handler when called |
|
81 |
|
82 RContextLdd Channel; |
|
83 |
|
84 |
|
85 TInt CallDeviceDriverAndSpin(TAny* aExpected) |
|
86 { |
|
87 TArmRegSet* expectedContext = (TArmRegSet*)aExpected; |
|
88 expectedContext->iR13 = Channel.SpinInKernel(EFalse); |
|
89 Channel.SpinInKernel(ETrue); |
|
90 return 0; |
|
91 } |
|
92 |
|
93 TInt UserRaiseExceptionThread(TAny* aExcType) |
|
94 { |
|
95 TExcType e = static_cast<TExcType>(reinterpret_cast<TInt>(aExcType)); |
|
96 User::RaiseException(e); |
|
97 return 0; |
|
98 } |
|
99 |
|
100 TInt RThreadRaiseExceptionThread(TAny* aExcType) |
|
101 { |
|
102 TExcType e = static_cast<TExcType>(reinterpret_cast<TInt>(aExcType)); |
|
103 User::RaiseException(e); |
|
104 return 0; |
|
105 } |
|
106 |
|
107 void UserExceptionHandler(TExcType aType) |
|
108 { |
|
109 // Check kernel-side handler was called before user-side one |
|
110 if (Channel.IsHooked() && KernelExcCount != 1) |
|
111 User::Invariant(); // force failure in RaiseExceptionHarness() |
|
112 |
|
113 LastUserExcType = aType; |
|
114 UserExcCount++; |
|
115 User::Panic(KUserExecPanic, ECausedException); |
|
116 } |
|
117 |
|
118 TInt UserTrapExceptionThread(TAny* aExcType) |
|
119 { |
|
120 TInt r = User::SetExceptionHandler(UserExceptionHandler, 0xFFFFFFFF); |
|
121 if (r != KErrNone) |
|
122 return 0; // force failure in RaiseExceptionHarness() |
|
123 TExcType e = static_cast<TExcType>(reinterpret_cast<TInt>(aExcType)); |
|
124 User::RaiseException(e); |
|
125 return 0; |
|
126 } |
|
127 |
|
128 TInt NaturalDeathFunc(TAny*) |
|
129 {// Don't do too much but be sure to complete. |
|
130 return KErrNone; |
|
131 } |
|
132 |
|
133 |
|
134 void RaiseExceptionHarness(TThreadFunction aFn, TExcType aType) |
|
135 { |
|
136 RThread t; |
|
137 TInt r = t.Create(_L("RaiseException"), aFn, KDefaultStackSize, NULL, |
|
138 reinterpret_cast<TAny*>(aType)); |
|
139 test(r == KErrNone); |
|
140 |
|
141 TRequestStatus s; |
|
142 t.Logon(s); |
|
143 TBool oldJitSetting = User::JustInTime(); |
|
144 User::SetJustInTime(EFalse); |
|
145 t.Resume(); |
|
146 User::WaitForRequest(s); |
|
147 User::SetJustInTime(oldJitSetting); |
|
148 |
|
149 test(t.ExitType() == EExitPanic); |
|
150 test(t.ExitCategory() == KUserExecPanic); |
|
151 test(t.ExitReason() == ECausedException); |
|
152 CLOSE_AND_WAIT(t); |
|
153 } |
|
154 |
|
155 |
|
156 void TestSwExcNoHandlers() |
|
157 { |
|
158 test.Next(_L("Check software exception scheme when no handler")); |
|
159 |
|
160 RaiseExceptionHarness(UserRaiseExceptionThread, EExcGeneral); |
|
161 RaiseExceptionHarness(RThreadRaiseExceptionThread, EExcGeneral); |
|
162 } |
|
163 |
|
164 void TestUserSwExcHandlerAlone() |
|
165 { |
|
166 test.Next(_L("Check user-side handler called when no kernel-side handler")); |
|
167 |
|
168 UserExcCount = 0; |
|
169 RaiseExceptionHarness(UserTrapExceptionThread, EExcIntegerDivideByZero); |
|
170 test(LastUserExcType == EExcIntegerDivideByZero); |
|
171 test(UserExcCount == 1); |
|
172 } |
|
173 |
|
174 void TestUserAndKernelSwExcHandlers() |
|
175 { |
|
176 test.Next(_L("Check kernel-side exception handler")); |
|
177 test.Start(_L("Check kernel-side handler called")); |
|
178 |
|
179 KernelExcCount = 0; |
|
180 RaiseExceptionHarness(UserRaiseExceptionThread, EExcUserInterrupt); |
|
181 test(KernelExcCount == 1); |
|
182 test(Channel.LastException() == EExcUserInterrupt); |
|
183 |
|
184 KernelExcCount = 0; |
|
185 RaiseExceptionHarness(RThreadRaiseExceptionThread, EExcIntegerDivideByZero); |
|
186 test(KernelExcCount == 1); |
|
187 test(Channel.LastException() == EExcIntegerDivideByZero); |
|
188 |
|
189 test.Next(_L("Check kernel-side handler not triggered by IsExceptionHandler()")); |
|
190 |
|
191 KernelExcCount = 0; |
|
192 (void) User::IsExceptionHandled(EExcUserInterrupt); |
|
193 test(KernelExcCount == 0); |
|
194 |
|
195 test.Next(_L("Check user-side + kernel-side handler")); |
|
196 |
|
197 UserExcCount = 0; |
|
198 KernelExcCount = 0; |
|
199 RaiseExceptionHarness(UserTrapExceptionThread, EExcIntegerDivideByZero); |
|
200 test(LastUserExcType == EExcIntegerDivideByZero); |
|
201 test(UserExcCount == 1); |
|
202 test(KernelExcCount == 1); |
|
203 test(Channel.LastException() == EExcIntegerDivideByZero); |
|
204 |
|
205 test.End(); |
|
206 } |
|
207 |
|
208 |
|
209 ////////////////////////////////////////////////////////////////////////////// |
|
210 |
|
211 void DumpContext(const TDesC& aTitle, TArmRegSet& aContext) |
|
212 { |
|
213 test.Printf(_L("%S\n"), &aTitle); |
|
214 test.Printf(_L(" r0 =%08x r1 =%08x r2 =%08x r3 =%08x\n"),aContext.iR0,aContext.iR1,aContext.iR2,aContext.iR3); |
|
215 test.Printf(_L(" r4 =%08x r5 =%08x r6 =%08x r7 =%08x\n"),aContext.iR4,aContext.iR5,aContext.iR6,aContext.iR7); |
|
216 test.Printf(_L(" r8 =%08x r9 =%08x r10=%08x r11=%08x\n"),aContext.iR8,aContext.iR9,aContext.iR10,aContext.iR11); |
|
217 test.Printf(_L(" r12=%08x r13=%08x r14=%08x r15=%08x\n"),aContext.iR12,aContext.iR13,aContext.iR14,aContext.iR15); |
|
218 test.Printf(_L(" cpsr=%08x dacr=%08x\n"),aContext.iFlags, aContext.iDacr); |
|
219 } |
|
220 |
|
221 void ModifyContext(TArmRegSet& aContext) |
|
222 { |
|
223 TArmReg* end = (TArmReg*)(&aContext+1); |
|
224 for (TArmReg* p = (TArmReg*)&aContext; p<end; ++p) |
|
225 *p = ~*p; |
|
226 } |
|
227 |
|
228 |
|
229 void TestHwExcContext(TKillMode aKillMode, TUserCallbackState aCallback) |
|
230 { |
|
231 test.Next(_L("Check context of thread taking hardware exception")); |
|
232 if (aKillMode == EAsynchronousKill) |
|
233 test.Printf(_L("Thread will be asynchronously killed\n")); |
|
234 else |
|
235 test.Printf(_L("Thread will kill itself\n")); |
|
236 |
|
237 TArmRegSet expectedContext; |
|
238 RThread t; |
|
239 TInt r = t.Create(_L("ContextHwExc"), ThreadContextHwExc, KDefaultStackSize, NULL, &expectedContext); |
|
240 test(r == KErrNone); |
|
241 |
|
242 TArmRegSet exceptionContext; |
|
243 TRequestStatus exceptionStatus; |
|
244 Channel.TrapNextHwExc(t.Id(), &exceptionContext, exceptionStatus, aKillMode==ESynchronousKill); |
|
245 |
|
246 TRequestStatus deathStatus; |
|
247 TArmRegSet deathContext; |
|
248 Channel.TrapNextDeath(t.Id(), &deathContext, deathStatus); |
|
249 |
|
250 TBool oldJitSetting = User::JustInTime(); |
|
251 User::SetJustInTime(EFalse); |
|
252 t.Resume(); |
|
253 User::WaitForRequest(exceptionStatus); |
|
254 User::SetJustInTime(oldJitSetting); |
|
255 test(exceptionStatus == KErrNone); // See CheckSetContext() in LDD |
|
256 |
|
257 test.Start(_L("Check context captured in hardware exception hook")); |
|
258 exceptionContext.iR15 += 4; // See CheckContextHwExc() |
|
259 DumpContext(_L("Expected context:"), expectedContext); |
|
260 DumpContext(_L("Context in hw exception hook:"), exceptionContext); |
|
261 test(CheckContextHwExc(&exceptionContext, &expectedContext)); |
|
262 |
|
263 if (aCallback != ENoCallback) |
|
264 { |
|
265 test.Printf(_L("Adding user callback type %d\n"), aCallback); |
|
266 Channel.AddUserCallback(t.Id(), aCallback); |
|
267 Channel.ResumeTrappedThread(t.Id()); |
|
268 User::After(500000); |
|
269 |
|
270 test.Next(_L("Check context captured while thread is in callback")); |
|
271 TArmRegSet callbackContext; |
|
272 Channel.GetContext(t.Id(), &callbackContext); |
|
273 callbackContext.iR15 += 4; // See CheckContextHwExc() |
|
274 DumpContext(_L("Expected context:"), expectedContext); |
|
275 DumpContext(_L("Actual context:"), callbackContext); |
|
276 test(CheckContextHwExc(&callbackContext, &expectedContext)); |
|
277 } |
|
278 |
|
279 ModifyContext(expectedContext); |
|
280 DumpContext(_L("Expected context after modification:"), expectedContext); |
|
281 |
|
282 if (aKillMode == EAsynchronousKill) |
|
283 { |
|
284 test.Next(_L("Check context can be modified by another thread")); |
|
285 TArmRegSet modifiedContext = expectedContext; |
|
286 test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone); |
|
287 modifiedContext.iR15 = exceptionContext.iR15; // See CheckContextHwExc() |
|
288 DumpContext(_L("Actual context after modification:"), modifiedContext); |
|
289 test(CheckContextHwExc(&modifiedContext, &expectedContext)); |
|
290 |
|
291 User::SetJustInTime(EFalse); |
|
292 t.Panic(_L("TEST"), 42); |
|
293 } |
|
294 else |
|
295 { |
|
296 // The thread has modified its own user context in the exception hook. |
|
297 User::SetJustInTime(EFalse); |
|
298 } |
|
299 |
|
300 User::WaitForRequest(deathStatus); |
|
301 User::SetJustInTime(oldJitSetting); |
|
302 CLOSE_AND_WAIT(t); |
|
303 |
|
304 test.Next(_L("Check context captured in RemoveThread hook")); |
|
305 deathContext.iR15 = exceptionContext.iR15; // See CheckContextHwExc() |
|
306 DumpContext(_L("context in RemoveThread hook:"), deathContext); |
|
307 test(CheckContextHwExc(&deathContext, &expectedContext)); |
|
308 test.End(); |
|
309 } |
|
310 |
|
311 |
|
312 void TestSwExcContext(TKillMode aKillMode, TUserCallbackState aCallback) |
|
313 { |
|
314 test.Next(_L("Check context of thread taking software exception (slow executive call)")); |
|
315 if (aKillMode == EAsynchronousKill) |
|
316 test.Printf(_L("Thread will be asynchronously killed\n")); |
|
317 else |
|
318 test.Printf(_L("Thread will kill itself\n")); |
|
319 |
|
320 TArmRegSet expectedContext; |
|
321 RThread t; |
|
322 TInt r = t.Create(_L("ContextSwExc"), ThreadContextSwExc, KDefaultStackSize, NULL, &expectedContext); |
|
323 test(r == KErrNone); |
|
324 |
|
325 TArmRegSet exceptionContext; |
|
326 TRequestStatus exceptionStatus; |
|
327 Channel.TrapNextSwExc(t.Id(), &exceptionContext, exceptionStatus, aKillMode == ESynchronousKill); |
|
328 |
|
329 TRequestStatus deathStatus; |
|
330 TArmRegSet deathContext; |
|
331 Channel.TrapNextDeath(t.Id(), &deathContext, deathStatus); |
|
332 |
|
333 TBool oldJitSetting = User::JustInTime(); |
|
334 User::SetJustInTime(EFalse); |
|
335 t.Resume(); |
|
336 User::WaitForRequest(exceptionStatus); |
|
337 User::SetJustInTime(oldJitSetting); |
|
338 test(exceptionStatus == KErrNone); // See CheckSetContext() in LDD |
|
339 |
|
340 test.Start(_L("Check context captured in software exception hook")); |
|
341 DumpContext(_L("Expected context:"), expectedContext); |
|
342 DumpContext(_L("Context in sw exception hook:"), exceptionContext); |
|
343 test(CheckContextSwExc(&exceptionContext, &expectedContext)); |
|
344 |
|
345 if (aCallback != ENoCallback) |
|
346 { |
|
347 test.Printf(_L("Adding user callback type %d\n"), aCallback); |
|
348 Channel.AddUserCallback(t.Id(), aCallback); |
|
349 Channel.ResumeTrappedThread(t.Id()); |
|
350 User::After(500000); |
|
351 |
|
352 test.Next(_L("Check context captured while thread is in callback")); |
|
353 TArmRegSet callbackContext; |
|
354 Channel.GetContext(t.Id(), &callbackContext); |
|
355 DumpContext(_L("Expected context:"), expectedContext); |
|
356 DumpContext(_L("Actual context:"), callbackContext); |
|
357 test(CheckContextSwExc(&callbackContext, &expectedContext)); |
|
358 } |
|
359 |
|
360 ModifyContext(expectedContext); |
|
361 DumpContext(_L("Expected context after modification:"), expectedContext); |
|
362 |
|
363 if (aKillMode == EAsynchronousKill) |
|
364 { |
|
365 test.Next(_L("Check context can be modified by another thread")); |
|
366 TArmRegSet modifiedContext = expectedContext; |
|
367 test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone); |
|
368 modifiedContext.iR14 = exceptionContext.iR14; // See CheckContextSwExc() |
|
369 modifiedContext.iR15 = exceptionContext.iR15; // See CheckContextSwExc() |
|
370 DumpContext(_L("Actual context after modification:"), modifiedContext); |
|
371 test(CheckContextSwExc(&modifiedContext, &expectedContext)); |
|
372 |
|
373 User::SetJustInTime(EFalse); |
|
374 t.Panic(_L("TEST"), 24); |
|
375 } |
|
376 else |
|
377 { |
|
378 // The thread has modified its own user context in the exception hook. |
|
379 User::SetJustInTime(EFalse); |
|
380 } |
|
381 |
|
382 User::WaitForRequest(deathStatus); |
|
383 User::SetJustInTime(oldJitSetting); |
|
384 CLOSE_AND_WAIT(t); |
|
385 |
|
386 test.Next(_L("Check context captured in RemoveThread hook")); |
|
387 deathContext.iR14 = exceptionContext.iR14; // See CheckContextSwExc() |
|
388 deathContext.iR15 = exceptionContext.iR15; // See CheckContextSwExc() |
|
389 DumpContext(_L("context in RemoveThread hook:"), deathContext); |
|
390 test(CheckContextSwExc(&deathContext, &expectedContext)); |
|
391 test.End(); |
|
392 } |
|
393 |
|
394 void TestKillWFAR(TUserCallbackState aCallback) |
|
395 { |
|
396 test.Next(_L("Check context of thread blocked on WFAR")); |
|
397 |
|
398 TArmRegSet expectedContext; |
|
399 RThread t; |
|
400 TInt r = t.Create(_L("ContextWFAR"), ThreadContextWFAR, KDefaultStackSize, NULL, &expectedContext); |
|
401 test(r == KErrNone); |
|
402 |
|
403 TRequestStatus deathStatus; |
|
404 TArmRegSet deathContext; |
|
405 Channel.TrapNextDeath(t.Id(), &deathContext, deathStatus); |
|
406 |
|
407 // Boost thread's priority and kick it off. This ensures we'll |
|
408 // run again only after it is blocked on its request semaphore. |
|
409 t.SetPriority(EPriorityMore); |
|
410 t.Resume(); |
|
411 |
|
412 if (aCallback != ENoCallback) |
|
413 { |
|
414 test.Printf(_L("Adding user callback type %d\n"), aCallback); |
|
415 Channel.AddUserCallback(t.Id(), aCallback); |
|
416 t.SetPriority(EPriorityNormal); |
|
417 t.RequestSignal(); |
|
418 User::After(500000); |
|
419 } |
|
420 |
|
421 test.Start(_L("Check context captured while thread is blocked")); |
|
422 TArmRegSet blockedContext; |
|
423 Channel.GetContext(t.Id(), &blockedContext); |
|
424 DumpContext(_L("Expected context:"), expectedContext); |
|
425 DumpContext(_L("Actual context:"), blockedContext); |
|
426 test(CheckContextWFAR(&blockedContext, &expectedContext)); |
|
427 |
|
428 test.Next(_L("Check context can be modified while thread is blocked")); |
|
429 ModifyContext(expectedContext); |
|
430 expectedContext.iR14 = blockedContext.iR14; // See CheckContextWFAR() |
|
431 expectedContext.iR15 = blockedContext.iR15; // See CheckContextWFAR() |
|
432 TArmRegSet modifiedContext = expectedContext; |
|
433 test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone); |
|
434 DumpContext(_L("Expected context after modification:"), expectedContext); |
|
435 DumpContext(_L("Actual context after modification:"), modifiedContext); |
|
436 test(CheckContextWFAR(&modifiedContext, &expectedContext)); |
|
437 |
|
438 TBool oldJitSetting = User::JustInTime(); |
|
439 User::SetJustInTime(EFalse); |
|
440 t.Panic(_L("TEST"), 999); |
|
441 User::WaitForRequest(deathStatus); |
|
442 User::SetJustInTime(oldJitSetting); |
|
443 CLOSE_AND_WAIT(t); |
|
444 |
|
445 test.Next(_L("Check context captured in RemoveThread hook")); |
|
446 DumpContext(_L("Expected context:"), expectedContext); |
|
447 DumpContext(_L("context in RemoveThread hook:\n"), deathContext); |
|
448 test(CheckContextWFARDied(&deathContext, &expectedContext)); |
|
449 test.End(); |
|
450 } |
|
451 |
|
452 void TestKillInterrupt(TUserCallbackState aCallback) |
|
453 { |
|
454 test.Next(_L("Check context of thread killed after being preempted by interrupt while in user mode")); |
|
455 |
|
456 TArmRegSet expectedContext; |
|
457 RThread t; |
|
458 TInt r = t.Create(_L("ContextKillInterrupt"), ThreadContextUserInt, KDefaultStackSize, NULL, &expectedContext); |
|
459 test(r == KErrNone); |
|
460 |
|
461 TArmRegSet trappedContext; |
|
462 TRequestStatus trapStatus; |
|
463 Channel.TrapNextDeath(t.Id(), &trappedContext, trapStatus); |
|
464 |
|
465 t.Resume(); |
|
466 User::After(500000); |
|
467 |
|
468 if (aCallback != ENoCallback) |
|
469 { |
|
470 test.Printf(_L("Adding user callback type %d\n"), aCallback); |
|
471 Channel.AddUserCallback(t.Id(), aCallback); |
|
472 User::After(500000); |
|
473 } |
|
474 |
|
475 test.Start(_L("Check context captured while thread is spinning")); |
|
476 TArmRegSet spinContext; |
|
477 Channel.GetContext(t.Id(), &spinContext); |
|
478 DumpContext(_L("Expected context:"), expectedContext); |
|
479 DumpContext(_L("Actual context:"), spinContext); |
|
480 test(CheckContextUserInt(&spinContext, &expectedContext)); |
|
481 |
|
482 test.Next(_L("Check context can be modified while thread is spinning")); |
|
483 ModifyContext(expectedContext); |
|
484 expectedContext.iR15 = spinContext.iR15; // see CheckContextUserInt() |
|
485 expectedContext.iFlags = spinContext.iFlags; // must be left unmodified |
|
486 expectedContext.iDacr = spinContext.iDacr; // must be left unmodified |
|
487 DumpContext(_L("Expected context after modification:"), expectedContext); |
|
488 TArmRegSet modifiedContext = expectedContext; |
|
489 test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone); |
|
490 DumpContext(_L("Actual context after modification:"), modifiedContext); |
|
491 test(CheckContextUserInt(&modifiedContext, &expectedContext)); |
|
492 |
|
493 TBool oldJitSetting = User::JustInTime(); |
|
494 User::SetJustInTime(EFalse); |
|
495 t.Kill(-1); |
|
496 User::WaitForRequest(trapStatus); |
|
497 User::SetJustInTime(oldJitSetting); |
|
498 CLOSE_AND_WAIT(t); |
|
499 |
|
500 test.Next(_L("Check context captured in RemoveThread hook")); |
|
501 DumpContext(_L("Expected context:"), expectedContext); |
|
502 DumpContext(_L("Trapped context:"), trappedContext); |
|
503 test(CheckContextUserIntDied(&trappedContext, &expectedContext)); |
|
504 test.End(); |
|
505 } |
|
506 |
|
507 void TestKernelContext() |
|
508 { |
|
509 test.Start(_L("Test kernel context function")); |
|
510 |
|
511 TArmRegSet kernelContext, expectedContext; |
|
512 for (TInt i=0; i<15; ++i) |
|
513 *(((TUint32*)&expectedContext)+i) = 0xa0000000 + i; |
|
514 |
|
515 RThread t; |
|
516 TInt r = t.Create(_L("SpinInKernel"), CallDeviceDriverAndSpin, KDefaultStackSize, NULL, &expectedContext); |
|
517 test(r == KErrNone); |
|
518 t.Resume(); |
|
519 |
|
520 User::After(500000); |
|
521 Channel.GetKernelContext(t.Id(), &kernelContext); |
|
522 |
|
523 TBool oldJitSetting = User::JustInTime(); |
|
524 User::SetJustInTime(EFalse); |
|
525 t.Kill(-1); |
|
526 User::SetJustInTime(oldJitSetting); |
|
527 CLOSE_AND_WAIT(t); |
|
528 |
|
529 test.Next(_L("Check kernel context is as expected")); |
|
530 DumpContext(_L("Expected context:"), expectedContext); |
|
531 DumpContext(_L("Actual context:"), kernelContext); |
|
532 test(CheckContextKernel(&kernelContext, &expectedContext)); |
|
533 |
|
534 test.End(); |
|
535 } |
|
536 |
|
537 void TestNaturalDeathContext() |
|
538 { |
|
539 test.Start(_L("Test setting and retrieving the context of a dead thread")); |
|
540 TArmFullContext context; |
|
541 memclr(&context, sizeof context); |
|
542 |
|
543 RThread t; |
|
544 TInt r = t.Create(_L("NaturalDeath"), NaturalDeathFunc, KDefaultStackSize, NULL, NULL); |
|
545 test_KErrNone(r); |
|
546 t.Resume(); |
|
547 |
|
548 User::After(500000); |
|
549 Channel.SetAndGetFullContext(t.Id(), &context); |
|
550 |
|
551 // Verify that no registers should be available for this dead thread. |
|
552 test_Equal(0, context.iUserAvail); |
|
553 test_Equal(0, context.iSystemAvail); |
|
554 |
|
555 t.Close(); |
|
556 test.End(); |
|
557 } |
|
558 |
|
559 TInt E32Main() |
|
560 { |
|
561 test.Title(); |
|
562 |
|
563 test.Start(_L("Loading LDD")); |
|
564 TInt r = User::LoadLogicalDevice(_L("D_CONTEXT")); |
|
565 test(r == KErrNone || r == KErrAlreadyExists); |
|
566 |
|
567 // Must be after LDD loading because User::FreeLogicalDevice() does not |
|
568 // free anything currently. |
|
569 __KHEAP_MARK; |
|
570 |
|
571 test.Next(_L("Opening LDD channel")); |
|
572 r = Channel.Open(); |
|
573 test(r == KErrNone); |
|
574 |
|
575 TestSwExcNoHandlers(); |
|
576 TestUserSwExcHandlerAlone(); |
|
577 |
|
578 test.Next(_L("Enable event hook")); |
|
579 r = Channel.Hook(&KernelExcCount); |
|
580 test(r == KErrNone); |
|
581 |
|
582 TestUserAndKernelSwExcHandlers(); |
|
583 TestHwExcContext(ESynchronousKill, ENoCallback); |
|
584 TestHwExcContext(EAsynchronousKill, ENoCallback); |
|
585 TestSwExcContext(ESynchronousKill, ENoCallback); |
|
586 TestSwExcContext(EAsynchronousKill, ENoCallback); |
|
587 TestKillWFAR(ENoCallback); |
|
588 TestKillInterrupt(ENoCallback); |
|
589 TestKernelContext(); |
|
590 TestNaturalDeathContext(); |
|
591 #ifdef _DEBUG |
|
592 TestHwExcContext(EAsynchronousKill, ESpinningCallback); |
|
593 TestHwExcContext(EAsynchronousKill, ESleepingCallback); |
|
594 TestSwExcContext(EAsynchronousKill, ESpinningCallback); |
|
595 TestSwExcContext(EAsynchronousKill, ESleepingCallback); |
|
596 TestKillWFAR(ESpinningCallback); |
|
597 TestKillWFAR(ESleepingCallback); |
|
598 TestKillInterrupt(ESpinningCallback); |
|
599 TestKillInterrupt(ESleepingCallback); |
|
600 #endif |
|
601 |
|
602 Channel.Close(); |
|
603 |
|
604 // Wait for idle + async cleanup (waits for DKernelEventHandler to go away) |
|
605 r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0); |
|
606 test_KErrNone(r); |
|
607 |
|
608 __KHEAP_MARKEND; |
|
609 |
|
610 // Don't check user heap because if TLS is stored on the user-side this will not be freed when |
|
611 // the thread exits due to an exception. |
|
612 |
|
613 test.End(); |
|
614 return 0; |
|
615 } |