Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 51
Текст из файла (страница 51)
An error code isreturned if the interrupt identifier is invalid or if there is no ISR associatedwith the interrupt source.TInt Interrupt::Enable(TInt aId);This method enables interrupts from the specified interrupt source. Notethat this only enables the interrupt source in the main interrupt controller;further setup in the peripheral itself may be necessary before interruptsINTERRUPTS233can actually occur.
An error code is returned if the interrupt identifieris invalid or if there is no ISR associated with the interrupt source. Aninterrupt may not be enabled if it does not have an ISR associated with it.TInt Interrupt::Disable(TInt aId);This method disables interrupts from the specified interrupt source. Notethat it only disables the interrupt source in the main interrupt controller;the peripheral itself is unaffected. An error code is returned if the interruptidentifier is invalid.TInt Interrupt::Clear(TInt aId);This method clears any pending interrupt from the specified source. Itreturns an error code if the interrupt identifier is invalid. This method israrely used – most interrupts are cleared either implicitly during servicingor explicitly by writing to a hardware register.
For example, a UART receiveinterrupt is usually cleared by reading all available data from the UARTreceive FIFO; a timer interrupt is cleared by writing to an acknowledgment register. The Interrupt::Clear() method is generally only usedwhere the aId value is determined at runtime instead of being hard coded.TInt Interrupt::SetPriority(TInt aId, TInt aPriority);On hardware that supports multiple interrupt priority levels and thatallows interrupt sources to have their priorities set dynamically, this callchanges the hardware priority level of the specified interrupt source. Themethod returns an error code if this functionality is not supported or if theidentifier is invalid. A typical use of this would be on ARM-based systemswhere the interrupt controller allows each interrupt source to be routed toeither IRQ or FIQ.
The board support package and device drivers for sucha platform would call the Interrupt::SetPriority() API duringinitialization to configure the hardware to route each interrupt to eitherIRQ or FIQ as appropriate.6.3.3.2 APIs for IDFCs and DFCsIDFCs and DFCs are both represented by objects of the TDfc class. Thepublic parts of this class are as follows:typedef void (*TDfcFn)(TAny*);class TDfc{public:TDfc(TDfcFn aFn, TAny* aPtr);TDfc(TDfcFn aFn, TAny* aPtr, TInt aPri);234INTERRUPTS AND EXCEPTIONSTDfc(TDfcFn aFn, TAny* aPtr, TDfcQue* aQ, TInt aPri);void Add();void Cancel();void Enque();void Enque(NFastMutex* aMutex);void DoEnque();inline TBool Queued();inline TBool IsIDFC();inline void SetDfcQ(TDfcQue* aQ);inline void SetFunction(TDfcFn aFn);};Now let’s look at these public functions in more detail:TDfc(TDfcFn aFn, TAny* aPtr);Whether the TDfc represents an IDFC or a DFC depends on how itis constructed.
This constructor initializes the TDfc object as an IDFC.Function aFn will be called when the IDFC runs, and aPtr will besupplied as the argument to aFn.TDfc(TDfcFn aFn, TAny* aPtr, TInt aPri);TDfc(TDfcFn aFn, TAny* aPtr, TDfcQue* aQ, TInt aPri);These constructors initialize the TDfc object as a DFC. Function aFnwill be called when the DFC runs and aPtr will be supplied as theargument to it. Parameter aPri specifies the priority of the DFC withinits DFC queue and must be between zero and seven inclusive. ParameteraQ specifies which DFC queue the DFC will run on.
The version of theconstructor without the parameter aQ will initialize the queue pointer toNULL, and the DFC queue to be used must be set with SetDfcQ beforethe DFC can be queued.void Add();This method places an IDFC or a DFC on the IDFC pending queue.The method is idempotent – if the object is already queued, no actionis taken. This method is almost always called from an ISR. It mayalso be called from an IDFC or a thread context with preemption disabled, but it must not be called from a thread context with preemptionenabled.void Cancel();INTERRUPTS235This method removes an IDFC or DFC from any queue it is currently on.If the object is not currently queued, no action is taken. You must onlycall this method from IDFCs or threads, not from ISRs.void Enque();void DoEnque();These methods place a DFC directly on its final queue without goingvia the IDFC pending queue.
They must not be called on a TDfc objectrepresenting an IDFC. Both methods take no action if the DFC is alreadyqueued. You can only call the DoEnque() from an IDFC or a threadcontext with preemption disabled; it is the recommended way to queuea DFC from inside an IDFC. You may also call Enque() from a threadcontext with preemption enabled; it is the recommended way to queue aDFC from a thread.void Enque(NFastMutex* aMutex);This method is equivalent to Enque() followed immediately and atomically by signaling the specified fast mutex. If aMutex is NULL, the systemlock is signaled. The call is atomic in that no reschedule may occurbetween the DFC being queued and the fast mutex being released. Thismethod may only be called from a thread context.The method is useful when both the thread queuing a DFC and theDFC thread itself need to access a data structure protected by a fast mutex.Let’s consider what would happen if it did not exist.
The first thread wouldacquire the mutex, update the structure, queue the DFC and then releasethe mutex. If, as is commonly the case, the DFC thread had the higherpriority, a reschedule would occur immediately after the DFC was queued,with the fast mutex still held. The DFC would immediately try to acquirethe mutex and find it locked, causing another reschedule back to the firstthread. Finally, the first thread would release the fast mutex and therewould be yet another reschedule back to the DFC thread, which couldthen claim the mutex and proceed.
The use of an atomic ‘‘queue DFC andrelease mutex’’ operation eliminates the last two of these reschedules,since the DFC thread does not run until the mutex has been released.TBool IsQueued();This method returns ETrue if the TDfc object is currently on the IDFCpending queue or a DFC final queue.TBool IsIDFC();236INTERRUPTS AND EXCEPTIONSThis method returns ETrue if the TDfc object represents an IDFC,EFalse if it represents a DFC.void SetDfcQ(TDfcQue* aQ);This sets the DFC queue on which a DFC will run.
It is intended for usein conjunction with the TDfc constructor that does not specify a DFCqueue, which is used when the queue is not known at the time the DFCis constructed. For example, this can happen in logical device driverswhere the DLogicalChannelBase-derived object contains embeddedDFCs, which are therefore constructed when the logical channel objectis instantiated. This occurs before the logical channel has been boundto any physical device driver, so if the DFC queue is determined by thephysical device driver, the TDfc::SetDfcQ method must be used tocomplete initialization of the DFCs once the queue is known.The TDfc::SetDfcQ method must only be used on unqueued DFCs;it will not move a queued DFC from one queue to another.void SetFunction(TDfcFn aFn);This sets the callback function to be used by an IDFC or DFC.6.4 Aborts, traps and faultsIn this section, I will describe how Symbian OS handles aborts, trapsand faults, and the uses it makes of them.
I will use the generic term‘‘exceptions’’ from here onwards to cover ‘‘aborts, traps and faults’’.6.4.1 Response to exceptionsAs with interrupts and system calls, the initial and final phases of exceptionhandling occur in the nanokernel. The higher level processing occurs ina per-thread exception handler, which, for Symbian OS threads, is astandard handler in the Symbian OS kernel. Next I shall discuss each ofthese phases in more detail.6.4.1.1 PreambleThe task of the exception preamble is similar to that of the interruptpreamble – to establish the correct context for the exception handlers torun, and to save the state of the system at the point where the exceptionoccurred. However there are two main differences.
The first is that theexception preamble saves the entire integer register set of the processorABORTS, TRAPS AND FAULTS237rather than just the minimum set required to restore the system state. Thereasons for this are:1. Exceptions are often indicative of programming errors, especiallyunder Symbian OS, which doesn’t support demand-paged virtualmemory. Saving the entire register set allows us to generate moreuseful diagnostics2. If an exception is intentional rather than the result of a programmingerror, we often need to modify the processor execution state beforeresuming the original program. For example, to run a user-sideexception handler, we must modify the stack pointer and programcounter of the running thread before resuming3.
Exceptions are quite rare events, so the performance penalty in savingand restoring all registers is acceptable.The second difference from the interrupt preamble is that checks aremade on the state of the system at the point where the exceptionoccurred. Depending on the result of these checks, a kernel fault maybe raised. This is because exceptions, unlike interrupts, are synchronizedwith program execution. Certain critical parts of kernel-side code are notexpected to cause exceptions – if they do, a kernel fault is raised. Thiswill immediately terminate normal system operation and either drop intothe kernel’s post-mortem debugger (if present) or (on a production device)cause the system to reboot.Handling exceptions on ARM processorsOn ARM processors, exceptions cause a transition to mode abt ormode und, and they disable IRQs but not FIQs.