sl@0: // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "k32bm.h" sl@0: sl@0: const TUint8 KMutexOrder = 0xf0; sl@0: sl@0: class DBMLDevice : public DLogicalDevice sl@0: { sl@0: public: sl@0: DBMLDevice(); sl@0: virtual TInt Install(); sl@0: virtual void GetCaps(TDes8& aDes) const; sl@0: virtual TInt Create(DLogicalChannelBase*& aChannel); sl@0: }; sl@0: sl@0: class DBMLChannel : public DLogicalChannelBase, public MBMIsr, public MBMInterruptLatencyIsr sl@0: { sl@0: public: sl@0: DBMLChannel(); sl@0: ~DBMLChannel(); sl@0: sl@0: virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); sl@0: virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); sl@0: sl@0: DBMPChannel* PChannel() { return (DBMPChannel*) iPdd; } sl@0: sl@0: private: sl@0: static const TInt KBMDfcQThreadPriority; sl@0: static const TInt KBMKernelThreadPriority; sl@0: sl@0: static void Dfc(TAny*); sl@0: sl@0: virtual void Isr(TBMTicks now); sl@0: sl@0: TInt (DBMLChannel::*iRequestInterrupt)(); // Measurement specific RBMChannel::RequestInterrupt() implmentation sl@0: TInt RequestInterrupt(); // Default iRequestInterrupt() implementation sl@0: sl@0: TBMTicks (DBMLChannel::*iResult)(); // Measurement specific RBMChannel::Result() implmentation sl@0: TBMTicks Result(); // Default iResult() implementation sl@0: sl@0: TInt Start(RBMChannel::TMode); sl@0: sl@0: TInt StartInterruptLatency(); sl@0: virtual void InterruptLatencyIsr(TBMTicks latency); sl@0: sl@0: TInt StartKernelPreemptionLatency(); sl@0: static TInt KernelPreemptionLatencyThreadEntry(TAny* ptr); sl@0: void KernelPreemptionLatencyThread(); sl@0: sl@0: TInt StartUserPreemptionLatency(); sl@0: TBMTicks UserPreemptionLatencyResult(); // iResult() implementation sl@0: sl@0: TInt StartNTimerJitter(); sl@0: TInt RequestNTimerJitterInterrupt(); // iRequestInterrupt() implementation sl@0: static void NTimerJitterCallBack(TAny*); sl@0: sl@0: TInt StartTimerStampOverhead(); sl@0: TInt RequestTimerStampOverhead(); // iRequestInterrupt() implementation sl@0: sl@0: TInt SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio); sl@0: sl@0: DMutex* iLock; // Shall be acquired by anyone who access the object's writable state. sl@0: sl@0: TBool iStarted; // ETrue when a particular sequence of measurements has been started sl@0: TBool iPendingInterruptRequest; // ETrue when an interrupt has been requested sl@0: sl@0: TDynamicDfcQue* iDfcQ; sl@0: TDfc iDfc; sl@0: sl@0: DThread* iKernelThread; // the kernel thread created by some benchmarks sl@0: DThread* iUserThread; // the user-side thread sl@0: DThread* iInterruptThread; // the thread signaled by DFC; if non-NULL either iKernelThread or iUserThread sl@0: sl@0: NTimer iNTimer; // the timer used in "NTimer jitter" benchmark sl@0: TBMTicks iOneNTimerTick; // number of high-resolution timer ticks in one NKern tick. sl@0: TInt iNTimerShotCount; // used in "NTimer jitter" to distinguish between the first and the second shots sl@0: sl@0: TBMTicks iTime; sl@0: TBMTicks iTimerPeriod; // period of high-resolution timer in ticks sl@0: sl@0: NFastSemaphore* iKernelThreadExitSemaphore; sl@0: sl@0: void Lock() sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: Kern::MutexWait(*iLock); sl@0: } sl@0: void Unlock() sl@0: { sl@0: Kern::MutexSignal(*iLock); sl@0: NKern::ThreadLeaveCS(); sl@0: } sl@0: sl@0: TBMTicks Delta(TBMTicks aT0, TBMTicks aT1) sl@0: { sl@0: return (aT0 <= aT1) ? (aT1 - aT0) : iTimerPeriod - (aT0 - aT1); sl@0: } sl@0: }; sl@0: sl@0: _LIT(KBMLChannelLit, "BMLChannel"); sl@0: sl@0: const TInt DBMLChannel::KBMDfcQThreadPriority = KBMLDDHighPriority; sl@0: const TInt DBMLChannel::KBMKernelThreadPriority = KBMLDDMidPriority; sl@0: sl@0: sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: // sl@0: // Create a new device sl@0: // sl@0: { sl@0: __ASSERT_CRITICAL; sl@0: return new DBMLDevice; sl@0: } sl@0: sl@0: DBMLDevice::DBMLDevice() sl@0: // sl@0: // Constructor sl@0: // sl@0: { sl@0: //iUnitsMask=0; sl@0: iVersion = TVersion(1,0,1); sl@0: iParseMask = KDeviceAllowPhysicalDevice; sl@0: } sl@0: sl@0: TInt DBMLDevice::Install() sl@0: // sl@0: // Install the device driver. sl@0: // sl@0: { sl@0: TInt r = SetName(&KBMLdName); sl@0: return r; sl@0: } sl@0: sl@0: void DBMLDevice::GetCaps(TDes8&) const sl@0: // sl@0: // Return the Comm capabilities. sl@0: // sl@0: { sl@0: } sl@0: sl@0: TInt DBMLDevice::Create(DLogicalChannelBase*& aChannel) sl@0: // sl@0: // Create a channel on the device. sl@0: // sl@0: { sl@0: __ASSERT_CRITICAL; sl@0: aChannel = new DBMLChannel; sl@0: return aChannel ? KErrNone : KErrNoMemory; sl@0: } sl@0: sl@0: DBMLChannel::DBMLChannel() : sl@0: iDfc(0, this, 0, 0), sl@0: iNTimer(NULL, this) sl@0: { sl@0: // iDfcQueue = NULL; sl@0: // iStarted = EFalse; sl@0: // iPendingInterruptRequest = EFalse; sl@0: // iKernelThread = NULL; sl@0: } sl@0: sl@0: TInt DBMLChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /* aInfo*/ , const TVersion& aVer) sl@0: // sl@0: // Create the channel from the passed info. sl@0: // sl@0: { sl@0: __ASSERT_CRITICAL; sl@0: if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer)) sl@0: return KErrNotSupported; sl@0: TInt r = Kern::MutexCreate(iLock, KBMLChannelLit, KMutexOrder); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: iTimerPeriod = PChannel()->TimerPeriod(); sl@0: // Calculate the number of high-resolution timer ticks in one NKern tick sl@0: // deviding the number of high-resolution timer ticks in one second by the sl@0: // number of NKern ticks in one second. sl@0: // sl@0: iOneNTimerTick = PChannel()->TimerNsToTicks(BMSecondsToNs(1))/NKern::TimerTicks(1000); sl@0: return KErrNone; sl@0: } sl@0: sl@0: DBMLChannel::~DBMLChannel() sl@0: // Called on a channel close. Note that if the PDD channel create failed sl@0: // then the DoCreate() call will not have been made so don't assume anything sl@0: // about non-ctor initialisation of members. sl@0: { sl@0: if (iLock) sl@0: iLock->Close(0); sl@0: sl@0: if (iPendingInterruptRequest) sl@0: { sl@0: PChannel()->CancelInterrupt(); sl@0: iDfc.Cancel(); sl@0: } sl@0: sl@0: if (iDfcQ) sl@0: { sl@0: iDfcQ->Destroy(); sl@0: } sl@0: sl@0: if (iKernelThread) sl@0: { sl@0: NFastSemaphore exitSemaphore; sl@0: exitSemaphore.iOwningThread = NKern::CurrentThread(); sl@0: iKernelThreadExitSemaphore = &exitSemaphore; sl@0: NKern::ThreadRequestSignal(&iKernelThread->iNThread); sl@0: NKern::FSWait(&exitSemaphore); sl@0: } sl@0: } sl@0: sl@0: void DBMLChannel::Dfc(TAny* ptr) sl@0: { sl@0: DBMLChannel* lCh = (DBMLChannel*) ptr; sl@0: BM_ASSERT(lCh->iPendingInterruptRequest); sl@0: BM_ASSERT(lCh->iInterruptThread); sl@0: NKern::ThreadRequestSignal(&lCh->iInterruptThread->iNThread); sl@0: lCh->iPendingInterruptRequest = EFalse; sl@0: } sl@0: sl@0: // sl@0: // Default DBMLChannel::iRequestInterrupt implementation sl@0: // sl@0: TInt DBMLChannel::RequestInterrupt() sl@0: { sl@0: if (!iStarted) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: if (iPendingInterruptRequest) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: iPendingInterruptRequest = ETrue; sl@0: PChannel()->RequestInterrupt(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // sl@0: // Default DBMLChannel::iResult implementation sl@0: // sl@0: TBMTicks DBMLChannel::Result() sl@0: { sl@0: return iTime; sl@0: } sl@0: sl@0: void DBMLChannel::Isr(TBMTicks aNow) sl@0: { sl@0: // sl@0: // Store the ISR entry time and queue a DFC. sl@0: // sl@0: iTime = aNow; sl@0: iDfc.Add(); sl@0: } sl@0: sl@0: // sl@0: // "INTERRUPT LATENCY" sl@0: // sl@0: // SCENARIO: sl@0: // sl@0: // A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest() sl@0: // (RBMChannel::Result()). sl@0: // When the interrupt occurs DBMLChannel::InterruptLatencyIsr() stores the interrupt latency sl@0: // provided by LDD, in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) sl@0: // which in its turn signals the user thread. sl@0: // sl@0: sl@0: TInt DBMLChannel::StartInterruptLatency() sl@0: { sl@0: if (iStarted) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: TInt r = PChannel()->BindInterrupt((MBMInterruptLatencyIsr*) this); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: // Use the default iRequestInterrupt() implmentation sl@0: iRequestInterrupt = &DBMLChannel::RequestInterrupt; sl@0: // Use the default iResult() implmentation sl@0: iResult = &DBMLChannel::Result; sl@0: iInterruptThread = &Kern::CurrentThread(); sl@0: iStarted = ETrue; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DBMLChannel::InterruptLatencyIsr(TBMTicks aLatency) sl@0: { sl@0: iTime = aLatency; sl@0: iDfc.Add(); sl@0: } sl@0: sl@0: // sl@0: // "KERNEL THREAD PREEMPTION LATENCY" sl@0: // sl@0: // SCENARIO: sl@0: // sl@0: // A new kernel thread is created at the beginning of a sequence of measurements sl@0: // (DBMLChannel::StartKernelPreemptionLatency()). The kernel thread waits at Kern::WaitForAnyRequest() sl@0: // (DBMLChannel::KernelPreemptionLatencyThread()). sl@0: // The user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest() sl@0: // (RBMChannel::Result()). sl@0: // When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time, provided by LDD sl@0: // in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which, in its turn, sl@0: // signals the kernel thread. sl@0: // The kernel thread, when awaken, calculates the latency as the difference between the ISR entry time sl@0: // and the current time and finally signals the user thread. sl@0: // sl@0: sl@0: TInt DBMLChannel::StartKernelPreemptionLatency() sl@0: { sl@0: if (iStarted) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: TInt r = PChannel()->BindInterrupt((MBMIsr*) this); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: { sl@0: SThreadCreateInfo info; sl@0: info.iType = EThreadSupervisor; sl@0: info.iFunction = DBMLChannel::KernelPreemptionLatencyThreadEntry; sl@0: info.iPtr = this; sl@0: info.iSupervisorStack = NULL; sl@0: info.iSupervisorStackSize = 0; sl@0: info.iInitialThreadPriority = KBMKernelThreadPriority; sl@0: info.iName.Set(KBMLChannelLit); sl@0: info.iTotalSize = sizeof(info); sl@0: r = Kern::ThreadCreate(info); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: iKernelThread = (DThread*) info.iHandle; sl@0: } sl@0: sl@0: iUserThread = &Kern::CurrentThread(); sl@0: // Use the default iRequestInterrupt() implmentation sl@0: iRequestInterrupt = &DBMLChannel::RequestInterrupt; sl@0: // Use the default iResult() implmentation sl@0: iResult = &DBMLChannel::Result; sl@0: iInterruptThread = iKernelThread; sl@0: iStarted = ETrue; sl@0: sl@0: Kern::ThreadResume(*iKernelThread); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DBMLChannel::KernelPreemptionLatencyThreadEntry(TAny* ptr) sl@0: { sl@0: DBMLChannel* lCh = (DBMLChannel*) ptr; sl@0: lCh->KernelPreemptionLatencyThread(); sl@0: BM_ASSERT(0); sl@0: return 0; sl@0: } sl@0: sl@0: void DBMLChannel::KernelPreemptionLatencyThread() sl@0: { sl@0: for(;;) sl@0: { sl@0: NKern::WaitForAnyRequest(); sl@0: sl@0: if(iKernelThreadExitSemaphore) sl@0: break; sl@0: sl@0: TBMTicks now = PChannel()->TimerStamp(); sl@0: iTime = Delta(iTime, now); sl@0: BM_ASSERT(iUserThread); sl@0: NKern::ThreadRequestSignal(&iUserThread->iNThread); sl@0: } sl@0: sl@0: NKern::FSSignal(iKernelThreadExitSemaphore); sl@0: Kern::Exit(0); sl@0: } sl@0: sl@0: sl@0: // sl@0: // "USER THREAD PREEMPTION LATENCY" sl@0: // sl@0: // SCENARIO: sl@0: // sl@0: // A user thread requests an interrupt (RBMChannel::RequestInterrupt()) and waits at User::WaitForAnyRequest() sl@0: // (RBMChannel::Result()). sl@0: // When the interrupt occurs DBMLChannel::Isr() stores the ISR entry time provided by LDD, sl@0: // in DBMLChannel::iTime and queues a DFC (DBMLChannel::iDfc, DBMLChannel::Dfc()) which in its turn sl@0: // signals the user thread. sl@0: // The user thread, when awaken, immediately re-enters in the LDD, and calculates the latency as sl@0: // the difference between the ISR entry time and the current time. sl@0: // sl@0: sl@0: TInt DBMLChannel::StartUserPreemptionLatency() sl@0: { sl@0: if (iStarted) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: TInt r = PChannel()->BindInterrupt((MBMIsr*) this); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: // Default iRequestInterrupt() implmentation sl@0: iRequestInterrupt = &DBMLChannel::RequestInterrupt; sl@0: iResult = &DBMLChannel::UserPreemptionLatencyResult; sl@0: iInterruptThread = &Kern::CurrentThread(); sl@0: iStarted = ETrue; sl@0: return KErrNone; sl@0: } sl@0: sl@0: TBMTicks DBMLChannel::UserPreemptionLatencyResult() sl@0: { sl@0: TBMTicks now = PChannel()->TimerStamp(); sl@0: return Delta(iTime, now); sl@0: } sl@0: sl@0: // sl@0: // "NTimer PERIOD JITTER" sl@0: // sl@0: // SCENARIO: sl@0: // sl@0: // One measuremnt is done by two consecutive NTimer callbacks. sl@0: // The first callback stores the current time and the second one calculate the actual period as sl@0: // the difference between its own current time and the time stored by the first callback. sl@0: // The difference between this actual period and the theoretical period is considered as the jitter. sl@0: // sl@0: sl@0: TInt DBMLChannel::StartNTimerJitter() sl@0: { sl@0: if (iStarted) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: new (&iNTimer) NTimer(&NTimerJitterCallBack, this); sl@0: iRequestInterrupt = &DBMLChannel::RequestNTimerJitterInterrupt; sl@0: // Use the default iResult() implmentation sl@0: iResult = &DBMLChannel::Result; sl@0: iInterruptThread = &Kern::CurrentThread(); sl@0: iStarted = ETrue; sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DBMLChannel::RequestNTimerJitterInterrupt() sl@0: { sl@0: if (!iStarted) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: if (iPendingInterruptRequest) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: iPendingInterruptRequest = ETrue; sl@0: iNTimerShotCount = 0; sl@0: iNTimer.OneShot(1); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: void DBMLChannel::NTimerJitterCallBack(TAny* ptr) sl@0: { sl@0: DBMLChannel* lCh = (DBMLChannel*) ptr; sl@0: TBMTicks now = lCh->PChannel()->TimerStamp(); sl@0: if (lCh->iNTimerShotCount++ == 0) sl@0: { sl@0: // sl@0: // This is the first callback: store the time and request another one. sl@0: // sl@0: lCh->iTime = now; sl@0: lCh->iNTimer.Again(1); sl@0: } sl@0: else sl@0: { sl@0: // sl@0: // This is the second callback: measure the jitter and schedule a DFC sl@0: // which in its turn will signal the user thread. sl@0: // sl@0: lCh->iTime = lCh->Delta(lCh->iTime, now); sl@0: lCh->iDfc.Add(); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // "TIMER OVERHEAD" sl@0: // sl@0: // SCENARIO: sl@0: // To measure the overhead of the high-precision timer read operation we get sl@0: // two consecutive timestamps through DBMPChannel::TimerStamp() interface. sl@0: // The difference beween this two values is considered as the measured overhead. sl@0: // sl@0: sl@0: TInt DBMLChannel::StartTimerStampOverhead() sl@0: { sl@0: if (iStarted) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: iRequestInterrupt = &DBMLChannel::RequestTimerStampOverhead; sl@0: // Use the default iResult() implmentation sl@0: iResult = &DBMLChannel::Result; sl@0: iInterruptThread = &Kern::CurrentThread(); sl@0: iStarted = ETrue; sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DBMLChannel::RequestTimerStampOverhead() sl@0: { sl@0: TBMTicks t1 = PChannel()->TimerStamp(); sl@0: TBMTicks t2 = PChannel()->TimerStamp(); sl@0: iTime = Delta(t1, t2); sl@0: NKern::ThreadRequestSignal(&iInterruptThread->iNThread); sl@0: return KErrNone; sl@0: } sl@0: // sl@0: // END OF "GETTING TIMER OVERHEAD" sl@0: // sl@0: sl@0: // sl@0: // The implmentation of RBMDriver::SetAbsPrioirty() call. sl@0: // sl@0: TInt DBMLChannel::SetAbsPrioirty(TInt aThreadHandle, TInt aNewPrio, TInt* aOldPrio) sl@0: { sl@0: NKern::LockSystem(); sl@0: // sl@0: // Under the system lock find the DThread object and increment its ref-count (i.e Open()) sl@0: // sl@0: DThread* thr = (DThread*) Kern::ObjectFromHandle(&Kern::CurrentThread(), aThreadHandle, EThread); sl@0: TInt r; sl@0: if (!thr) sl@0: { sl@0: r = EBadHandle; sl@0: } sl@0: else sl@0: { sl@0: r = thr->Open(); sl@0: } sl@0: // sl@0: // Now it's safe to release the system lock and to work with the object. sl@0: // sl@0: NKern::ThreadEnterCS(); sl@0: NKern::UnlockSystem(); sl@0: if (r != KErrNone) sl@0: { sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: *aOldPrio = thr->iDefaultPriority; sl@0: Kern::SetThreadPriority(aNewPrio, thr); sl@0: // sl@0: // Work is done - close the object. sl@0: // sl@0: thr->Close(NULL); sl@0: NKern::ThreadLeaveCS(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: _LIT(KBmDfcQName, "BmDfcQ"); sl@0: sl@0: // sl@0: // Starts a new sequence of measurements. sl@0: // sl@0: // Only one sequence can be started for any particular DBMLChannel object during its life. sl@0: // If more than one sequence is required a new DBMLChannel object must be created. sl@0: // sl@0: TInt DBMLChannel::Start(RBMChannel::TMode aMode) sl@0: { sl@0: TInt r; sl@0: if (iDfcQ == NULL) sl@0: { sl@0: r = Kern::DynamicDfcQCreate(iDfcQ, KBMDfcQThreadPriority, KBmDfcQName); sl@0: if (r != KErrNone) sl@0: return r; sl@0: sl@0: iDfc.SetDfcQ(iDfcQ); sl@0: iDfc.SetFunction(Dfc); sl@0: } sl@0: sl@0: switch (aMode) sl@0: { sl@0: case RBMChannel::EInterruptLatency: sl@0: r = StartInterruptLatency(); sl@0: break; sl@0: case RBMChannel::EKernelPreemptionLatency: sl@0: r = StartKernelPreemptionLatency(); sl@0: break; sl@0: case RBMChannel::EUserPreemptionLatency: sl@0: r = StartUserPreemptionLatency(); sl@0: break; sl@0: case RBMChannel::ENTimerJitter: sl@0: r = StartNTimerJitter(); sl@0: break; sl@0: case RBMChannel::ETimerStampOverhead: sl@0: r = StartTimerStampOverhead(); sl@0: break; sl@0: default: sl@0: r = KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: // sl@0: // Client requests. sl@0: // sl@0: TInt DBMLChannel::Request(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: TInt r = KErrNone; sl@0: switch (aFunction) sl@0: { sl@0: case RBMChannel::EStart: sl@0: { sl@0: RBMChannel::TMode mode = (RBMChannel::TMode) (TInt) a1; sl@0: Lock(); sl@0: r = Start(mode); sl@0: Unlock(); sl@0: break; sl@0: } sl@0: case RBMChannel::ERequestInterrupt: sl@0: { sl@0: Lock(); sl@0: r = (this->*iRequestInterrupt)(); sl@0: Unlock(); sl@0: break; sl@0: } sl@0: case RBMChannel::EResult: sl@0: { sl@0: // sl@0: // We don't acquire the lock because: sl@0: // (1) iResult() typically reads iTime which was written BEFORE to signal the current thread sl@0: // and therefore BEFORE the current thread comes here. sl@0: // (2) we really want if possible (i.e. correct!) to avoid the lock acquisition because it can sl@0: // increase the measurement overhead in the case when we are in a measured path (e.g. user sl@0: // preemption latency benchmark). sl@0: // sl@0: TBMTicks ticks = (this->*iResult)(); sl@0: umemput(a1, &ticks, sizeof(ticks)); sl@0: break; sl@0: } sl@0: // sl@0: // All below requests do not access writable DBMChannel state and therefore do not require the lock sl@0: // sl@0: case RBMChannel::ETimerStamp: sl@0: { sl@0: TBMTicks ticks = PChannel()->TimerStamp(); sl@0: umemput(a1, &ticks, sizeof(ticks)); sl@0: break; sl@0: } sl@0: case RBMChannel::ETimerPeriod: sl@0: { sl@0: TBMTicks ticks = iTimerPeriod; sl@0: umemput(a1, &ticks, sizeof(ticks)); sl@0: break; sl@0: } sl@0: case RBMChannel::ETimerTicksToNs: sl@0: { sl@0: TBMTicks ticks; sl@0: umemget(&ticks, a1, sizeof(ticks)); sl@0: TBMNs ns = PChannel()->TimerTicksToNs(ticks); sl@0: umemput(a2, &ns, sizeof(ns)); sl@0: break; sl@0: } sl@0: case RBMChannel::ETimerNsToTicks: sl@0: { sl@0: TBMNs ns; sl@0: umemget(&ns, a1, sizeof(ns)); sl@0: TBMTicks ticks = PChannel()->TimerNsToTicks(ns); sl@0: umemput(a2, &ticks, sizeof(ticks)); sl@0: break; sl@0: } sl@0: case RBMChannel::ESetAbsPriority: sl@0: { sl@0: TInt newPrio; sl@0: TInt oldPrio; sl@0: umemget(&newPrio, a2, sizeof(newPrio)); sl@0: r = SetAbsPrioirty((TInt) a1, newPrio, &oldPrio); sl@0: umemput(a2, &oldPrio, sizeof(oldPrio)); sl@0: break; sl@0: } sl@0: default: sl@0: r = KErrNotSupported; sl@0: break; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: