1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/nkern/nk_timer.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,592 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\nkern\nk_timer.cpp
1.18 +// Fast Millisecond Timer Implementation
1.19 +// This file is just a template - you'd be mad not to machine code this
1.20 +//
1.21 +//
1.22 +
1.23 +#include "nk_priv.h"
1.24 +
1.25 +const TInt KTimerQDfcPriority=6;
1.26 +
1.27 +GLDEF_D NTimerQ TheTimerQ;
1.28 +
1.29 +#ifndef __MSTIM_MACHINE_CODED__
1.30 +#ifdef _DEBUG
1.31 +#define __DEBUG_CALLBACK(n) {if (iDebugFn) (*iDebugFn)(iDebugPtr,n);}
1.32 +#else
1.33 +#define __DEBUG_CALLBACK(n)
1.34 +#endif
1.35 +
1.36 +
1.37 +/** Starts a nanokernel timer in one-shot mode with ISR callback.
1.38 +
1.39 + Queues the timer to expire in the specified number of nanokernel ticks. The
1.40 + actual wait time will be at least that much and may be up to one tick more.
1.41 + The expiry handler will be called in ISR context.
1.42 +
1.43 + Note that NKern::TimerTicks() can be used to convert milliseconds to ticks.
1.44 +
1.45 + @param aTime Timeout in nanokernel ticks
1.46 +
1.47 + @return KErrNone if no error; KErrInUse if timer is already active.
1.48 +
1.49 + @pre Any context
1.50 +
1.51 + @see NKern::TimerTicks()
1.52 + */
1.53 +EXPORT_C TInt NTimer::OneShot(TInt aTime)
1.54 + {
1.55 + return OneShot(aTime,FALSE);
1.56 + }
1.57 +
1.58 +
1.59 +/** Starts a nanokernel timer in one-shot mode with ISR or DFC callback.
1.60 +
1.61 + Queues the timer to expire in the specified number of nanokernel ticks. The
1.62 + actual wait time will be at least that much and may be up to one tick more.
1.63 + The expiry handler will be called in either ISR context or in the context
1.64 + of the nanokernel timer thread (DfcThread1).
1.65 +
1.66 + Note that NKern::TimerTicks() can be used to convert milliseconds to ticks.
1.67 +
1.68 + @param aTime Timeout in nanokernel ticks
1.69 + @param aDfc TRUE if DFC callback required, FALSE if ISR callback required.
1.70 +
1.71 + @return KErrNone if no error; KErrInUse if timer is already active.
1.72 +
1.73 + @pre Any context
1.74 +
1.75 + @see NKern::TimerTicks()
1.76 + */
1.77 +EXPORT_C TInt NTimer::OneShot(TInt aTime, TBool aDfc)
1.78 + {
1.79 + __NK_ASSERT_DEBUG(aTime>=0);
1.80 +
1.81 + /** iFunction could be set to NULL after NTimer::OneShot(TInt, TDfc&) call.
1.82 + Call-back mechanism cannot be changed in the life time of a timer. */
1.83 + __NK_ASSERT_DEBUG(iFunction!=NULL);
1.84 +
1.85 + TInt irq=NKern::DisableAllInterrupts();
1.86 + if (iState!=EIdle)
1.87 + {
1.88 + NKern::RestoreInterrupts(irq);
1.89 + return KErrInUse;
1.90 + }
1.91 + iCompleteInDfc=TUint8(aDfc?1:0);
1.92 + iTriggerTime=TheTimerQ.iMsCount+(TUint32)aTime;
1.93 + TheTimerQ.Add(this);
1.94 + NKern::RestoreInterrupts(irq);
1.95 + return KErrNone;
1.96 + }
1.97 +
1.98 +/** Starts a nanokernel timer in one-shot mode with callback in dfc thread that provided DFC belongs to.
1.99 +
1.100 + Queues the timer to expire in the specified number of nanokernel ticks. The
1.101 + actual wait time will be at least that much and may be up to one tick more.
1.102 + On expiry aDfc will be queued in ISR context.
1.103 +
1.104 + Note that NKern::TimerTicks() can be used to convert milliseconds to ticks.
1.105 +
1.106 + @param aTime Timeout in nanokernel ticks
1.107 + @param aDfc - Dfc to be queued when the timer expires.
1.108 +
1.109 + @return KErrNone if no error; KErrInUse if timer is already active.
1.110 +
1.111 + @pre Any context
1.112 +
1.113 + @see NKern::TimerTicks()
1.114 + */
1.115 +EXPORT_C TInt NTimer::OneShot(TInt aTime, TDfc& aDfc)
1.116 + {
1.117 + __NK_ASSERT_DEBUG(aTime>=0);
1.118 + TInt irq=NKern::DisableAllInterrupts();
1.119 + if (iState!=EIdle)
1.120 + {
1.121 + NKern::RestoreInterrupts(irq);
1.122 + return KErrInUse;
1.123 + }
1.124 + iCompleteInDfc = 0;
1.125 + iFunction = NULL;
1.126 + iPtr = (TAny*) &aDfc;
1.127 + iTriggerTime=TheTimerQ.iMsCount+(TUint32)aTime;
1.128 + TheTimerQ.Add(this);
1.129 + NKern::RestoreInterrupts(irq);
1.130 + return KErrNone;
1.131 + }
1.132 +
1.133 +
1.134 +/** Starts a nanokernel timer in zero-drift periodic mode with ISR or DFC callback.
1.135 +
1.136 + Queues the timer to expire in the specified number of nanokernel ticks,
1.137 + measured from the time at which it last expired. This allows exact periodic
1.138 + timers to be implemented with no drift caused by delays in requeueing the
1.139 + timer.
1.140 +
1.141 + The expiry handler will be called in the same context as the previous timer
1.142 + expiry. Generally the way this is used is that NTimer::OneShot() is used to start
1.143 + the first time interval and this specifies whether the callback is in ISR context
1.144 + or in the context of the nanokernel timer thread (DfcThread1) or other Dfc thread.
1.145 + The expiry handler then uses NTimer::Again() to requeue the timer.
1.146 +
1.147 + @param aTime Timeout in nanokernel ticks
1.148 +
1.149 + @return KErrNone if no error; KErrInUse if timer is already active;
1.150 + KErrArgument if the requested expiry time is in the past.
1.151 +
1.152 + @pre Any context
1.153 + */
1.154 +EXPORT_C TInt NTimer::Again(TInt aTime)
1.155 +//
1.156 +// Wait aTime from last trigger time - used for periodic timers
1.157 +//
1.158 + {
1.159 + __NK_ASSERT_DEBUG(aTime>0);
1.160 + TInt irq=NKern::DisableAllInterrupts();
1.161 + if (iState!=EIdle)
1.162 + {
1.163 + NKern::RestoreInterrupts(irq);
1.164 + return KErrInUse;
1.165 + }
1.166 + TUint32 nextTick=TheTimerQ.iMsCount;
1.167 + TUint32 trigger=iTriggerTime+(TUint32)aTime;
1.168 + TUint32 d=trigger-nextTick;
1.169 + if (d>=0x80000000)
1.170 + {
1.171 + NKern::RestoreInterrupts(irq);
1.172 + return KErrArgument; // requested time is in the past
1.173 + }
1.174 + iTriggerTime=trigger;
1.175 + TheTimerQ.Add(this);
1.176 + NKern::RestoreInterrupts(irq);
1.177 + return KErrNone;
1.178 + }
1.179 +
1.180 +
1.181 +/** Cancels a nanokernel timer.
1.182 +
1.183 + Removes this timer from the nanokernel timer queue. Does nothing if the
1.184 + timer is inactive or has already expired.
1.185 + Note that if the timer was queued and DFC callback requested it is possible
1.186 + for the expiry handler to run even after Cancel() has been called. This will
1.187 + occur in the case where DfcThread1 is preempted just before calling the
1.188 + expiry handler for this timer and the preempting thread/ISR/IDFC calls
1.189 + Cancel() on the timer.
1.190 +
1.191 + @pre Any context
1.192 + @return TRUE if timer was actually cancelled
1.193 + @return FALSE if timer was not cancelled - this could be because it was not
1.194 + active or because its expiry handler was already running on
1.195 + another CPU or in the timer DFC.
1.196 + */
1.197 +EXPORT_C TBool NTimer::Cancel()
1.198 + {
1.199 + TBool result = TRUE;
1.200 + TInt irq=NKern::DisableAllInterrupts();
1.201 + if (iState>ETransferring) // idle or transferring timers are not on a queue
1.202 + Deque();
1.203 + switch (iState)
1.204 + {
1.205 + case ETransferring: // signal DFC to abort this iteration
1.206 + TheTimerQ.iTransferringCancelled=TRUE;
1.207 + break;
1.208 + case ECritical: // signal DFC to abort this iteration
1.209 + TheTimerQ.iCriticalCancelled=TRUE;
1.210 + break;
1.211 + case EFinal:
1.212 + {
1.213 + // Need to clear bit in iPresent if both final queues now empty
1.214 + // NOTE: Timer might actually be on the completed queue rather than the final queue
1.215 + // but the check is harmless in any case.
1.216 + TInt i=iTriggerTime & NTimerQ::ETimerQMask;
1.217 + NTimerQ::STimerQ& q=TheTimerQ.iTickQ[i];
1.218 + if (q.iIntQ.IsEmpty() && q.iDfcQ.IsEmpty())
1.219 + TheTimerQ.iPresent &= ~(1<<i);
1.220 + break;
1.221 + }
1.222 + case EIdle: // nothing to do
1.223 + result = FALSE;
1.224 + case EHolding: // just deque
1.225 + case EOrdered: // just deque
1.226 + break;
1.227 + }
1.228 + iState=EIdle;
1.229 + NKern::RestoreInterrupts(irq);
1.230 + return result;
1.231 + }
1.232 +#endif
1.233 +
1.234 +
1.235 +/** Check if a nanokernel timer is pending or not
1.236 +
1.237 + @return TRUE if the timer is pending (OneShot() etc. would return KErrInUse)
1.238 + @return FALSE if the timer is idle (OneShot() etc. would succeed)
1.239 + @pre Any context
1.240 +
1.241 + @publishedPartner
1.242 + @prototype
1.243 + */
1.244 +EXPORT_C TBool NTimer::IsPending()
1.245 + {
1.246 + return iState != EIdle;
1.247 + }
1.248 +
1.249 +
1.250 +/** Obtains the address of the nanokernel timer queue object.
1.251 +
1.252 + Not intended for general use. Intended only for base ports in order to get
1.253 + the address used to call NTimerQ::Tick() with.
1.254 +
1.255 + @return The address of the nanokernel timer queue object
1.256 + @pre Any context
1.257 + */
1.258 +EXPORT_C TAny* NTimerQ::TimerAddress()
1.259 + {
1.260 + return &TheTimerQ;
1.261 + }
1.262 +
1.263 +NTimerQ::NTimerQ()
1.264 + : iDfc(NTimerQ::DfcFn,this,NULL,KTimerQDfcPriority)
1.265 + {
1.266 + // NOTE: All other members are initialised to zero since the single instance
1.267 + // of NTimerQ resides in .bss
1.268 + }
1.269 +
1.270 +void NTimerQ::Init1(TInt aTickPeriod)
1.271 + {
1.272 + TheTimerQ.iTickPeriod=aTickPeriod;
1.273 + __KTRACE_OPT(KBOOT,DEBUGPRINT("NTimerQ::Init1 - period %d us",aTickPeriod));
1.274 + __KTRACE_OPT(KMEMTRACE, DEBUGPRINT("MT:P %d",aTickPeriod));
1.275 + }
1.276 +
1.277 +void NTimerQ::Init3(TDfcQue* aDfcQ)
1.278 + {
1.279 + __KTRACE_OPT(KBOOT,DEBUGPRINT("NTimerQ::Init3 DFCQ at %08x",aDfcQ));
1.280 + TheTimerQ.iDfc.SetDfcQ(aDfcQ);
1.281 + }
1.282 +
1.283 +#ifndef __MSTIM_MACHINE_CODED__
1.284 +void NTimerQ::Add(NTimer* aTimer)
1.285 +//
1.286 +// Internal function to add a timer to the queue.
1.287 +// Enter and return with all interrupts disabled.
1.288 +//
1.289 + {
1.290 + TInt t=TInt(aTimer->iTriggerTime-iMsCount);
1.291 + if (t<ENumTimerQueues)
1.292 + AddFinal(aTimer);
1.293 + else
1.294 + {
1.295 + // >=32ms to expiry, so put on holding queue
1.296 + aTimer->iState=NTimer::EHolding;
1.297 + iHoldingQ.Add(aTimer);
1.298 + }
1.299 + }
1.300 +
1.301 +void NTimerQ::AddFinal(NTimer* aTimer)
1.302 +//
1.303 +// Internal function to add a timer to the corresponding final queue.
1.304 +// Enter and return with all interrupts disabled.
1.305 +//
1.306 + {
1.307 + TInt i=aTimer->iTriggerTime & ETimerQMask;
1.308 + SDblQue* pQ;
1.309 + if (aTimer->iCompleteInDfc)
1.310 + pQ=&iTickQ[i].iDfcQ;
1.311 + else
1.312 + pQ=&iTickQ[i].iIntQ;
1.313 + iPresent |= (1<<i);
1.314 + aTimer->iState=NTimer::EFinal;
1.315 + pQ->Add(aTimer);
1.316 + }
1.317 +
1.318 +void NTimerQ::DfcFn(TAny* aPtr)
1.319 + {
1.320 + ((NTimerQ*)aPtr)->Dfc();
1.321 + }
1.322 +
1.323 +void NTimerQ::Dfc()
1.324 +//
1.325 +// Do deferred timer queue processing and/or DFC completions
1.326 +//
1.327 + {
1.328 + TInt irq;
1.329 +
1.330 + // First transfer entries on the Ordered queue to the Final queues
1.331 + FOREVER
1.332 + {
1.333 + irq=NKern::DisableAllInterrupts();
1.334 + if (iOrderedQ.IsEmpty())
1.335 + break;
1.336 + NTimer* pC=(NTimer*)iOrderedQ.First();
1.337 + TInt remain=pC->iTriggerTime-iMsCount;
1.338 + if (remain>=ENumTimerQueues)
1.339 + break;
1.340 +
1.341 + // If remaining time <32 ticks, add it to final queue;
1.342 + // also if remain < 0 we've 'missed it' so add to final queue.
1.343 + pC->Deque();
1.344 + AddFinal(pC);
1.345 + NKern::RestoreInterrupts(irq);
1.346 + __DEBUG_CALLBACK(0);
1.347 + }
1.348 + NKern::RestoreInterrupts(irq);
1.349 + __DEBUG_CALLBACK(1);
1.350 +
1.351 + // Next transfer entries on the Holding queue to the Ordered queue or final queue
1.352 + FOREVER
1.353 + {
1.354 + irq=NKern::DisableAllInterrupts();
1.355 + if (iHoldingQ.IsEmpty())
1.356 + break;
1.357 + NTimer* pC=(NTimer*)iHoldingQ.First();
1.358 + pC->Deque();
1.359 + pC->iState=NTimer::ETransferring;
1.360 + iTransferringCancelled=FALSE;
1.361 + TUint32 trigger=pC->iTriggerTime;
1.362 + if (TInt(trigger-iMsCount)<ENumTimerQueues)
1.363 + {
1.364 + // <32ms remaining so put it on final queue
1.365 + AddFinal(pC);
1.366 + }
1.367 + else
1.368 + {
1.369 + FOREVER
1.370 + {
1.371 + NKern::RestoreInterrupts(irq);
1.372 + __DEBUG_CALLBACK(2);
1.373 +
1.374 + // we now need to walk ordered queue to find correct position for pC
1.375 + SDblQueLink* anchor=&iOrderedQ.iA;
1.376 + iCriticalCancelled=FALSE;
1.377 + irq=NKern::DisableAllInterrupts();
1.378 + NTimer* pN=(NTimer*)iOrderedQ.First();
1.379 + while (pN!=anchor && !iTransferringCancelled)
1.380 + {
1.381 + if ((pN->iTriggerTime-trigger)<0x80000000u)
1.382 + break; // insert before pN
1.383 + pN->iState=NTimer::ECritical;
1.384 + NKern::RestoreInterrupts(irq);
1.385 + __DEBUG_CALLBACK(3);
1.386 + irq=NKern::DisableAllInterrupts();
1.387 + if (iCriticalCancelled)
1.388 + break;
1.389 + pN->iState=NTimer::EOrdered;
1.390 + pN=(NTimer*)pN->iNext;
1.391 + }
1.392 +
1.393 + if (iTransferringCancelled)
1.394 + break; // this one has been cancelled, go on to next one
1.395 + if (!iCriticalCancelled)
1.396 + {
1.397 + pC->InsertBefore(pN);
1.398 + pC->iState=NTimer::EOrdered;
1.399 + break; // done this one
1.400 + }
1.401 + }
1.402 + }
1.403 + NKern::RestoreInterrupts(irq);
1.404 + __DEBUG_CALLBACK(4);
1.405 + }
1.406 + NKern::RestoreInterrupts(irq);
1.407 + __DEBUG_CALLBACK(5);
1.408 +
1.409 + // Finally do call backs for timers which requested DFC callback
1.410 + FOREVER
1.411 + {
1.412 + irq=NKern::DisableAllInterrupts();
1.413 + if (iCompletedQ.IsEmpty())
1.414 + break;
1.415 + NTimer* pC=(NTimer*)iCompletedQ.First();
1.416 + pC->Deque();
1.417 + pC->iState=NTimer::EIdle;
1.418 + TAny* p=pC->iPtr;
1.419 + NTimerFn f=pC->iFunction;
1.420 + NKern::RestoreInterrupts(irq);
1.421 + __DEBUG_CALLBACK(7);
1.422 + (*f)(p);
1.423 + }
1.424 + NKern::RestoreInterrupts(irq);
1.425 + }
1.426 +
1.427 +
1.428 +/** Tick over the nanokernel timer queue.
1.429 + This function should be called by the base port in the system tick timer ISR.
1.430 + It should not be called at any other time.
1.431 + The value of 'this' to pass is the value returned by NTimerQ::TimerAddress().
1.432 +
1.433 + @see NTimerQ::TimerAddress()
1.434 + */
1.435 +EXPORT_C void NTimerQ::Tick()
1.436 + {
1.437 +#ifdef _DEBUG
1.438 + // If there are threads waiting to be released by the tick, enqueue the dfc
1.439 + if (!TheScheduler.iDelayedQ.IsEmpty())
1.440 + TheScheduler.iDelayDfc.Add();
1.441 +#endif
1.442 + TheScheduler.TimesliceTick();
1.443 + TInt irq=NKern::DisableAllInterrupts();
1.444 + TInt i=iMsCount & ETimerQMask;
1.445 + iMsCount++;
1.446 + STimerQ* pQ=iTickQ+i;
1.447 + iPresent &= ~(1<<i);
1.448 + TBool doDfc=FALSE;
1.449 + if (!pQ->iDfcQ.IsEmpty())
1.450 + {
1.451 + // transfer DFC completions to completed queue and queue DFC
1.452 + iCompletedQ.MoveFrom(&pQ->iDfcQ);
1.453 + doDfc=TRUE;
1.454 + }
1.455 + if ((i&(ETimerQMask>>1))==0)
1.456 + {
1.457 + // Every 16 ticks we check if a DFC is required.
1.458 + // This allows a DFC latency of up to 16 ticks before timers are missed.
1.459 + if (!iHoldingQ.IsEmpty())
1.460 + doDfc=TRUE; // if holding queue nonempty, queue DFC to sort
1.461 + else if (!iOrderedQ.IsEmpty())
1.462 + {
1.463 + // if first ordered queue entry expires in <32ms, queue the DFC to transfer
1.464 + NTimer* pC=(NTimer*)iOrderedQ.First();
1.465 +#ifdef __EPOC32__
1.466 + __ASSERT_WITH_MESSAGE_DEBUG(iMsCount<=pC->iTriggerTime, "iMsCount has exceeded pC->iTriggerTime; function called later than expected ","NTimerQ::Tick()");
1.467 +#endif
1.468 + if (TInt(pC->iTriggerTime-iMsCount)<ENumTimerQueues)
1.469 + doDfc=TRUE;
1.470 + }
1.471 + }
1.472 + if (!pQ->iIntQ.IsEmpty())
1.473 + {
1.474 + // transfer ISR completions to a temporary queue
1.475 + // careful here - higher priority interrupts could dequeue timers!
1.476 + SDblQue q(&pQ->iIntQ,0);
1.477 + while(!q.IsEmpty())
1.478 + {
1.479 + NTimer* pC=(NTimer*)q.First();
1.480 + pC->Deque();
1.481 + pC->iState=NTimer::EIdle;
1.482 + NKern::RestoreInterrupts(irq);
1.483 + if (pC->iFunction)
1.484 + (*pC->iFunction)(pC->iPtr);
1.485 + else
1.486 + ((TDfc*)(pC->iPtr))->Add();
1.487 + irq=NKern::DisableAllInterrupts();
1.488 + }
1.489 + }
1.490 + NKern::RestoreInterrupts(irq);
1.491 + if (doDfc)
1.492 + iDfc.Add();
1.493 + }
1.494 +
1.495 +
1.496 +/** Return the number of ticks before the next nanokernel timer expiry.
1.497 + May on occasion return a pessimistic estimate (i.e. too low).
1.498 + Used by base port to disable the system tick interrupt when the system
1.499 + is idle.
1.500 +
1.501 + @return The number of ticks before the next nanokernel timer expiry.
1.502 +
1.503 + @pre Interrupts must be disabled.
1.504 +
1.505 + @post Interrupts are disabled.
1.506 + */
1.507 +EXPORT_C TInt NTimerQ::IdleTime()
1.508 + {
1.509 + CHECK_PRECONDITIONS(MASK_INTERRUPTS_DISABLED,"NTimerQ::IdleTime");
1.510 +#ifdef _DEBUG
1.511 + // If there are threads waiting to be released by the tick we can't idle
1.512 + if (!TheScheduler.iDelayedQ.IsEmpty())
1.513 + return 1;
1.514 +#endif
1.515 + NTimerQ& m=TheTimerQ;
1.516 + TUint32 next=m.iMsCount; // number of next tick
1.517 + TUint32 p=m.iPresent;
1.518 + TInt r=KMaxTInt;
1.519 + if (p)
1.520 + {
1.521 + // Final queues nonempty
1.522 + TInt nx=next&0x1f; // number of next tick modulo 32
1.523 + p=(p>>nx)|(p<<(32-nx)); // rotate p right by nx (so lsb corresponds to next tick)
1.524 + r=__e32_find_ls1_32(p); // find number of zeros before LS 1
1.525 + }
1.526 + if (!m.iHoldingQ.IsEmpty())
1.527 + {
1.528 + // Sort operation required - need to process next tick divisible by 16
1.529 + TInt nx=next&0x0f; // number of next tick modulo 16
1.530 + TInt r2=nx?(16-nx):0; // number of ticks before next divisible by 16
1.531 + if (r2<r)
1.532 + r=r2;
1.533 + }
1.534 + if (!m.iOrderedQ.IsEmpty())
1.535 + {
1.536 + // Timers present on ordered queue
1.537 + NTimer* pC=(NTimer*)m.iOrderedQ.First();
1.538 + TUint32 tt=pC->iTriggerTime;
1.539 + tt=(tt&~0x0f)-16; // time at which transfer to final queue would occur
1.540 + TInt r3=(TInt)(tt-next);
1.541 + if (r3<r)
1.542 + r=r3;
1.543 + }
1.544 + return r;
1.545 + }
1.546 +#endif
1.547 +
1.548 +
1.549 +/** Advance the nanokernel timer queue by the specified number of ticks.
1.550 + It is assumed that no timers expire as a result of this.
1.551 + Used by base port when system comes out of idle mode after disabling the
1.552 + system tick interrupt to bring the timer queue up to date.
1.553 +
1.554 + @param aTicks Number of ticks skipped due to tick suppression
1.555 +
1.556 + @pre Interrupts must be disabled.
1.557 +
1.558 + @post Interrupts are disabled.
1.559 + */
1.560 +EXPORT_C void NTimerQ::Advance(TInt aTicks)
1.561 + {
1.562 + CHECK_PRECONDITIONS(MASK_INTERRUPTS_DISABLED,"NTimerQ::Advance");
1.563 + TheTimerQ.iMsCount+=(TUint32)aTicks;
1.564 + }
1.565 +
1.566 +
1.567 +/** Returns the period of the nanokernel timer.
1.568 + @return Period in microseconds
1.569 + @pre any context
1.570 + @see NTimer
1.571 + */
1.572 +EXPORT_C TInt NKern::TickPeriod()
1.573 + {
1.574 + return TheTimerQ.iTickPeriod;
1.575 + }
1.576 +
1.577 +
1.578 +/** Converts a time interval to timer ticks.
1.579 +
1.580 + @param aMilliseconds time interval in milliseconds.
1.581 + @return Number of nanokernel timer ticks. Non-integral results are rounded up.
1.582 +
1.583 + @pre aMilliseconds should be <=2147483 to avoid integer overflow.
1.584 + @pre any context
1.585 + */
1.586 +EXPORT_C TInt NKern::TimerTicks(TInt aMilliseconds)
1.587 + {
1.588 + __ASSERT_WITH_MESSAGE_DEBUG(aMilliseconds<=2147483,"aMilliseconds should be <=2147483","NKern::TimerTicks");
1.589 + TUint32 msp=TheTimerQ.iTickPeriod;
1.590 + if (msp==1000) // will be true except on pathological hardware
1.591 + return aMilliseconds;
1.592 + TUint32 us=(TUint32)aMilliseconds*1000;
1.593 + return (us+msp-1)/msp;
1.594 + }
1.595 +