diff -r 000000000000 -r 96e5fb8b040d kernel/eka/memmodel/epoc/flexible/mmu/maddrcont.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/maddrcont.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,337 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "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: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include "maddrcont.h" + +RAddressedContainer::RAddressedContainer(NFastMutex* aReadLock, DMutex*& aWriteLock) + : iMaxCount(0), iCount(0), iList(0), iReadLock(aReadLock), iWriteLock(aWriteLock) + {} + + +RAddressedContainer::~RAddressedContainer() + { + Kern::Free(iList); + } + + +const TUint MinCount = 8; // must be power of two + +FORCE_INLINE TUint RAddressedContainer::CalculateGrow() + { + TUint newMax = iMaxCount; + + if(newMax>= 1; + } + while(tryMax>=aCount); + + if(newMaxiCleanup.iThread==&Kern::CurrentThread(); + } + + +#ifdef _DEBUG +const TUint KMaxEntriesInOneGo = 4; // small number to improve test coverage +#else +const TUint KMaxEntriesInOneGo = 32; // to produce a similar worst case number of cache line accesses to the binary search +#endif + +TInt RAddressedContainer::Add(TLinAddr aAddress, TAny* aObject) + { + __NK_ASSERT_DEBUG(aObject); + __ASSERT_CRITICAL; + __NK_ASSERT_DEBUG(CheckWriteLock()); + +#ifdef _DEBUG + if(K::CheckForSimulatedAllocFail()) + { + __KTRACE_OPT(KMMU,Kern::Printf("RAddressedContainer::Add returns simulated OOM %d",KErrNoMemory)); + return KErrNoMemory; + } +#endif + + // find list insertion point... + TUint i = FindIndex(aAddress); + + if(iCountiAddress = aAddress; + entry->iObject = aObject; + + ReadUnlock(); + } + else + { + // list memory needs expanding... + TUint newMaxCount = CalculateGrow(); + + // allocate new memory... + TEntry* newList = (TEntry*)Kern::Alloc(sizeof(TEntry)*newMaxCount); + if(!newList) + return KErrNoMemory; + #ifdef _DEBUG + if(iList) + K::Allocator->DebugFunction(RAllocator::ECopyDebugInfo, iList, newList); + #endif + iMaxCount = newMaxCount; + + // copy list to new memory, and insert new entry... + wordmove(newList,iList,sizeof(TEntry)*i); + TEntry* entry = newList+i; + entry->iAddress = aAddress; + entry->iObject = aObject; + wordmove(entry+1,iList+i,sizeof(TEntry)*(iCount-i)); + + // start using new list... + TEntry* oldList = iList; + ReadLock(); + iList = newList; + ++iCount; + ReadUnlock(); + + // free memory used for old list... + Kern::Free(oldList); + } + + return KErrNone; + } + + +TAny* RAddressedContainer::Remove(TLinAddr aAddress) + { + __ASSERT_CRITICAL; + __NK_ASSERT_DEBUG(CheckWriteLock()); + + // search for it... + TUint i = FindIndex(aAddress); + TEntry* entry = iList+i-1; + + if(!i || entry->iAddress!=aAddress) + { + // not found... + return 0; + } + --i; // make 'i' the index of entry to remove + + // get object... + TAny* result = entry->iObject; + __NK_ASSERT_DEBUG(result); + + TUint newMaxCount = CalculateShrink(iCount-1); + + if(newMaxCount>=iMaxCount) + { +remove_without_resize: + // remove old entry... + ReadLock(); + + // shuffling entries down in the array KMaxEntriesInOneGo at a time... + TEntry* prev = iList+i+1; + TEntry* end = iList+iCount; + for(;;) + { + TEntry* next = prev+KMaxEntriesInOneGo; + if(next>=end) + { + // move the final remaining entries... + wordmove(prev-1,prev,(TUintPtr)end-(TUintPtr)prev); + break; + } + wordmove(prev-1,prev,(TUintPtr)next-(TUintPtr)prev); + prev = next; + // flash the read lock to give readers a chance to look at the list... + ReadFlash(); + // Note, readers may see a duplicate entry at the end of the list but this + // is OK as the Find functions will still work. + } + + --iCount; // must do this after moving all the entries + ReadUnlock(); + } + else + { + // list memory needs shrinking... + + // allocate new memory... + TEntry* newList = 0; + if(newMaxCount) + { + newList = (TEntry*)Kern::Alloc(sizeof(TEntry)*newMaxCount); + if(!newList) + goto remove_without_resize; // have no memory to shrink array + #ifdef _DEBUG + if(iList) + K::Allocator->DebugFunction(RAllocator::ECopyDebugInfo, iList, newList); + #endif + } + iMaxCount = newMaxCount; + + // copy list to new memory, deleting removed entry... + wordmove(newList,iList,sizeof(TEntry)*i); + wordmove(newList+i,iList+i+1,sizeof(TEntry)*(iCount-i-1)); + + // start using new list... + TEntry* oldList = iList; + ReadLock(); + iList = newList; + --iCount; + ReadUnlock(); + + // free memory used for old list... + Kern::Free(oldList); + } + + return result; + } + + +TAny* RAddressedContainer::Find(TLinAddr aAddress) + { + if(iReadLock) + __NK_ASSERT_DEBUG(iReadLock->HeldByCurrentThread()); + else + __NK_ASSERT_DEBUG(CheckWriteLock()); + + TUint i = FindIndex(aAddress); + TEntry* entry = iList+i; + if(i==0) + return 0; + --entry; + + if(aAddress!=entry->iAddress) + return 0; + + TAny* result = entry->iObject; + __NK_ASSERT_DEBUG(result); + return result; + } + + +TAny* RAddressedContainer::Find(TLinAddr aAddress, TUint& aOffset) + { + if(iReadLock) + __NK_ASSERT_DEBUG(iReadLock->HeldByCurrentThread()); + else + __NK_ASSERT_DEBUG(CheckWriteLock()); + + TUint i = FindIndex(aAddress); + TEntry* entry = iList+i; + if(i==0) + return 0; + --entry; + + aOffset = aAddress-entry->iAddress; + + TAny* result = entry->iObject; + __NK_ASSERT_DEBUG(result); + return result; + } + + +TUint RAddressedContainer::FindIndex(TLinAddr aAddress) + { + TEntry* list = iList; +#if 0 + // linear search from end... + TUint count = iCount; + while(count) + { + if(list[count-1].iAddress<=aAddress) + break; + --count; + } + return count; +#else + // binary search... + TUint l = 0; + TUint r = iCount; + TUint m; + while(l>1; + TUint32 x = list[m].iAddress; + if(x<=aAddress) + l = m+1; + else + r = m; + } + return r; +#endif + } + +