|
1 // Copyright (c) 2002-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 // |
|
15 |
|
16 #include "k32bm.h" |
|
17 |
|
18 const TUint8 KMutexOrder = 0xf0; |
|
19 |
|
20 class DBMLDevice : public DLogicalDevice |
|
21 { |
|
22 public: |
|
23 DBMLDevice(); |
|
24 virtual TInt Install(); |
|
25 virtual void GetCaps(TDes8& aDes) const; |
|
26 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
27 }; |
|
28 |
|
29 class DBMLChannel : public DLogicalChannelBase, public MBMIsr, public MBMInterruptLatencyIsr |
|
30 { |
|
31 public: |
|
32 DBMLChannel(); |
|
33 ~DBMLChannel(); |
|
34 |
|
35 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); |
|
36 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); |
|
37 |
|
38 DBMPChannel* PChannel() { return (DBMPChannel*) iPdd; } |
|
39 |
|
40 private: |
|
41 static const TInt KBMDfcQThreadPriority; |
|
42 static const TInt KBMKernelThreadPriority; |
|
43 |
|
44 static void Dfc(TAny*); |
|
45 |
|
46 virtual void Isr(TBMTicks now); |
|
47 |
|
48 TInt (DBMLChannel::*iRequestInterrupt)(); // Measurement specific RBMChannel::RequestInterrupt() implmentation |
|
49 TInt RequestInterrupt(); // Default iRequestInterrupt() implementation |
|
50 |
|
51 TBMTicks (DBMLChannel::*iResult)(); // Measurement specific RBMChannel::Result() implmentation |
|
52 TBMTicks Result(); // Default iResult() implementation |
|
53 |
|
54 TInt Start(RBMChannel::TMode); |
|
55 |
|
56 TInt StartInterruptLatency(); |
|
57 virtual void InterruptLatencyIsr(TBMTicks latency); |
|
58 |
|
59 TInt StartKernelPreemptionLatency(); |
|
60 static TInt KernelPreemptionLatencyThreadEntry(TAny* ptr); |
|
61 void KernelPreemptionLatencyThread(); |
|
62 |
|
63 TInt StartUserPreemptionLatency(); |
|
64 TBMTicks UserPreemptionLatencyResult(); // iResult() implementation |
|
65 |
|
66 TInt StartNTimerJitter(); |
|
67 TInt RequestNTimerJitterInterrupt(); // iRequestInterrupt() implementation |
|
68 static void NTimerJitterCallBack(TAny*); |
|
69 |
|
70 TInt StartTimerStampOverhead(); |
|
71 TInt RequestTimerStampOverhead(); // iRequestInterrupt() implementation |
|
72 |
|
73 TInt SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio); |
|
74 |
|
75 DMutex* iLock; // Shall be acquired by anyone who access the object's writable state. |
|
76 |
|
77 TBool iStarted; // ETrue when a particular sequence of measurements has been started |
|
78 TBool iPendingInterruptRequest; // ETrue when an interrupt has been requested |
|
79 |
|
80 TDynamicDfcQue* iDfcQ; |
|
81 TDfc iDfc; |
|
82 |
|
83 DThread* iKernelThread; // the kernel thread created by some benchmarks |
|
84 DThread* iUserThread; // the user-side thread |
|
85 DThread* iInterruptThread; // the thread signaled by DFC; if non-NULL either iKernelThread or iUserThread |
|
86 |
|
87 NTimer iNTimer; // the timer used in "NTimer jitter" benchmark |
|
88 TBMTicks iOneNTimerTick; // number of high-resolution timer ticks in one NKern tick. |
|
89 TInt iNTimerShotCount; // used in "NTimer jitter" to distinguish between the first and the second shots |
|
90 |
|
91 TBMTicks iTime; |
|
92 TBMTicks iTimerPeriod; // period of high-resolution timer in ticks |
|
93 |
|
94 NFastSemaphore* iKernelThreadExitSemaphore; |
|
95 |
|
96 void Lock() |
|
97 { |
|
98 NKern::ThreadEnterCS(); |
|
99 Kern::MutexWait(*iLock); |
|
100 } |
|
101 void Unlock() |
|
102 { |
|
103 Kern::MutexSignal(*iLock); |
|
104 NKern::ThreadLeaveCS(); |
|
105 } |
|
106 |
|
107 TBMTicks Delta(TBMTicks aT0, TBMTicks aT1) |
|
108 { |
|
109 return (aT0 <= aT1) ? (aT1 - aT0) : iTimerPeriod - (aT0 - aT1); |
|
110 } |
|
111 }; |
|
112 |
|
113 _LIT(KBMLChannelLit, "BMLChannel"); |
|
114 |
|
115 const TInt DBMLChannel::KBMDfcQThreadPriority = KBMLDDHighPriority; |
|
116 const TInt DBMLChannel::KBMKernelThreadPriority = KBMLDDMidPriority; |
|
117 |
|
118 |
|
119 |
|
120 DECLARE_STANDARD_LDD() |
|
121 // |
|
122 // Create a new device |
|
123 // |
|
124 { |
|
125 __ASSERT_CRITICAL; |
|
126 return new DBMLDevice; |
|
127 } |
|
128 |
|
129 DBMLDevice::DBMLDevice() |
|
130 // |
|
131 // Constructor |
|
132 // |
|
133 { |
|
134 //iUnitsMask=0; |
|
135 iVersion = TVersion(1,0,1); |
|
136 iParseMask = KDeviceAllowPhysicalDevice; |
|
137 } |
|
138 |
|
139 TInt DBMLDevice::Install() |
|
140 // |
|
141 // Install the device driver. |
|
142 // |
|
143 { |
|
144 TInt r = SetName(&KBMLdName); |
|
145 return r; |
|
146 } |
|
147 |
|
148 void DBMLDevice::GetCaps(TDes8&) const |
|
149 // |
|
150 // Return the Comm capabilities. |
|
151 // |
|
152 { |
|
153 } |
|
154 |
|
155 TInt DBMLDevice::Create(DLogicalChannelBase*& aChannel) |
|
156 // |
|
157 // Create a channel on the device. |
|
158 // |
|
159 { |
|
160 __ASSERT_CRITICAL; |
|
161 aChannel = new DBMLChannel; |
|
162 return aChannel ? KErrNone : KErrNoMemory; |
|
163 } |
|
164 |
|
165 DBMLChannel::DBMLChannel() : |
|
166 iDfc(0, this, 0, 0), |
|
167 iNTimer(NULL, this) |
|
168 { |
|
169 // iDfcQueue = NULL; |
|
170 // iStarted = EFalse; |
|
171 // iPendingInterruptRequest = EFalse; |
|
172 // iKernelThread = NULL; |
|
173 } |
|
174 |
|
175 TInt DBMLChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /* aInfo*/ , const TVersion& aVer) |
|
176 // |
|
177 // Create the channel from the passed info. |
|
178 // |
|
179 { |
|
180 __ASSERT_CRITICAL; |
|
181 if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer)) |
|
182 return KErrNotSupported; |
|
183 TInt r = Kern::MutexCreate(iLock, KBMLChannelLit, KMutexOrder); |
|
184 if (r != KErrNone) |
|
185 { |
|
186 return r; |
|
187 } |
|
188 iTimerPeriod = PChannel()->TimerPeriod(); |
|
189 // Calculate the number of high-resolution timer ticks in one NKern tick |
|
190 // deviding the number of high-resolution timer ticks in one second by the |
|
191 // number of NKern ticks in one second. |
|
192 // |
|
193 iOneNTimerTick = PChannel()->TimerNsToTicks(BMSecondsToNs(1))/NKern::TimerTicks(1000); |
|
194 return KErrNone; |
|
195 } |
|
196 |
|
197 DBMLChannel::~DBMLChannel() |
|
198 // Called on a channel close. Note that if the PDD channel create failed |
|
199 // then the DoCreate() call will not have been made so don't assume anything |
|
200 // about non-ctor initialisation of members. |
|
201 { |
|
202 if (iLock) |
|
203 iLock->Close(0); |
|
204 |
|
205 if (iPendingInterruptRequest) |
|
206 { |
|
207 PChannel()->CancelInterrupt(); |
|
208 iDfc.Cancel(); |
|
209 } |
|
210 |
|
211 if (iDfcQ) |
|
212 { |
|
213 iDfcQ->Destroy(); |
|
214 } |
|
215 |
|
216 if (iKernelThread) |
|
217 { |
|
218 NFastSemaphore exitSemaphore; |
|
219 exitSemaphore.iOwningThread = NKern::CurrentThread(); |
|
220 iKernelThreadExitSemaphore = &exitSemaphore; |
|
221 NKern::ThreadRequestSignal(&iKernelThread->iNThread); |
|
222 NKern::FSWait(&exitSemaphore); |
|
223 } |
|
224 } |
|
225 |
|
226 void DBMLChannel::Dfc(TAny* ptr) |
|
227 { |
|
228 DBMLChannel* lCh = (DBMLChannel*) ptr; |
|
229 BM_ASSERT(lCh->iPendingInterruptRequest); |
|
230 BM_ASSERT(lCh->iInterruptThread); |
|
231 NKern::ThreadRequestSignal(&lCh->iInterruptThread->iNThread); |
|
232 lCh->iPendingInterruptRequest = EFalse; |
|
233 } |
|
234 |
|
235 // |
|
236 // Default DBMLChannel::iRequestInterrupt implementation |
|
237 // |
|
238 TInt DBMLChannel::RequestInterrupt() |
|
239 { |
|
240 if (!iStarted) |
|
241 { |
|
242 return KErrNotReady; |
|
243 } |
|
244 if (iPendingInterruptRequest) |
|
245 { |
|
246 return KErrInUse; |
|
247 } |
|
248 iPendingInterruptRequest = ETrue; |
|
249 PChannel()->RequestInterrupt(); |
|
250 return KErrNone; |
|
251 } |
|
252 |
|
253 // |
|
254 // Default DBMLChannel::iResult implementation |
|
255 // |
|
256 TBMTicks DBMLChannel::Result() |
|
257 { |
|
258 return iTime; |
|
259 } |
|
260 |
|
261 void DBMLChannel::Isr(TBMTicks aNow) |
|
262 { |
|
263 // |
|
264 // Store the ISR entry time and queue a DFC. |
|
265 // |
|
266 iTime = aNow; |
|
267 iDfc.Add(); |
|
268 } |
|
269 |
|
270 // |
|
271 // "INTERRUPT LATENCY" |
|
272 // |
|
273 // SCENARIO: |
|
274 // |
|
275 // A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest() |
|
276 // (RBMChannel::Result()). |
|
277 // When the interrupt occurs DBMLChannel::InterruptLatencyIsr() stores the interrupt latency |
|
278 // provided by LDD, in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) |
|
279 // which in its turn signals the user thread. |
|
280 // |
|
281 |
|
282 TInt DBMLChannel::StartInterruptLatency() |
|
283 { |
|
284 if (iStarted) |
|
285 { |
|
286 return KErrInUse; |
|
287 } |
|
288 TInt r = PChannel()->BindInterrupt((MBMInterruptLatencyIsr*) this); |
|
289 if (r != KErrNone) |
|
290 { |
|
291 return r; |
|
292 } |
|
293 // Use the default iRequestInterrupt() implmentation |
|
294 iRequestInterrupt = &DBMLChannel::RequestInterrupt; |
|
295 // Use the default iResult() implmentation |
|
296 iResult = &DBMLChannel::Result; |
|
297 iInterruptThread = &Kern::CurrentThread(); |
|
298 iStarted = ETrue; |
|
299 return KErrNone; |
|
300 } |
|
301 |
|
302 void DBMLChannel::InterruptLatencyIsr(TBMTicks aLatency) |
|
303 { |
|
304 iTime = aLatency; |
|
305 iDfc.Add(); |
|
306 } |
|
307 |
|
308 // |
|
309 // "KERNEL THREAD PREEMPTION LATENCY" |
|
310 // |
|
311 // SCENARIO: |
|
312 // |
|
313 // A new kernel thread is created at the beginning of a sequence of measurements |
|
314 // (DBMLChannel::StartKernelPreemptionLatency()). The kernel thread waits at Kern::WaitForAnyRequest() |
|
315 // (DBMLChannel::KernelPreemptionLatencyThread()). |
|
316 // The user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest() |
|
317 // (RBMChannel::Result()). |
|
318 // When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time, provided by LDD |
|
319 // in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which, in its turn, |
|
320 // signals the kernel thread. |
|
321 // The kernel thread, when awaken, calculates the latency as the difference between the ISR entry time |
|
322 // and the current time and finally signals the user thread. |
|
323 // |
|
324 |
|
325 TInt DBMLChannel::StartKernelPreemptionLatency() |
|
326 { |
|
327 if (iStarted) |
|
328 { |
|
329 return KErrInUse; |
|
330 } |
|
331 TInt r = PChannel()->BindInterrupt((MBMIsr*) this); |
|
332 if (r != KErrNone) |
|
333 { |
|
334 return r; |
|
335 } |
|
336 { |
|
337 SThreadCreateInfo info; |
|
338 info.iType = EThreadSupervisor; |
|
339 info.iFunction = DBMLChannel::KernelPreemptionLatencyThreadEntry; |
|
340 info.iPtr = this; |
|
341 info.iSupervisorStack = NULL; |
|
342 info.iSupervisorStackSize = 0; |
|
343 info.iInitialThreadPriority = KBMKernelThreadPriority; |
|
344 info.iName.Set(KBMLChannelLit); |
|
345 info.iTotalSize = sizeof(info); |
|
346 r = Kern::ThreadCreate(info); |
|
347 if (r != KErrNone) |
|
348 { |
|
349 return r; |
|
350 } |
|
351 iKernelThread = (DThread*) info.iHandle; |
|
352 } |
|
353 |
|
354 iUserThread = &Kern::CurrentThread(); |
|
355 // Use the default iRequestInterrupt() implmentation |
|
356 iRequestInterrupt = &DBMLChannel::RequestInterrupt; |
|
357 // Use the default iResult() implmentation |
|
358 iResult = &DBMLChannel::Result; |
|
359 iInterruptThread = iKernelThread; |
|
360 iStarted = ETrue; |
|
361 |
|
362 Kern::ThreadResume(*iKernelThread); |
|
363 |
|
364 return KErrNone; |
|
365 } |
|
366 |
|
367 TInt DBMLChannel::KernelPreemptionLatencyThreadEntry(TAny* ptr) |
|
368 { |
|
369 DBMLChannel* lCh = (DBMLChannel*) ptr; |
|
370 lCh->KernelPreemptionLatencyThread(); |
|
371 BM_ASSERT(0); |
|
372 return 0; |
|
373 } |
|
374 |
|
375 void DBMLChannel::KernelPreemptionLatencyThread() |
|
376 { |
|
377 for(;;) |
|
378 { |
|
379 NKern::WaitForAnyRequest(); |
|
380 |
|
381 if(iKernelThreadExitSemaphore) |
|
382 break; |
|
383 |
|
384 TBMTicks now = PChannel()->TimerStamp(); |
|
385 iTime = Delta(iTime, now); |
|
386 BM_ASSERT(iUserThread); |
|
387 NKern::ThreadRequestSignal(&iUserThread->iNThread); |
|
388 } |
|
389 |
|
390 NKern::FSSignal(iKernelThreadExitSemaphore); |
|
391 Kern::Exit(0); |
|
392 } |
|
393 |
|
394 |
|
395 // |
|
396 // "USER THREAD PREEMPTION LATENCY" |
|
397 // |
|
398 // SCENARIO: |
|
399 // |
|
400 // A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest() |
|
401 // (RBMChannel::Result()). |
|
402 // When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time provided by LDD, |
|
403 // in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which in its turn |
|
404 // signals the user thread. |
|
405 // The user thread, when awaken, immediately re-enters in the LDD, and calculates the latency as |
|
406 // the difference between the ISR entry time and the current time. |
|
407 // |
|
408 |
|
409 TInt DBMLChannel::StartUserPreemptionLatency() |
|
410 { |
|
411 if (iStarted) |
|
412 { |
|
413 return KErrInUse; |
|
414 } |
|
415 TInt r = PChannel()->BindInterrupt((MBMIsr*) this); |
|
416 if (r != KErrNone) |
|
417 { |
|
418 return r; |
|
419 } |
|
420 // Default iRequestInterrupt() implmentation |
|
421 iRequestInterrupt = &DBMLChannel::RequestInterrupt; |
|
422 iResult = &DBMLChannel::UserPreemptionLatencyResult; |
|
423 iInterruptThread = &Kern::CurrentThread(); |
|
424 iStarted = ETrue; |
|
425 return KErrNone; |
|
426 } |
|
427 |
|
428 TBMTicks DBMLChannel::UserPreemptionLatencyResult() |
|
429 { |
|
430 TBMTicks now = PChannel()->TimerStamp(); |
|
431 return Delta(iTime, now); |
|
432 } |
|
433 |
|
434 // |
|
435 // "NTimer PERIOD JITTER" |
|
436 // |
|
437 // SCENARIO: |
|
438 // |
|
439 // One measuremnt is done by two consecutive NTimer callbacks. |
|
440 // The first callback stores the current time and the second one calculate the actual period as |
|
441 // the difference between its own current time and the time stored by the first callback. |
|
442 // The difference between this actual period and the theoretical period is considered as the jitter. |
|
443 // |
|
444 |
|
445 TInt DBMLChannel::StartNTimerJitter() |
|
446 { |
|
447 if (iStarted) |
|
448 { |
|
449 return KErrInUse; |
|
450 } |
|
451 new (&iNTimer) NTimer(&NTimerJitterCallBack, this); |
|
452 iRequestInterrupt = &DBMLChannel::RequestNTimerJitterInterrupt; |
|
453 // Use the default iResult() implmentation |
|
454 iResult = &DBMLChannel::Result; |
|
455 iInterruptThread = &Kern::CurrentThread(); |
|
456 iStarted = ETrue; |
|
457 return KErrNone; |
|
458 } |
|
459 |
|
460 TInt DBMLChannel::RequestNTimerJitterInterrupt() |
|
461 { |
|
462 if (!iStarted) |
|
463 { |
|
464 return KErrNotReady; |
|
465 } |
|
466 if (iPendingInterruptRequest) |
|
467 { |
|
468 return KErrInUse; |
|
469 } |
|
470 iPendingInterruptRequest = ETrue; |
|
471 iNTimerShotCount = 0; |
|
472 iNTimer.OneShot(1); |
|
473 return KErrNone; |
|
474 } |
|
475 |
|
476 |
|
477 void DBMLChannel::NTimerJitterCallBack(TAny* ptr) |
|
478 { |
|
479 DBMLChannel* lCh = (DBMLChannel*) ptr; |
|
480 TBMTicks now = lCh->PChannel()->TimerStamp(); |
|
481 if (lCh->iNTimerShotCount++ == 0) |
|
482 { |
|
483 // |
|
484 // This is the first callback: store the time and request another one. |
|
485 // |
|
486 lCh->iTime = now; |
|
487 lCh->iNTimer.Again(1); |
|
488 } |
|
489 else |
|
490 { |
|
491 // |
|
492 // This is the second callback: measure the jitter and schedule a DFC |
|
493 // which in its turn will signal the user thread. |
|
494 // |
|
495 lCh->iTime = lCh->Delta(lCh->iTime, now); |
|
496 lCh->iDfc.Add(); |
|
497 } |
|
498 } |
|
499 |
|
500 // |
|
501 // "TIMER OVERHEAD" |
|
502 // |
|
503 // SCENARIO: |
|
504 // To measure the overhead of the high-precision timer read operation we get |
|
505 // two consecutive timestamps through DBMPChannel::TimerStamp() interface. |
|
506 // The difference beween this two values is considered as the measured overhead. |
|
507 // |
|
508 |
|
509 TInt DBMLChannel::StartTimerStampOverhead() |
|
510 { |
|
511 if (iStarted) |
|
512 { |
|
513 return KErrInUse; |
|
514 } |
|
515 iRequestInterrupt = &DBMLChannel::RequestTimerStampOverhead; |
|
516 // Use the default iResult() implmentation |
|
517 iResult = &DBMLChannel::Result; |
|
518 iInterruptThread = &Kern::CurrentThread(); |
|
519 iStarted = ETrue; |
|
520 return KErrNone; |
|
521 } |
|
522 |
|
523 TInt DBMLChannel::RequestTimerStampOverhead() |
|
524 { |
|
525 TBMTicks t1 = PChannel()->TimerStamp(); |
|
526 TBMTicks t2 = PChannel()->TimerStamp(); |
|
527 iTime = Delta(t1, t2); |
|
528 NKern::ThreadRequestSignal(&iInterruptThread->iNThread); |
|
529 return KErrNone; |
|
530 } |
|
531 // |
|
532 // END OF "GETTING TIMER OVERHEAD" |
|
533 // |
|
534 |
|
535 // |
|
536 // The implmentation of RBMDriver::SetAbsPrioirty() call. |
|
537 // |
|
538 TInt DBMLChannel::SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio) |
|
539 { |
|
540 NKern::LockSystem(); |
|
541 // |
|
542 // Under the system lock find the DThread object and increment its ref-count (i.e Open()) |
|
543 // |
|
544 DThread* thr = (DThread*) Kern::ObjectFromHandle(&Kern::CurrentThread(), aThreadHandle, EThread); |
|
545 TInt r; |
|
546 if (!thr) |
|
547 { |
|
548 r = EBadHandle; |
|
549 } |
|
550 else |
|
551 { |
|
552 r = thr->Open(); |
|
553 } |
|
554 // |
|
555 // Now it's safe to release the system lock and to work with the object. |
|
556 // |
|
557 NKern::ThreadEnterCS(); |
|
558 NKern::UnlockSystem(); |
|
559 if (r != KErrNone) |
|
560 { |
|
561 NKern::ThreadLeaveCS(); |
|
562 return r; |
|
563 } |
|
564 *aOldPrio = thr->iDefaultPriority; |
|
565 Kern::SetThreadPriority(aNewPrio, thr); |
|
566 // |
|
567 // Work is done - close the object. |
|
568 // |
|
569 thr->Close(NULL); |
|
570 NKern::ThreadLeaveCS(); |
|
571 return KErrNone; |
|
572 } |
|
573 |
|
574 _LIT(KBmDfcQName, "BmDfcQ"); |
|
575 |
|
576 // |
|
577 // Starts a new sequence of measurements. |
|
578 // |
|
579 // Only one sequence can be started for any particular DBMLChannel object during its life. |
|
580 // If more than one sequence is required a new DBMLChannel object must be created. |
|
581 // |
|
582 TInt DBMLChannel::Start(RBMChannel::TMode aMode) |
|
583 { |
|
584 TInt r; |
|
585 if (iDfcQ == NULL) |
|
586 { |
|
587 r = Kern::DynamicDfcQCreate(iDfcQ, KBMDfcQThreadPriority, KBmDfcQName); |
|
588 if (r != KErrNone) |
|
589 return r; |
|
590 |
|
591 iDfc.SetDfcQ(iDfcQ); |
|
592 iDfc.SetFunction(Dfc); |
|
593 } |
|
594 |
|
595 switch (aMode) |
|
596 { |
|
597 case RBMChannel::EInterruptLatency: |
|
598 r = StartInterruptLatency(); |
|
599 break; |
|
600 case RBMChannel::EKernelPreemptionLatency: |
|
601 r = StartKernelPreemptionLatency(); |
|
602 break; |
|
603 case RBMChannel::EUserPreemptionLatency: |
|
604 r = StartUserPreemptionLatency(); |
|
605 break; |
|
606 case RBMChannel::ENTimerJitter: |
|
607 r = StartNTimerJitter(); |
|
608 break; |
|
609 case RBMChannel::ETimerStampOverhead: |
|
610 r = StartTimerStampOverhead(); |
|
611 break; |
|
612 default: |
|
613 r = KErrNotSupported; |
|
614 break; |
|
615 } |
|
616 |
|
617 return r; |
|
618 } |
|
619 |
|
620 // |
|
621 // Client requests. |
|
622 // |
|
623 TInt DBMLChannel::Request(TInt aFunction, TAny* a1, TAny* a2) |
|
624 { |
|
625 TInt r = KErrNone; |
|
626 switch (aFunction) |
|
627 { |
|
628 case RBMChannel::EStart: |
|
629 { |
|
630 RBMChannel::TMode mode = (RBMChannel::TMode) (TInt) a1; |
|
631 Lock(); |
|
632 r = Start(mode); |
|
633 Unlock(); |
|
634 break; |
|
635 } |
|
636 case RBMChannel::ERequestInterrupt: |
|
637 { |
|
638 Lock(); |
|
639 r = (this->*iRequestInterrupt)(); |
|
640 Unlock(); |
|
641 break; |
|
642 } |
|
643 case RBMChannel::EResult: |
|
644 { |
|
645 // |
|
646 // We don't acquire the lock because: |
|
647 // (1) iResult() typically reads iTime which was written BEFORE to signal the current thread |
|
648 // and therefore BEFORE the current thread comes here. |
|
649 // (2) we really want if possible (i.e. correct!) to avoid the lock acquisition because it can |
|
650 // increase the measurement overhead in the case when we are in a measured path (e.g. user |
|
651 // preemption latency benchmark). |
|
652 // |
|
653 TBMTicks ticks = (this->*iResult)(); |
|
654 umemput(a1, &ticks, sizeof(ticks)); |
|
655 break; |
|
656 } |
|
657 // |
|
658 // All below requests do not access writable DBMChannel state and therefore do not require the lock |
|
659 // |
|
660 case RBMChannel::ETimerStamp: |
|
661 { |
|
662 TBMTicks ticks = PChannel()->TimerStamp(); |
|
663 umemput(a1, &ticks, sizeof(ticks)); |
|
664 break; |
|
665 } |
|
666 case RBMChannel::ETimerPeriod: |
|
667 { |
|
668 TBMTicks ticks = iTimerPeriod; |
|
669 umemput(a1, &ticks, sizeof(ticks)); |
|
670 break; |
|
671 } |
|
672 case RBMChannel::ETimerTicksToNs: |
|
673 { |
|
674 TBMTicks ticks; |
|
675 umemget(&ticks, a1, sizeof(ticks)); |
|
676 TBMNs ns = PChannel()->TimerTicksToNs(ticks); |
|
677 umemput(a2, &ns, sizeof(ns)); |
|
678 break; |
|
679 } |
|
680 case RBMChannel::ETimerNsToTicks: |
|
681 { |
|
682 TBMNs ns; |
|
683 umemget(&ns, a1, sizeof(ns)); |
|
684 TBMTicks ticks = PChannel()->TimerNsToTicks(ns); |
|
685 umemput(a2, &ticks, sizeof(ticks)); |
|
686 break; |
|
687 } |
|
688 case RBMChannel::ESetAbsPriority: |
|
689 { |
|
690 TInt newPrio; |
|
691 TInt oldPrio; |
|
692 umemget(&newPrio, a2, sizeof(newPrio)); |
|
693 r = SetAbsPrioirty((TInt) a1, newPrio, &oldPrio); |
|
694 umemput(a2, &oldPrio, sizeof(oldPrio)); |
|
695 break; |
|
696 } |
|
697 default: |
|
698 r = KErrNotSupported; |
|
699 break; |
|
700 } |
|
701 return r; |
|
702 } |
|
703 |
|
704 |