Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 89
Текст из файла (страница 89)
In either case, if the kernel finds that thecode segment is already loaded, it returns a ‘‘code segment handle’’ tothe loader. This is not a standard Symbian OS handle but is actually justthe pointer to the kernel-side DCodeSeg object. The loader then calls420THE LOADERE32Loader::CodeSegInfo() on the returned handle; this populatesthe E32Image object with information about the code segment beingloaded, including full path name, UIDs, attributes, version number, security information, code and data sizes, code and data addresses and exportinformation. The loader then calls E32Loader::CodeSegOpen() onthe handle. This call checks the EMarkLdr flag on the code segment;if this flag is clear, it sets the flag and increments the reference count ofthe code segment.
The E32Loader::CodeSegOpen() function thenperforms the same operation recursively on all code segments in thesub-graph below the original one. At the end of this, the loader has areference on the code segment and on all the code segments upon whichit depends, so these will not be deleted.If the kernel does not find the selected code segment, the loader populates the E32Image object with information read from the E32Imageheader of the selected file.The loader then calls E32Loader::ProcessCreate(), passing inthe E32Image object; the latter derives from TProcessCreateInfo,which contains all the information the kernel needs to create a newprocess.
Figure 10.2 illustrates the relationship of these classes.The kernel-side handler, ExecHandler::ProcessCreate(), verifies that the calling thread belongs to the F32 process and then doessome argument marshaling to pass the parameters over to the kernelside.
It then calls Kern::ProcessCreate() to do the actual work; thisfunction is also used by the startup extension (EXSTART.DLL) to createthe F32 process after the kernel has booted.Actual process creation proceeds as follows:1.The kernel creates an object of the concrete class derived fromDProcess. There is only one such class in any given system(DArmPlatProcess or DX86PlatProcess) and its definitiondepends on both the processor type and the memory model in use.The generic kernel code calls the function P::NewProcess() toinstantiate such an object. Once created, this object will contain allthe information that the kernel needs to know about the process2.The kernel stores the command line, UIDs and security information(capabilities, SID and VID) in the new process.
It sets the DObjectname to be the root name of the image file used and calculatesthe generation number as one greater than the highest generationnumber of any existing process with the same root name and thirdUID. If you retrieve the full name of a process, it will be in theform name.exe[uuuuuuuu]gggg, where name.exe is the rootfilename, uuuuuuuu is the third UID in hexadecimal, and gggg isthe generation number in base 103.The kernel allocates an ID to the process. Process and thread IDsoccupy the same number space, beginning at 0 and incrementingKERNEL-SIDE CODE MANAGEMENT421for each new process or thread. If the 32-bit ID reaches 232 –1,the kernel reboots to ensure uniqueness of IDs over all time.
Weconsider it highly unlikely that this would occur in practice since itwould require the system to be active for a very long time withoutrebooting due to power down4.The kernel creates the process-relative handles array (DObjectIx)for the new process5.The kernel creates the process lock and DLL lock mutexes6.Some platform-dependent initialization of the process object nowoccurs. Under the moving memory model running on an ARMprocessor, the kernel just allocates an ARM domain to the processif it is a fixed address process and there is a free domain.
Underthe multiple memory model, the kernel allocates the process anew OS ASID, a new page directory and a new address allocator(TLinearSection) for the process local address area. Chapter 7describes OS ASIDs and the address areas used in the multiplememory model. The kernel maps the new page directory at the virtual address corresponding to the allocated OS ASID and initializesit – it copies all global mappings into it if necessary and clears thelocal mapping area7.If the process is being created from an already existing code segment,the kernel attaches the existing code segment to the new process.
Itincrements its reference count and creates the process data/bss/stackchunk using the data and bss size information in the code segment.At this point it checks that the run address of the .data sectioncreated matches the run address expected by the code segment.If this is not the case (for example, an attempt to create a secondinstance of a fixed XIP process with .data and/or .bss), the processcreation fails8.If the process is not being created from an existing code segment,the kernel creates a new code segment using the information passedin by the loader.
It increments the reference count of the codesegment, so that it becomes 2 – one for the loader, one for thenew process. I will describe code segment creation in more detaillater in the chapter, but essentially, for non-XIP code, the kernelallocates an address and maps RAM to store the code and the initialvalues of the initialized data.
For all code segments, it allocatesa data address if necessary. For EXE code segments, the kernelcreates the new process’s data/bss/stack chunk using the data/bsssize information passed from the loader. Finally, the kernel passesrun and load addresses for both code and data back to the loader9.The kernel creates the process’s first thread. It sets its DObjectname to Main, and sets its stack and heap sizes to the values passed422THE LOADERby the loader; these values were originally read from the E32Imageheader.
The kernel marks the thread as ‘‘process permanent’’,which means that if it exits for any reason, the kernel will kill thewhole process including any threads that are created after this mainone. It also marks the thread as ‘‘original’’, which signifies that itis the first thread. This information is used by the process entrypoint code – the original thread causes the process static data tobe initialized and E32Main() to be called, whereas subsequentthreads cause the specified thread entry point to be called. The firstthread is created with an M-state of DThread::ECreated, so itcannot yet be resumed10.The newly created process is added to the process object container(DObjectCon)11.The kernel creates a handle from the calling thread (the loader) tothe new process and passes this handle back to the loader.After E32Loader::ProcessCreate() completes, if a new code segment has been created, the loader needs to load and relocate the code (ifnot XIP) and load all DLLs to which the new EXE code segment implicitlylinks – see Section 10.4.4 for more details of this.Finally, after it has resolved all dependencies, the loader callsE32Loader::ProcessLoaded().
This performs the following actions:1.If a new EXE code segment was created for the process, the kernelcalls DCodeSeg::Loaded() on it. This performs steps 1 to 3 of theCodeSegLoaded() function, described at the end of Section 10.4.42.The kernel maps the EXE code segment and all the code segmentson which it depends into the process and increments their referencecounts3.The kernel sets the EMarkLoaded flag of the EXE code segment toenable it to be reused to launch another instance of the process4.The kernel changes the first thread’s M-state to DThread::EReady;it is now ready to be resumed5.The kernel creates a handle from the loader’s client to the newprocess; the client will eventually use this handle to resume the newprocess.After E32Loader::ProcessLoaded() has completed, the loadercopies the new handle to the process back to the client, and cleansup the E32Image object corresponding to the new process.
Finally, itcompletes the client request and control returns to the client.KERNEL-SIDE CODE MANAGEMENT42310.4.4 Loading a librarySimilarly to process loading, the kernel’s involvement in library loadingbegins after the loader has completed its search for the requested DLLimage and decided which of the available files should be loaded. Theloader will have created an E32Image object on its heap to representthe new image file being loaded. This procedure is carried out bythe loader function E32Image::LoadCodeSeg(), which then callsE32Image::DoLoadCodeSeg() to perform the actual load; this latterfunction is also called while resolving implicit linkages to load theimplicitly linked DLLs.
In a similar way to process loading, the loaderthen queries the kernel to discover if the selected image file is alreadyloaded. It makes an additional check while searching for a matchingcode segment – it must be compatible with the process it is destined tobe loaded into. An incompatibility can result from any of the followingconsiderations:• If a code segment links directly or indirectly to an EXE, it may only beloaded into a process instantiated from that EXE. This is because onlyone EXE file can be loaded into any process; an EXE cannot be loadedas a DLL• If a code segment has writeable static data or links directly or indirectlyto such a code segment, it may only be loaded into a process withwhich the address of the static data is compatible.