Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 43
Текст из файла (страница 43)
In fact, the bottomlayer of the memory model is both CPU- and MMU-specific, as well asspecific to the type of memory model.The key class that the memory model provides is ArmMmu (or X86Mmuon X86 processors). This class is derived from Mmu, which in its turn isderived from MmuBase. The methods provided by this class allow thestandard MMU operations, such as the mapping and unmapping of pages,the changing of page permissions and so on.
Here are a few examples:virtual void Map(TLinAddr aLinAddr, TPhysAddr aPhysAddr, TInt aSize,TPde aPdePerm, TPte aPtePerm, TInt aMapShift);194KERNEL SERVICESvirtual void Unmap(TLinAddr aLinAddr, TInt aSize);virtual void ApplyTopLevelPermissions(TLinAddr anAddr, TUint aChunkSize,TPde aPermissions);Key concrete classesAt this level, you can see MMU-specific portions of key Symbian OSclasses, namely DArmPlatThread, DArmPlatChunk and DArmPlatProcess.5.4.5 Variant layerThe variant provides the hardware-specific implementation of the controlfunctions expected by the nanokernel and Symbian OS kernel.The class Asic, provided in assp.h, contains pure virtual APIs, whichare to be provided by the variant and called by the CPU layer. So, if youare creating a variant, you would derive it from the Asic class:class Asic{public:// initialisationvirtual TMachineStartupType StartupReason()=0;virtual void Init1()=0;virtual void Init3()=0;// debugvirtual void DebugOutput(TUint aChar)=0;// power managementvirtual void Idle()=0;//virtualvirtualvirtualvirtualtimingTInt MsTickPeriod()=0;TInt SystemTimeInSecondsFrom2000(TInt& aTime)=0;TInt SetSystemTimeInSecondsFrom2000(Tint aTime)=0;TUint32 NanoWaitCalibration()=0;// HALvirtual TInt VariantHal(TInt aFunction, TAny* a1, TAny* a2)=0;// Machine configurationvirtual TPtr8 MachineConfiguration()=0;};The variant provides other interfaces that are available for use bydevice drivers and extensions.
A key example is the Interrupt classprovided in assp.h:class Interrupt{TIMERSpublic:IMPORT_CIMPORT_CIMPORT_CIMPORT_CIMPORT_CIMPORT_C};staticstaticstaticstaticstaticstaticTIntTIntTIntTIntTIntTInt195Bind(TInt aId, TIsr aIsr, TAny* aPtr);Unbind(TInt aId);Enable(TInt aId);Disable(TInt aId);Clear(TInt aId);SetPriority(TInt aId, TInt aPriority);The variant performs interrupt dispatch for the system; the methods inthe Interrupt class allow device drivers and extensions to install theirown interrupt handlers.The CPU layer can also provide hardware-specific implementations ofHAL functions, although these may equally be implemented in the kernelitself or in an extension.5.5 TimersTimers are both a fundamental need for the functioning of EKA2, and aservice that EKA2 provides to its users.
In this section, I will discuss thedetailed operation of nanokernel and Symbian OS timers.5.5.1 Nanokernel timersEarlier in this chapter, I said that nanokernel timers, NTimer, provide themost fundamental system timing functions in the operating system. Let’slook now at how they are implemented.The main requirements for NTimer are:• Timers can be started and stopped from any kernel code – ISRs, IDFCsor threads, so the timer start and stop functions should have smalldeterministic execution times• It should be possible to generate periodic timers with no drift due todelays in servicing the timer• It should be possible to disable the timer tick if the CPU is expectedto be idle for several ticks without affecting the accuracy of the timedintervals, to minimize system power consumption.The timer queue uses 67 separate doubly linked lists. Of these, the 32pairs of final queues hold timers that are due to expire within the next 32ticks.
Of the other three, one is used to support timers whose handlersare called back in a DFC (the completed queue) and the other two (the196KERNEL SERVICESholding queue and the ordered queue) hold timers which are due toexpire more than 32 ticks in the future.The timer queue contains a tick count, which is incremented on everytick interrupt. The tick count modulo 32 determines which of the 32 pairsof linked lists is checked on that tick.
One list of the pair holds timersthat require the handler to be called at the end of the tick ISR itself, andthe other holds timers that require the handler to be called from a DFCfollowing the tick interrupt. This second list, if non-empty, is appended tothe end of the completed queue and the timer DFC is queued to processthe callbacks. A 32-bit mask is also maintained – this corresponds to the32 pairs of final queues, with one bit representing each pair.
A bit is setif either of the corresponding pair of final queues has an entry.If a timer is queued for a time less than 33 ticks in the future, the kerneljust places that timer on the respective final queue. Timers that are queuedfor more than 32 ticks in the future are placed on the holding queue inFIFO order. Every 16 ticks, the tick interrupt service routine checks theholding queue, and if it is not empty, queues the timer DFC. This transfersany timers on the holding queue that are now due to expire in less than33 ticks to their respective final queue.
It transfers timers that still expirein more than 32 ticks to the ordered queue. As its name implies, entrieson this queue always appear in increasing order of expiry time.The timer DFC also drains the ordered queue. Every 16 ticks theinterrupt service routine checks the ordered queue; if this is non-emptyand the first entry expires in less than 33 ticks, then the ISR queues aDFC. The DFC will then walk the ordered queue, transferring entries tothe final queues, until it reaches the end of the ordered queue or reachesan entry that expires in more than 32 ticks.The kernel uses the ordered queue, in combination with the bit maskfor the final queues and the holding queue, to determine the number ofticks until the next timer queue operation.
In fact, this would generally bedone in the null (idle) thread, just before it puts the CPU into idle mode.The null thread can then disable the timer tick for that number of ticks,allowing the CPU to sleep undisturbed for longer, and possibly allowing alower-power sleep mode to be used. The bit mask for final queues is usedto determine the number of ticks before the next final queue expiry. If theholding queue is non-empty, the number of ticks before the sort operationis calculated from the tick number – the sort operation is triggered if thetick count is zero modulo 16. If the ordered queue is non-empty, the timeat which transfer of the first entry (that is, the one that expires first) to therelevant final queue would occur is calculated. The minimum of thesethree time values gives the number of ticks that can be skipped. It can beseen that this calculation has a small, predictable execution time, whichis just as well since it will be done with interrupts disabled.To be able to cancel timers, we need to keep track of which queuea timer is on.
Each timer has a state that gives this information, and theTIMERS197following states are defined:• Idle. The timer is not linked into any queue and is not currently setto expire. However the expiry handler may actually be running. Noaction is required to cancel a timer in this state• Holding. The timer is linked into the holding queue. To cancel atimer in this state, simply remove it from the holding queue• Transferring. The timer is in transit from the holding queue to theordered queue. It is not actually linked into either. To cancel a timerin this state, no dequeuing is needed, but a flag must be set to notifythe timer DFC that the timer currently being transferred has beencanceled. The timer DFC will then abort the transfer• Ordered.
The timer is linked into the ordered queue. To cancel atimer in this state, simply remove it from the ordered queue• Critical. The timer is linked into the ordered queue and is currentlybeing inspected by the timer DFC while transferring another timerfrom the holding queue to its correct position on the ordered queue.To cancel a timer in this state it is removed from the ordered queueand a flag is also set to notify the timer DFC that the current criticaltimer has been canceled. The timer DFC will then restart the sortoperation• Final.
The timer is linked into the final queue corresponding to itsexpiry time. To cancel a timer in this state, first remove it from thequeue, then check the two final queues corresponding to the expirytime of the timer being canceled; if both are now empty, clear thecorresponding bit in the iPresent bit mask.Timers for less than 32 ticks in the future will simply transition from Idleto Final, whereas timers for longer periods will generally transitionthrough all these states.When a timer expires, we set its state back to Idle just before calling the timer handler.
This means that care needs to be taken whencanceling a timer whose expiry handler runs in the timer DFC. If thethread calling Cancel() has a priority above the timer DFC threador Cancel() is called from an ISR or IDFC then Cancel() mayoccur during the execution of the timer handler. Since the state hasbeen set back to Idle, the cancel will not do anything. If the memory containing the timer control block is now freed and reassigned tosomething else, contention may occur with the expiry handler.
This isnot usually a problem since threads of such high priority will not usuallydelete objects. It would, however, be a problem on an SMP systemsince the canceling thread could overlap the handler even if it had alower priority.198KERNEL SERVICESWe provide two functions to start a nanokernel timer:OneShot(aTime, aDfc)This sets a timer for aTime ticks from now.