os/kernelhwsrv/kerneltest/e32test/benchmark/bm_ldd.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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