Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 38
Текст из файла (страница 38)
We define it recursively as the full name of the DObject’sowner appended with ‘‘::<short name of this object>’’. The limitOBJECTS AND HANDLES167of 80 characters on the length of the short name guarantees that the fullname cannot exceed 256 characters, because there can be a maximumof three objects in the owner chain: the DObject might be owned bya thread that is owned by a process. For example, a semaphore namedALAZON, owned by the thread EPOS, in turn part of the LEXIS process,would be called LEXIS::EPOS::ALAZON.
If you’re worrying aboutthread-relative threads, don’t – we no longer allow them in EKA2.We use a global fast mutex, DObject::Lock, to protect the operations of getting an object’s name, setting its name and setting its owner.We do this to avoid inconsistent results when one thread renames anobject while another is reading its name or full name. (Obviously, weprotect the setting of the owner because this changes the full name ofthe object.)The method that reads an object’s short name, DObject::DoAppendName(), can be over-ridden in a derived class. In fact,theDLibrary and DProcess classes do over-ride it, because they bothinclude the UID in the object name, and DProcess adds a generationnumber too.5.1.2.6 Object indexes and handlesNow that I’ve described the DObject class, I can return to the objectindex class that is used to record the handles held by user threads orprocesses on kernel objects.A handle is a 32-bit integer, split into bit fields like this:BitsFunction0-1415-bit index into the DObjectIx holding the handle.15No close flag.
If set to 1 the handle cannot be closedusing RHandleBase::Close().16-2914-bit instance count (taken fromDObjectIx::iNextInstance). This field is neverzero for a valid handle.30Local handle flag. If set to 1 the handle is thread-local,otherwise it is process-global.310 for normal handles, 1 for special handles. Supportedspecial handles are:FFFF8000 – always refers to the current processFFFF8001 – always refers to the current thread.168KERNEL SERVICESLet’s have a look at the DObjectIx class, along with theSDObjectIxRec structure that it makes use of:struct SDObjectIxRec{TInt16 instance;TInt16 uniqueID;DObject* obj;};class DObjectIx : public DBase{public:enum{ENoClose=KHandleNoClose, ELocalHandle=0x40000000};public:IMPORT_C static DObjectIx* New(TAny* aPtr);IMPORT_C ∼DObjectIx();IMPORT_C TInt Add(DObject* aObj, TInt& aHandle);IMPORT_C TInt Remove(TInt aHandle, DObject*& aObject, TAny*& aPtr);IMPORT_C DObject* At(TInt aHandle,TInt aUniqueID);IMPORT_C DObject* At(TInt aHandle);IMPORT_C TInt At(DObject* aObject);IMPORT_C TInt Count(DObject* aObject);IMPORT_C DObject* operator[](TInt aIndex);TInt LastHandle();static void Wait();static void Signal();inline TInt Count();inline TInt ActiveCount();protected:IMPORT_C DObjectIx(TAny* aPtr);private:void UpdateState();TInt iNextInstance;TInt iAllocated;// Max entries before realloc neededTInt iCount; // At least 1 above the highest active indexTInt iActiveCount; // No of actual entries in the indexSDObjectIxRec* iObjects;TAny* iPtr;TInt iFree;// The index of the first free slot or -1.TInt iUpdateDisabled;public:static DMutex* HandleMutex;};Key member data of DObjectIxiNextInstanceThis is a counter that starts at 1, and is incremented every time an objectis added to the index.
It is incremented again if it would become zeromodulo 16384, so that the lower 14 bits range from 1 to 16383.iAllocatedThis is the number of slots currently allocated in the iObjects array.OBJECTS AND HANDLES169iCountThis field is 1 + the highest index of any occupied slot in the iObjectsarray.iActiveCountThis is the number of occupied slots in the iObjects array.iObjectsThis is a pointer to the array of object index records. Each record containsa pointer to a DObject, the instance counter modulo 16384 when theentry was added and the unique ID of the DObjectCon in which theDObject is held.iPtrThis is a pointer to the process that is the ultimate owner of all handles inthis index (that is, the thread’s owning process for a thread-local handlearray).
This is passed as a parameter to DObject::Close() when ahandle is closed.Finding objects from handlesTo translate a handle into a DObject pointer, the kernel follows thefollowing steps, which are shown graphically in Figure 5.1:1. Uses bit 30 of the handle to choose a DObjectIx (either the currentthread’s or the current process’s handle array)2. Takes the bottom 15 bits to use as an index, and checks this indexagainst the DObjectIx::iCount value to ensure it is within thearray3. Uses the index to access an entry in the iObjects array of theDObjectIx4.
Compares the handle’s instance value (bits 16–29) against theinstance value stored in the iObjects array entry.1 (We set thelatter from the DObjectIx::iNextInstance value when theDObjectIx entry was made2 )5. If the two instance values are the same, then the handle is valid6. Checks the unique ID value in the iObjects array entry to ensurethat the object pointed to is of the expected type7. Finally, extracts the DObject pointer from the iObjects arrayentry.1Note that the instance value provides protection against a stale handle being re-usedafter it has been closed and after the kernel has reallocated its index slot to a new handle.Handle lookup always occurs with the system locked to protect against changes in thehandle array while it is being examined.2Which is when the handle was created.1703130KERNEL SERVICESinstance1.
Choose DObjectIx= 0 - process's= 1 - thread's15indexhandle2. Index into array ofSDObjectIxRecsDObjectIxiNextInstanceiAllocatediCountiArchiveCountSDObjectIxReciObjects3. Check instancesmatch4. Check unique ID isvalid for this type ofobjectinstanceuniqueIDDObject*5. Follow DObject* tofind object denoted byhandleDObjectFigure 5.1Finding an object from a handleProtection of handle mechanismsThe adding and removing of handles requires some care. The kernel protects additions and removals from DObjectIx arrays with aglobal mutex, DObjectIx::HandleMutex.
The mutex allows theExec::HandleInfo() function to prevent any handle creation anddeletion while it inspects the handle array of every thread and process.OBJECTS AND HANDLES171The kernel doesn’t protect the lookup of handles, though – this wouldslow it down too much. Instead it looks up handles while holding onlythe system lock.If the iObjects array needs to grow as a result of adding a handle,the kernel uses the Kern::SafeReAlloc() function. This allocates anew larger block first, copies the old contents into it, fills the extra spacein the new block with zeros, and then acquires the system lock beforereplacing the pointer with the address of the new block and deleting theold block.
This ensures that any code running with the system lockedalways sees a valid handle array.Since a handle contains an index into the iObjects array, the removalof an entry from the iObjects array cannot result in all the later entriesbeing moved as that would make all the existing handles to those objectsinvalid.
Instead, the kernel sets the entry’s object pointer to NULL andadds the entry to the front of the linked list of free slots – that is, it setsiFree to point to the entry. When it next adds an object to the index, itwill use up the slot denoted by iFree.5.1.2.7 Object containersObject containers exist for two reasons:1. So that the kernel can find objects by name2. So that the kernel can enumerate all the objects of a certain type.With some exceptions, such as internal kernel mutexes, whenever thekernel creates a DObject-derived object it adds that object to theDObjectCon that corresponds to the object’s type.The kernel removes the object from the container when it deletesit – which, as we saw earlier, happens when the object’s access countdrops to zero.
In fact, the removal of the object from the container isthe last action that the kernel does before it frees the memory – becauseit is the DObject destructor that removes the dying DObject fromthe container.When the kernel adds an object to a container, it checks that theobject’s full name is unique among the objects in that container. Thisensures that the kernel can find the object unambiguously using itsfull name.Each DObjectCon has its own DMutex that protects all accesses tothe container, including those that simply index into the container.