Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 17
Текст из файла (страница 17)
You can read more about this inSection 5.2.1.3.EKA2 also provides each Symbian OS thread with:• Access to a set of executive functions to enable user-mode threads togain access to kernel functionality• An exception handler, which enables the kernel to handle exceptionsin user-mode threads (typically caused by programming errors)• An exit handler, which allows resources to be freed and other threadsto be notified when a thread terminates.SYMBIAN OS THREADS63Symbian OS threadiUserStackRunAddressUser-mode stackiSupervisorStackSupervisor stacknano-threadFigure 3.1 Stacks for a user-mode Symbian OS thread3.3.1 Symbian OS thread creation3.3.1.1 Creating a thread: 1User-mode code creates a Symbian OS thread by calling RThread::Create().
By default, this method creates a thread belonging to thecurrent process, and returns an open handle to the newly created threadback to the caller.The RThread::Create() method goes via an exec call (see Chapter5, Kernel Services) to the kernel, where it ends up inside the methodDThread::Create(SThreadCreateInfo&aInfo).SThreadCreateInfoThe basic SThreadCreateInfo structure looks like this:struct SThreadCreateInfo{TAny* iHandle;TInt iType;TThreadFunction iFunction;TAny* iPtr;TAny* iSupervisorStack;TInt iSupervisorStackSize;TAny* iUserStack;TInt iUserStackSize;TInt iInitialThreadPriority;TPtrC iName;TInt iTotalSize;// Size including any extras};64THREADS, PROCESSES AND LIBRARIESKey member data of SThreadCreateInfoiHandleHandle on thread, returned to caller.iTypeType of thread (EThreadInitial, EThreadSupervisor, EThreadMinimalSupervisor or EThreadUser). Indicates whether thread canexecute in user mode and whether creation should be fast or normal.iFunctionWhere to begin execution of this thread.iPtrThe pointer passed as an argument to iFunction.iSupervisorStackPointer to supervisor stack.
If 0, a stack will be created for it.iSupervisorStackSizeSize of supervisor stack. Zero means to use the default value of 4 KB.iUserStackPointer to user stack. This is returned to caller, not passed in.iUserStackSizeSize of user stack. Zero means to use the default value of 8 KB.iInitialThreadPriorityInitial priority for this thread.iNameName of the thread. If this is non-zero then the thread is a global object.iTotalSizeSize including any extras. This must be a multiple of 8 bytes.SStdEpocThreadCreateInfoThe basic SThreadCreateInfo structure is then derived by SStdEpocThreadCreateInfo to provide three more fields, like so:struct SStdEpocThreadCreateInfo : public SThreadCreateInfo{RAllocator* iAllocator;TInt iHeapInitialSize;TInt iHeapMaxSize;TInt iPadding; // Make size a multiple of 8 bytes};This structure adds a pointer to the RAM allocator and an initial and amaximum size for the heap.
It forms the control block that is pushed ontoa thread’s stack before that thread starts. The extra fields are used by theSYMBIAN OS THREADS65standard entry point function to set up the thread’s heap – the kernel doesnot use them itself.We chose to derive from SThreadCreateInfo so that we couldsupport other kinds of threads in personality layers.
Those new types ofthread would probably need to pass different parameters to the thread’sentry point instead. The authors of the personality layer can do this easily,by deriving a new class from SThreadCreateInfo.3.3.1.2 Creating a thread: 2The DThread constructor sets the state of the new thread to ECreated.The thread stays in this state throughout the construction process, then,once the thread is completely constructed, the kernel changes its status toEReady. This ensures that there are no anomalies arising from the deathof a partly created thread.Then the DThread::Create() method creates a user stack for thethread. To find out more about where in memory we create the thread’sstack, see Chapter 7, Memory Models.Next DThread::Create() calls DThread::DoCreate().
Thismethod continues the work of setting up the thread, callingNKern::ThreadCreate() to create the nanokernel portion of theSymbian OS thread.On return from DoCreate(), DThread::Create() adds the threadto the object container for threads (assuming it is neither the initial thread,nor a minimal supervisor thread). For more on object containers, seeChapter 5, Kernel Services.When the Symbian OS thread first starts to run, it executes__StartThread. This calls DThread::EpocThreadFunction(),which checks to see if the thread is a kernel or user thread.If it is a kernel thread, then DThread::EpocThreadFunction()calls the thread function – this is the function that the caller specified inKern::ThreadCreate().If it is a user thread, then the thread creation information is copiedto the user stack.
Then the CPU is switched to user mode and the process’sentry point is called, with a parameter that is eitherKModuleEntryReasonProcessInit for the first thread in the process,or KModuleEntryReasonThreadInit for subsequent threads.The process’s entry point is __E32Startup in e32\euser\epoc\arm\uc_exe.cia. This code compiles into eexe.lib – Symbian’sequivalent of crt0.obj on Windows.The process entry point then calls RunThread(), which calls UserHeap::SetupThreadHeap(). This is the function that will create thethread’s heap if required.Then, if this is the first thread in the process, the constructors forstatic data are called before calling E32Main().
Otherwise, the threadfunction is called straight away.66THREADS, PROCESSES AND LIBRARIES3.3.1.3 Over-riding the Symbian OS allocatorsYou may have noticed that EKA2 does not create the thread’s heap.Instead, threads create their own heaps (or share an existing heap)when they first run. This makes it possible for the process itself to hookin and over-ride the normal heap creation function. In this way, youcan choose to make a particular process use a memory allocator otherthan the standard one that Symbian provides in EUSER. You can alsoinsert additional heap tracking or diagnostic functions. However, youshould note that the function UserHeap::SetupThreadHeap() mustbe in a static library if you want to automatically over-ride heap creation in a process; the code for the RAllocator-derived class canbe in a DLL.
You do need to be careful when over-riding UserHeap::SetupThreadHeap(), because it is called before static data isinitialized.3.3.2 The DThread classAs we’ve already seen, the DThread class represents a Symbian OSthread. Now let’s find out a little more about it. DThread derives fromDObject, which makes it a dynamically allocated reference countedobject inside the kernel (see Chapter 5, Kernel Services, for more onthis). The DThread has an embedded nanothread (iNThread), whichenables the nanokernel to schedule it.We then derive the DThread class further to give a concrete CPU/MMU specific class – on ARM CPUs this is called DArmPlatThread.DArmPlatThread contains some CPU specifics but in general, it doesnot add much functionality to DThread.Here is a cut-down version of the DThread class to give you a flavorfor the kind of thing it includes:class DThread : public DObject{public:enum {EDefaultUserTimeSliceMs = 20};enum TThreadState{ECreated,EDead,EReady,EWaitSemaphore,EWaitSemaphoreSuspended,EWaitMutex,EWaitMutexSuspended,EHoldMutexPending,EWaitCondVar,EWaitCondVarSuspended,};SYMBIAN OS THREADSenum TOperation{ESuspend=0,EResume=1,EForceResume=2,EReleaseWait=3,EChangePriority=4,};public:DThread();void Destruct();TInt Create(SThreadCreateInfo& aInfo);TInt SetPriority(TThreadPriority aPriority);IMPORT_C void RequestComplete(TRequestStatus*& aStatus,TInt aReason);IMPORT_C TInt DesRead(const TAny* aPtr, TUint8* aDes,TInt aMax, TInt aOffset, TInt aMode);IMPORT_C TInt DesWrite(const TAny* aPtr, const TUint8* aDes,TInt aLength, TInt aOffset, TInt aMode,DThread* aOriginatingThread);// not memory model dependentTInt DoCreate(SThreadCreateInfo& aInfo);IMPORT_C void SetThreadPriority(TInt aThreadPriority);void SetDefaultPriority(TInt aDefaultPriority);void AbortTimer(TBool aAbortAbsolute);void Suspend(TInt aCount);void Resume();void ForceResume();void Exit();void Die(TExitType aType, TInt aReason,const TDesC& aCategory);TInt Logon(TRequestStatus* aStatus, TBool aRendezvous);void Rendezvous(TInt aReason);// memory model dependentTInt AllocateSupervisorStack();void FreeSupervisorStack();void FreeUserStack();TInt AllocateUserStack(TInt aSize);TInt RawRead(const TAny* aSrc, TAny* aDest, TInt aLength,TInt aFlags);TInt RawWrite(const TAny* aDest, const TAny* aSrc,TInt aLength, TInt aFlags, DThread* aOriginatingThread);DChunk* OpenSharedChunk(const TAny* aAddress, TBool aWrite,TInt& aOffset)static void DefaultUnknownStateHandler(DThread* aThread,TInt& aOperation, TInt aParameter);static void EpocThreadFunction(TAny* aPtr);static TDfc* EpocThreadExitHandler(NThread* aThread);static void EpocThreadTimeoutHandler(NThread* aThread,TInt aOp);public:TUint32 iIpcCount;TLinAddr iUserStackRunAddress;6768THREADS, PROCESSES AND LIBRARIESTInt iUserStackSize;TUint32 iFlags;DProcess* iOwningProcess;SDblQueLink iProcessLink;TInt iThreadPriority;DObjectIx* iHandles;TUint iId;RAllocator* iAllocator;RAllocator* iCreatedAllocator;TTrap* iFrame;TTrapHandler* iTrapHandler;RArray<STls> iTls;CActiveScheduler* iScheduler;TExceptionHandler iExceptionHandler;TUint iExceptionMask;TExcTrap* iExcTrap;TInt iDebugMask;TThreadMessage iKernMsg;DObject* iTempObj;DObject* iExtTempObj;TAny* iTempAlloc;SDblQue iOwnedLogons;SDblQue iTargetLogons;RMessageK iSyncMsg;TDfc iKillDfc;SDblQue iClosingLibs;TPriListLink iWaitLink;TInt iDefaultPriority; // default scheduling priorityTAny* iWaitObj; // object on which this thread is waiting// handler for extra thread states - used by RTOS// personality layersTUnknownStateHandler iUnknownStateHandler;// pointer to extra data used by RTOS personality layersTAny* iExtras;TAny* iSupervisorStack;// thread’s supervisor mode stackTInt iSupervisorStackSize;TUint8 iSupervisorStackAllocated;TUint8 iThreadType;TUint8 iExitType;TUint8 iPad1;TInt iExitReason;TBufC<KMaxExitCategoryName> iExitCategory;// list of held mutexes, used only for acquisition// order checkingSDblQue iMutexList;// things to clean up when we dieTPriList<TThreadCleanup,KNumPriorities> iCleanupQ;TTimer iTimer;NThread iNThread;};Key member data of DThreadiFlagsThread flags (system critical, last chance, process permanent, original).iExitTypeTop level thread exit reason (kill, terminate or panic) or EExitPendingif thread still running.SYMBIAN OS THREADS69iExitReasonExit code (return value from thread main function or reason supplied tokill, terminate or panic call).iExitCategoryString providing additional exit information in case of panic.iThreadTypeType of thread: EThreadInitial, EThreadSupervisor, EThreadMinimalSupervisor or EThreadUser.iOwningProcessPointer to DProcess object that represents the process to which thisthread belongs.iThreadPriorityPriority of this thread in either absolute or process-relative form.