Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 26
Текст из файла (страница 26)
This is because we can change addressspaces in just a few assembly language instructions.3.6.1 Scheduling of Symbian OS threadAs I said in the previous section, scheduling is the responsibility of thenanokernel, and the scheduler deals in nanothreads, not Symbian OSthreads. Symbian OS only contributes to scheduling in the setting ofthread priorities.The Symbian OS thread class, DThread, has a member iThreadPriority.
This specifies the priority in either absolute or process-relativeform. Values between 0 and 63 inclusive represent absolute priorities (corresponding directly to nanokernel priorities) and negative values between−8 and −2 represent process-relative values (−1 is not used).A call to the user-side API RThread::SetPriority() sets theiThreadPriority field using a value derived from the TThreadPriority argument that is passed to it. The kernel combines theiThreadPriority field with the process priority of the thread’s owning process using a mapping table to produce the iDefaultPriorityfield. The following code shows how this is done.Calculating Thread Priority// Mapping table for thread+process priority to// thread absolute priorityLOCAL_D const TUint8 ThreadPriorityTable[64] ={//Idle MuchLess Less Normal More MuchMore RealTime/*Low*/1, 1, 2, 3, 4, 5, 22, 0,/*Background*/3, 5, 6, 7, 8, 9, 22, 0,/*Foreground*/3, 10, 11, 12, 13, 14, 22, 0,/*High*/3, 17, 18, 19, 20, 22, 23, 0,/*SystemServer1*/9, 15, 16, 21, 24, 25, 28, 0,/*SystemServer2*/9, 15, 16, 21, 24, 25, 28, 0,/*SystemServer3*/9, 15, 16, 21, 24, 25, 28, 0,/*RealTimeServer*/ 18, 26, 27, 28, 29, 30, 31, 0};TInt DThread::CalcDefaultThreadPriority(){TInt r;TInt tp=iThreadPriority;if (tp>=0) // absolute thread prioritiesr=(tp<KNumPriorities)?tp:KNumPriorities-1;elseSCHEDULING109{tp+=8;if (tp<0)tp=0;TInt pp=iOwningProcess->iPriority; // proc priority 0-7TInt i=(pp<<3)+tp;// map thread+process priority to actual priorityr=ThreadPriorityTable[i];return r;}}This iDefaultPriority, returned from CalcDefaultThreadPriority() is the actual scheduling priority used by the thread when itdoesn’t hold a Symbian OS mutex, and so it is not subject to priorityinheritance.What about when the thread does hold a mutex? As we saw inSection 3.3.5.1, the nanokernel priority of a Symbian OS thread is givenby the maximum of its iDefaultPriority value and the maximumpriority of any entry on the thread’s cleanup queue.
Some of the cleanupqueue entries result from mutexes held by the thread and, as we saw, thekernel adjusts their priorities to provide priority inheritance.3.6.2Scheduling in the emulatorAs we saw in Chapter 1, Introducing EKA2, the emulator uses the hostOS (Win32) threads. This means that the nanokernel needs to provide itsown scheduling mechanism as Windows does not provide the 64 prioritylevels we have in Symbian OS. (Win32 only really provides five usabledistinct priorities within a process.)To make this work, we cannot allow Windows to arbitrarily scheduleSymbian OS threads to run.
The nanokernel achieves this by only makingone Symbian OS thread ready to run as a Win32 thread; all the others willeither be waiting on a Win32 event object or suspended. A side effectof this policy is that all Symbian OS threads can have the same standardWin32 priority.3.6.2.1 Disabling preemptionEKA2 provides two mechanisms to disable preemption and rescheduling:1. Masking interrupts – disables interrupt dispatch and thus preemption2.
Locking the kernel – disables preemption and rescheduling.The emulator only has to emulate the first of these, since the second usesthe same implementation as the target mobile phone.110THREADS, PROCESSES AND LIBRARIESWe provide the interrupt mask in the emulator using something similarto a Win32 critical section object. Unlike the RCriticalSection ofSymbian OS, this is re-entrant, allowing a single thread to wait on acritical section multiple times. The key difference to the standard Win32critical section is the ability to operate correctly on a multi-processor PCin conjunction with the emulator’s ‘‘interrupt’’ mechanism.We disable interrupts by entering this critical section. This is effectiveas ’’interrupts’’ must do the same, and so they are blocked until the threadthat owns the critical section releases it (by restoring interrupts).
Thus thisalso prevents a thread being preempted whilst it has masked interrupts,as desired.3.6.2.2 TScheduler::RescheduleThe kernel lock is just a simple counter, rather than the Win32 criticalsection used in EKA1; this allows the emulator to hand over the lockbetween threads when rescheduling exactly as the target scheduler does.The result is that the scheduler code follows the same algorithm as thenanokernel with regards to:• Disabling interrupts• Running IDFCs• Selecting a new thread• Exiting the scheduler.The major difference in scheduling is in the handover code betweenthreads.
Any Symbian OS thread which is not the current thread willeither be waiting on a Win32 event object, the ‘‘reschedule lock’’,or suspended. Suspension is rare, and only occurs if the thread waspreempted rather than voluntarily rescheduling. I discuss preemptionin more detail in the next section; this section will concentrate on thenormal case.The handover from the old (executing) thread is usually done bysignaling the new thread’s reschedule lock and then waiting on the oldone’s lock. The new thread starts running from the same point in the code(because there is only one place where the waiting is done), the kernel isstill locked and the algorithm continues as normal.This is slightly different to the behavior on a real target phone.
Onthe latter, there is no ‘‘waiting’’, as the thread state is saved to its stackbefore the new thread state is restored. The scheduler knows that thereis only one true thread of execution in the CPU and just changes theregister context to effect the switch. But in the emulator we have two‘‘real’’ execution contexts (ours, and the new thread) and we need to giveSCHEDULING111the impression that execution is being directly handed off from one tothe other.Note that blocked threads nearly always have the same functionsat the top of the call stack, SwitchThreads() and TScheduler::Reschedule().Also note that this handover in the emulator works equally well whenthe new thread is the same as the old thread.3.6.2.3 ‘‘Interrupts’’ and preemptionInteraction with the hardware in the emulator is always via the hostOS.
As a result, there are no real interrupts to handle in the emulator.Interaction with the host is always done using native threads, which makeuse of the host OS APIs for timer services, file I/O, UI and so on.The emulator creates a number of Win32 threads to act as ‘‘event’’ or‘‘interrupt’’ sources. These are not Symbian OS threads, therefore theyare effectively unknown to the nanokernel scheduler. They run at a hostpriority above that of the Symbian OS threads to ensure that they respondto events immediately and cause preemption within the emulator.The emulator provides two routines which act as the interrupt preambleand post-amble, StartOfInterrupt() and EndOfInterrupt().The preamble routine, StartOfInterrupt(), disables interrupts andthen suspends the host thread that is the current nanokernel thread.This ensures that the ‘‘interrupt’’ behaves like a real interrupt, executingwhile the current thread does nothing, even on multi-processor PCs.
Thepost-amble routine, EndOfInterrupt(), does something similar to theARM interrupt post-amble on a real phone – checking the kernel lockstate and the need for a reschedule. If a reschedule is needed, the routineleaves the current thread suspended and causes a reschedule, otherwiseit resumes the thread and enables interrupts again.Unlike on a real phone, the end of interrupt function cannot cause thecurrent thread to branch off to the scheduler because it is not safe to diverta Win32 thread from an arbitrary location – this can cause the entire hostOS to hang.