kerneltest/e32test/benchmark/bm_ldd.cpp
changeset 0 a41df078684a
child 148 31ea0f8e3c99
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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