diff -r 000000000000 -r 7f656887cf89 libraries/memoryaccess/objectix.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libraries/memoryaccess/objectix.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,513 @@ +// objectix.cpp +// +// Copyright (c) 1994 - 2010 Accenture. All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Accenture - Initial contribution +// + +/** +@file +@internalTechnology +*/ + +#include +#include "dobject.h" +#define DObjectIx DObjectIxNinePointTwoHack // So that we're not redefining DObjectIx + +/** Creates a new kernel object index. + + @param aPtr Value to pass to Close() when objects are closed due to index deletion. + + @return The pointer to the new index, NULL if out of memory. + + @pre Calling thread must be in a critical section. + @pre No fast mutex can be held. + @pre Call in a thread context. + */ +DObjectIx *DObjectIx::New(TAny* aPtr) + { + return new DObjectIx(aPtr); + } + +#ifndef DOBJECT_TEST_CODE +void DObjectIx::Wait() + { + Kern::MutexWait(*HandleMutex); + } + +void DObjectIx::Signal() + { + Kern::MutexSignal(*HandleMutex); + } +#endif + + +/** Construct a kernel object index + */ +DObjectIx::DObjectIx(TAny *aPtr) + : iNextInstance(1), iPtr(aPtr), iFree(-1) + { + } + + +/** Destroys a kernel object index. + + Any objects in the index are closed. The iPtr member of the index is passed + as the parameter to Close() for each object. + + @pre Calling thread must be in a critical section. + @pre No fast mutex can be held. + @pre Call in a thread context. + */ +DObjectIx::~DObjectIx() + { + // We have to be very careful here. Calling Close() on the objects in the array + // may result in other entries being removed from the array before we delete + // them here, and may result in the array being ReAlloc()ed, corrupting the removed + // entries, hence we must check the iCount value each time round the loop. + TInt i=-1; + while(++iobj; + if (pO) + { + --iActiveCount; + pS->obj=NULL; // invalidate entry after closing it + pO->Close(iPtr); + } + } + SDObjectIxRec* pR=iObjects; + iObjects=NULL; + delete pR; + } + + +/** Adds a kernel object to an index and return a handle. + + @param aObj Pointer to the object to add + @param aHandle Place to write returned handle to + + @return KErrNone, if operation successful; + KErrNoMemory, if there was insufficient memory to expand the array. + + @pre Calling thread must be in a critical section. + @pre No fast mutex can be held. + @pre Call in a thread context. + @pre DObject::HandleMutex held + */ +TInt DObjectIx::Add(DObject* anObj, TInt& aHandle) + { + //Check preconditions(debug build only) + __ASSERT_CRITICAL; + __ASSERT_NO_FAST_MUTEX; + + TInt index=iFree; //iFree contains the index of the first empty slot or -1 if there is no such. + if (index<0) //Check if the free list is empty + { + // The free list is empty, so more slots must be allocated. + if (iCount==KObjectIxMaxHandles) + return KErrNoMemory; + + //Those are internal checking of the object consistency + __ASSERT_DEBUG(iAllocated==iCount,Panic(EObjInconsistent)); + __ASSERT_DEBUG(iAllocated==iActiveCount,Panic(EObjInconsistent)); + + //Double allocated memory + TInt newAlloc=iAllocated ? 2*iAllocated : KObjectIxGranularity; + if(newAlloc>KObjectIxMaxHandles) + newAlloc=KObjectIxMaxHandles; + TInt r=Kern::SafeReAlloc((TAny*&)iObjects,iAllocated*sizeof(SDObjectIxRec),newAlloc*sizeof(SDObjectIxRec)); + if (r) + return r; + //NOTE: There is no need to initialize newly allocated memory (e.g. to zero iObjects) as it all goes + //beyond iCount and will be not considered when search in At(...) or operator[]() methods. + //As the free list is initially ordered, each slot goes through the states as follows: + // - Created as the part of the free list beyond iCount. - uninitialized and not searched in any method. + // - In use - initialized. + // - The part of the free list within iCount - initialized to zero. + //Also bear in mind that UpdateState() does not reorder free list beyond iCount but keeps it preserverd. + + iAllocated=newAlloc; //Update the number of allocated slots + iUpdateDisabled = iAllocated/2;//The number of Remove() calls before the object update(free list,iCount,..) + + //Connect all newly allocated slots into the list and set 'index' to point to the first one. + SDObjectIxRec* pA = (SDObjectIxRec*)iObjects; + index=newAlloc-1; + pA[index].nextEmpty = -1; + while (iCount <= --index) + pA[index].nextEmpty=index+1; + index++; + } + + //At this point, 'index' variable points to the slot that will be used for the new entry. + //It also represents the first element in the list of empty slots. + + SDObjectIxRec *pS=iObjects+index; // pS points to the object that will be used for the new entry. + iFree=pS->nextEmpty; // Update iFree to point to the next empty slot. + + NKern::LockSystem(); + + //Initialize data of the new element of the array. + pS->obj=anObj; + pS->str.uniqueID=(TUint16)anObj->UniqueID(); + pS->str.instance=(TUint16)instanceLimit(iNextInstance); + + iNextInstance++; + + if (index>=iCount) //Update iCount to points to the slot after the last in use. + iCount=index+1; + + ++iActiveCount; + + NKern::UnlockSystem(); + + //Internal checking of the object consistency + __ASSERT_DEBUG( (iFree==-1 && iAllocated==iCount && iAllocated==iActiveCount) + ||(iFree!=-1 && iAllocated>iActiveCount),Panic(EObjInconsistent)); + + aHandle=makeHandle(index,pS->str.instance); + return KErrNone; + } + + +/** Removes a kernel object from an index by handle. + + Returns a pointer to the object removed and the parameter to pass to Close(). + + @param aHandle Handle to object to be removed. + @param aObj Place to write pointer to the object to add. + @param aPtr Place to write parameter to be passed to Close(). + + @return KErrNone, if operation successful; + KErrBadHandle, if the supplied handle was invalid. + + @pre Calling thread must be in a critical section. + @pre No fast mutex can be held. + @pre Call in a thread context. + @pre DObject::HandleMutex held. + */ +TInt DObjectIx::Remove(TInt aHandle, DObject*& aObj, TAny*& aPtr) + { + //Check preconditions(debug build only) + __ASSERT_CRITICAL; + __ASSERT_NO_FAST_MUTEX; + + TInt i=index(aHandle); + + if (i >= iCount) + return KErrBadHandle; + + SDObjectIxRec* pR=iObjects+i; + DObject *pO=pR->obj; + if (!pO || pR->str.instance!=instance(aHandle) || pR->str.uniqueID!=pO->UniqueID()) + return KErrBadHandle; + + NKern::LockSystem(); + pR->obj=NULL; + --iActiveCount; + NKern::UnlockSystem(); + + if(iActiveCount) + { + // Add the entry onto the free list + pR->nextEmpty=iFree; + iFree=i; + + if(iUpdateDisabled) + iUpdateDisabled--; //Count down till state update is enabled again. + + if ( //Update the states(HWM, resort free list & memory shrink) if: + (!iUpdateDisabled) && //There were a number of Remove() calls since the last ReAlloc + (iAllocated>=2*KObjectIxGranularity))//Allocated memory is above the limit. + { + UpdateState(); + iUpdateDisabled = iAllocated/2;//The number of Remove() calls before the next update comes. + } + } + else + { + //There is no any CObject left. Reset the object to initial state (except iNextInstance) + delete iObjects; + iObjects=NULL; + iAllocated=0; + iCount=0; + iFree=-1; //Empty free list + } + + //This is internal checking of the object consistency + __ASSERT_DEBUG( (iFree==-1 && iAllocated==iCount && iAllocated==iActiveCount) + ||(iFree!=-1 && iAllocated>iActiveCount),Panic(EObjInconsistent)); + + aObj=pO; + aPtr=iPtr; + return KErrNone; + } + + +// Private method which: +//1. Reorders free list. +//2. Updates iCount. This is the only place where HWM is decreased, while it can be increased during AddL(). +//3. Shrinks the heap memory (pointed by iObjects) if it can be at least halved. +//The function is entered with at least one occupied slot in iObjects array. +//The array is searched from its end. Special care is given to the case where +//iCount is less then KObjectIxGranularity as the size of the arrey does not go below it. +//Note: HighWaterMark (HWM) is a term used for iCount. +void DObjectIx::UpdateState() + { + TBool toShrink = EFalse; + TBool foundFreeBelowLimit = EFalse;//Used to handle spacial case when HWM is below the minimum alloc. limit + TInt newHWM = 0; + + //Start from the HWM as all slots beyond are free and sorted already. + TInt current = iCount; + TInt prevFreeSlot = iCount == iAllocated ? -1 : iCount; + while (--current>=0) + { + if (iObjects[current].obj) + { + //This is the slot with the valid entry. Check if this is the last in the array. + if(!newHWM) + { + //This is the first occupied slot we found => It is new HWM. + newHWM=current+1; + if (current < iAllocated/2) + { + //At this point we decide to shrink memory. + toShrink = ETrue; + //Once we find HWM and decide to shrink, all slots after that point should be removed + //from the free list as that memory will be freed. The exception is the case when HWM is below + //the minimum of allocated memory (8 slots as the moment). + if((current >= KObjectIxGranularity) || (!foundFreeBelowLimit)) + prevFreeSlot = -1; //The next free slot to find will be the last one in the list. + } + } + } + else + { + //This is the free slot. + if ((!newHWM) && (!foundFreeBelowLimit) &&(currentobj==aObject) + c++; + } while (++pS=iCount) + return(NULL); + SDObjectIxRec *pS=iObjects+i; + if (pS->str.instance!=instance(aHandle) || pS->str.uniqueID!=aUniqueID) + return(NULL); + return(pS->obj); + } + + +/** Looks up an object in the index by handle. + + The object may be of any type. + + @param aHandle Handle to look up. + + @return Pointer to object or NULL if handle invalid. + + @pre Call in a thread context. + @pre System lock must be held. + */ +DObject* DObjectIx::At(TInt aHandle) + { + __ASSERT_SYSTEM_LOCK; //Check preconditions (debug build only) + TInt i=index(aHandle); + if (i>=iCount) + return NULL; + SDObjectIxRec *pS=iObjects+i; + if (pS->str.instance!=instance(aHandle)) + return NULL; + return pS->obj; + } +#endif + + +/** Looks up an object in the index by object pointer. + + Returns a handle to the object. + + @param aObj Pointer to the object to look up. + + @return Handle to object (always >0); + KErrNotFound, if object not present in index. + + @pre Calling thread must be in a critical section. + @pre No fast mutex can be held. + @pre Call in a thread context. + @pre DObject::HandleMutex held. + */ +TInt DObjectIx::At(DObject* aObj) + { + //Check preconditions(debug build only) + __ASSERT_CRITICAL; + __ASSERT_NO_FAST_MUTEX; + + if (iCount) + { + SDObjectIxRec* pS=iObjects; + SDObjectIxRec* pE=pS+iCount; + TInt i=0; + while(pSobj!=aObj) + pS++, i++; + if (pSstr.instance)); + } + return KErrNotFound; + } + + +#ifndef __DOBJECT_MACHINE_CODED__ +/** Finds the object at a specific position in the index array. + + @param aIndex Index into array. + + @return Pointer to the object at that position (could be NULL). + + @pre Call in a thread context. + @pre System lock must be held. + */ +DObject* DObjectIx::operator[](TInt aIndex) + { + __ASSERT_SYSTEM_LOCK; //Check preconditions (debug build only) + __ASSERT_ALWAYS(aIndex>=0 && aIndex=iObjects && !p->obj) {} + return makeHandle(p-iObjects,p->str.instance); + } + return 0; + } + +// +// Include these in exactly one CPP file somewhere +// + +extern TBool gRunningWithOldDefinition = ETrue; + +NONSHARABLE_CLASS(DObjectWithPaddingOnly) : public DObject + { +public: + DOBJECT_PADDING; + }; + +TBool CalculateDObjectSize() + { + DObjectWithPaddingOnly* obj = new DObjectWithPaddingOnly; + if (!obj) return EFalse; + + // objectId points to the mem location where iObjectId will be. So if running on a system with the new size DOBject it will always be non-zero (because objectIds are set in the DObject constructor, and are always non-zero), but if running on earlier systems it will be zero because DBase zero-fills the object + TUint64& objectId = *reinterpret_cast((TUint8*)&obj->iName + sizeof(HBuf*)); + + if (objectId != 0) + { + //Kern::Printf("Detected MemoryAccess is running with new larger DObject"); + gRunningWithOldDefinition = EFalse; + } + else + { + //Kern::Printf("Detected MemoryAccess is running with old-format DObject"); + } + obj->Close(NULL); + return ETrue; + }