First public contribution.
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include <kernel/kern_priv.h>
17 #include "maddrcont.h"
19 RAddressedContainer::RAddressedContainer(NFastMutex* aReadLock, DMutex*& aWriteLock)
20 : iMaxCount(0), iCount(0), iList(0), iReadLock(aReadLock), iWriteLock(aWriteLock)
24 RAddressedContainer::~RAddressedContainer()
30 const TUint MinCount = 8; // must be power of two
32 FORCE_INLINE TUint RAddressedContainer::CalculateGrow()
34 TUint newMax = iMaxCount;
44 TUint RAddressedContainer::CalculateShrink(TUint aCount)
46 TUint newMax = iMaxCount;
48 return 0; // empty container should have zero max size
51 // we want at least 'MinCount' free slots after shrinking for hysteresis,
52 // but not in UDEB builds because OOM testing will barf...
56 TUint tryMax = newMax;
62 while(tryMax>=aCount);
71 TBool RAddressedContainer::CheckWriteLock()
74 return true; // check disabled during boot as we are single threaded at that point
77 if((((TLinAddr)iWriteLock)&1))
78 return true; // its a lock from DMutexPool, we can't check that, assume it's OK
79 return iWriteLock->iCleanup.iThread==&Kern::CurrentThread();
84 const TUint KMaxEntriesInOneGo = 4; // small number to improve test coverage
86 const TUint KMaxEntriesInOneGo = 32; // to produce a similar worst case number of cache line accesses to the binary search
89 TInt RAddressedContainer::Add(TLinAddr aAddress, TAny* aObject)
91 __NK_ASSERT_DEBUG(aObject);
93 __NK_ASSERT_DEBUG(CheckWriteLock());
96 if(K::CheckForSimulatedAllocFail())
98 __KTRACE_OPT(KMMU,Kern::Printf("RAddressedContainer::Add returns simulated OOM %d",KErrNoMemory));
103 // find list insertion point...
104 TUint i = FindIndex(aAddress);
108 // insert new entry...
111 // make room by shuffling entries up in the array KMaxEntriesInOneGo at a time...
112 TEntry* entry = iList+i;
113 TEntry* prev = iList+iCount;
114 ++iCount; // must do this before releasing read lock for the first time
117 TEntry* next = prev-KMaxEntriesInOneGo;
120 // move the final remaining entries...
121 wordmove(entry+1,entry,(TUintPtr)prev-(TUintPtr)entry);
124 wordmove(next+1,next,(TUintPtr)prev-(TUintPtr)next);
126 // flash the read lock to give readers a chance to look at the list...
128 // Note, readers may see a duplicate entry in the list at 'prev' but this
129 // is OK as the Find functions will still work.
132 // copy in new entry...
133 entry->iAddress = aAddress;
134 entry->iObject = aObject;
140 // list memory needs expanding...
141 TUint newMaxCount = CalculateGrow();
143 // allocate new memory...
144 TEntry* newList = (TEntry*)Kern::Alloc(sizeof(TEntry)*newMaxCount);
149 K::Allocator->DebugFunction(RAllocator::ECopyDebugInfo, iList, newList);
151 iMaxCount = newMaxCount;
153 // copy list to new memory, and insert new entry...
154 wordmove(newList,iList,sizeof(TEntry)*i);
155 TEntry* entry = newList+i;
156 entry->iAddress = aAddress;
157 entry->iObject = aObject;
158 wordmove(entry+1,iList+i,sizeof(TEntry)*(iCount-i));
160 // start using new list...
161 TEntry* oldList = iList;
167 // free memory used for old list...
175 TAny* RAddressedContainer::Remove(TLinAddr aAddress)
178 __NK_ASSERT_DEBUG(CheckWriteLock());
181 TUint i = FindIndex(aAddress);
182 TEntry* entry = iList+i-1;
184 if(!i || entry->iAddress!=aAddress)
189 --i; // make 'i' the index of entry to remove
192 TAny* result = entry->iObject;
193 __NK_ASSERT_DEBUG(result);
195 TUint newMaxCount = CalculateShrink(iCount-1);
197 if(newMaxCount>=iMaxCount)
199 remove_without_resize:
200 // remove old entry...
203 // shuffling entries down in the array KMaxEntriesInOneGo at a time...
204 TEntry* prev = iList+i+1;
205 TEntry* end = iList+iCount;
208 TEntry* next = prev+KMaxEntriesInOneGo;
211 // move the final remaining entries...
212 wordmove(prev-1,prev,(TUintPtr)end-(TUintPtr)prev);
215 wordmove(prev-1,prev,(TUintPtr)next-(TUintPtr)prev);
217 // flash the read lock to give readers a chance to look at the list...
219 // Note, readers may see a duplicate entry at the end of the list but this
220 // is OK as the Find functions will still work.
223 --iCount; // must do this after moving all the entries
228 // list memory needs shrinking...
230 // allocate new memory...
234 newList = (TEntry*)Kern::Alloc(sizeof(TEntry)*newMaxCount);
236 goto remove_without_resize; // have no memory to shrink array
239 K::Allocator->DebugFunction(RAllocator::ECopyDebugInfo, iList, newList);
242 iMaxCount = newMaxCount;
244 // copy list to new memory, deleting removed entry...
245 wordmove(newList,iList,sizeof(TEntry)*i);
246 wordmove(newList+i,iList+i+1,sizeof(TEntry)*(iCount-i-1));
248 // start using new list...
249 TEntry* oldList = iList;
255 // free memory used for old list...
263 TAny* RAddressedContainer::Find(TLinAddr aAddress)
266 __NK_ASSERT_DEBUG(iReadLock->HeldByCurrentThread());
268 __NK_ASSERT_DEBUG(CheckWriteLock());
270 TUint i = FindIndex(aAddress);
271 TEntry* entry = iList+i;
276 if(aAddress!=entry->iAddress)
279 TAny* result = entry->iObject;
280 __NK_ASSERT_DEBUG(result);
285 TAny* RAddressedContainer::Find(TLinAddr aAddress, TUint& aOffset)
288 __NK_ASSERT_DEBUG(iReadLock->HeldByCurrentThread());
290 __NK_ASSERT_DEBUG(CheckWriteLock());
292 TUint i = FindIndex(aAddress);
293 TEntry* entry = iList+i;
298 aOffset = aAddress-entry->iAddress;
300 TAny* result = entry->iObject;
301 __NK_ASSERT_DEBUG(result);
306 TUint RAddressedContainer::FindIndex(TLinAddr aAddress)
308 TEntry* list = iList;
310 // linear search from end...
311 TUint count = iCount;
314 if(list[count-1].iAddress<=aAddress)
327 TUint32 x = list[m].iAddress;