|
1 // Copyright (c) 1997-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 "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". |
|
7 // Initial Contributors: |
|
8 // Nokia Corporation - initial contribution. |
|
9 // Contributors: |
|
10 // |
|
11 // Description: |
|
12 // CMBufPoolManager.cpp |
|
13 // Maintains one or more pool chains (CMBufPoolChain) on behalf of CMBufManager |
|
14 // |
|
15 // |
|
16 |
|
17 /** |
|
18 @file |
|
19 |
|
20 Maintains one or more pool chains (CMBufPoolChain) on behalf of CMBufManager |
|
21 |
|
22 @internalComponent |
|
23 |
|
24 */ |
|
25 |
|
26 #include "mbufmanager.h" |
|
27 #include <comms-infras/cfmacro.h> |
|
28 #include "MBufPoolManager.h" |
|
29 #include "MBufPoolChain.h" |
|
30 #include "MBufPool.h" |
|
31 #include "MBufMemoryAllocator.h" |
|
32 #include <cflog.h> |
|
33 |
|
34 static const TInt KMemoryAlignment = 8; |
|
35 const TInt KNoOutstandingRequests = -1; |
|
36 |
|
37 /** Patchable constant detailing the size of cache lines in the target architecture. |
|
38 The MBufMgr will align data to cache lines. |
|
39 */ |
|
40 extern const TUint KMBufCacheLineSize = 32; |
|
41 |
|
42 #define ALIGN_CACHE_MASK (KMBufCacheLineSize-1) |
|
43 #define ALIGN_CACHE_UP(n) (((n)+(ALIGN_MASK)) & ~ALIGN_MASK) |
|
44 #define ALIGN_CACHE_DOWN(n) ((n) & ~ALIGN_MASK) |
|
45 #define IS_CACHE_ALIGNED(p) ((((TUint32)(p)) & ALIGN_MASK)==0) |
|
46 |
|
47 #ifdef __CFLOG_ACTIVE |
|
48 __CFLOG_STMT(_LIT8(KComponent, "PoolManager");) |
|
49 __CFLOG_STMT(_LIT8(KSubsysMBufMgr, "MBufMgr");) // subsystem name |
|
50 __CFLOG_STMT(_LIT8(KComponentPerformance, "performance");) // component name - used for any sub-optimal performance behaviuor |
|
51 #endif |
|
52 |
|
53 CMBufPoolManager* CMBufPoolManager::NewL(TInt aMaxAllocSize, CMBufManager& aMBufManager) |
|
54 { |
|
55 CMBufPoolManager* This = new(ELeave) CMBufPoolManager(aMaxAllocSize, aMBufManager); |
|
56 CleanupStack::PushL(This); |
|
57 This->ConstructL(aMaxAllocSize); |
|
58 CleanupStack::Pop(This); |
|
59 return This; |
|
60 } |
|
61 |
|
62 // ctor |
|
63 CMBufPoolManager::CMBufPoolManager(TInt aMaxAllocSize, CMBufManager& aMBufManager) |
|
64 : CActive(EPriorityStandard), |
|
65 iMaxAllocSize(aMaxAllocSize), |
|
66 iMBufManager(aMBufManager) |
|
67 { |
|
68 #ifdef __CFLOG_ACTIVE |
|
69 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager %x:\tCMBufPoolManager()"), this)); |
|
70 #endif |
|
71 |
|
72 iCommitted = EFalse; |
|
73 iNextMBufSize = KNoOutstandingRequests; |
|
74 } |
|
75 |
|
76 void CMBufPoolManager::ConstructL(TInt aMaxAllocSize) |
|
77 { |
|
78 User::LeaveIfError(iPoolChainLock.CreateLocal()); |
|
79 iMBufMgrOwnerThread.Duplicate(RThread()); |
|
80 |
|
81 iMemoryAllocator = CMBufMemoryAllocator::NewL(aMaxAllocSize); |
|
82 |
|
83 CActiveScheduler::Add(this); |
|
84 |
|
85 WaitForNewPoolRequest(); |
|
86 } |
|
87 |
|
88 CMBufPoolManager::~CMBufPoolManager() |
|
89 { |
|
90 // Cancel any outstanding requests |
|
91 Cancel(); |
|
92 |
|
93 iPoolChains.ResetAndDestroy(); |
|
94 iPoolChains.Close(); |
|
95 |
|
96 delete iMemoryAllocator; |
|
97 |
|
98 iPoolChainLock.Close(); |
|
99 iMBufMgrOwnerThread.Close(); |
|
100 } |
|
101 |
|
102 CMBufMemoryAllocator& CMBufPoolManager::Memory() |
|
103 { |
|
104 return *iMemoryAllocator; |
|
105 } |
|
106 |
|
107 CMBufManager& CMBufPoolManager::Manager() |
|
108 { |
|
109 return iMBufManager; |
|
110 } |
|
111 |
|
112 void CMBufPoolManager::WaitForNewPoolRequest() |
|
113 { |
|
114 __ASSERT_DEBUG(!IsActive(), CMBufManager::Panic(EMBuf_AlreadyActive)); |
|
115 iStatus = KRequestPending; |
|
116 SetActive(); |
|
117 } |
|
118 |
|
119 void CMBufPoolManager::DoCancel() |
|
120 { |
|
121 NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications |
|
122 if(!iSignalled) |
|
123 { |
|
124 // We're almost certainly the only thread doing this; now check again inside the critsec to be sure |
|
125 iPoolChainLock.Wait(); |
|
126 if(!iSignalled) |
|
127 { |
|
128 iSignalled = ETrue; |
|
129 TRequestStatus* pStatus = &iStatus; |
|
130 User::RequestComplete(pStatus, KErrCancel); |
|
131 } |
|
132 iPoolChainLock.Signal(); |
|
133 } |
|
134 } |
|
135 |
|
136 TInt CMBufPoolManager::BackgroundAllocateNewPool(CMBufPoolChain& aPoolChain, |
|
137 TInt aNumMBufs) |
|
138 { |
|
139 |
|
140 // Build a list of MBuf sizes and allow one request per MBuf pool size.... |
|
141 // Note its essential that at least one request is serviced, the allocation can |
|
142 // then attempt to use the new MBufs created. Its not essential that every |
|
143 // request is serviced, its more important to prevent this single new pool |
|
144 // allocation routine from locking out processing on the many threads that use |
|
145 // this routine for a long time |
|
146 |
|
147 // The first attempted growth by aNumMBufs wins |
|
148 NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications |
|
149 if (!aPoolChain.iSignalled) |
|
150 { |
|
151 |
|
152 // This is being most likely being called from the context of some thread other than the |
|
153 // MBufMgr owner, and there's a distinct risk of more than one thread being OOB at the same |
|
154 // time since it's a common PoolChain. So we have to lock here to process this PoolChain |
|
155 iPoolChainLock.Wait(); |
|
156 |
|
157 // We're almost certainly the only thread doing this; now check again inside the critsec to be sure |
|
158 if (!aPoolChain.iSignalled) |
|
159 { |
|
160 // First do a simple test to see if the new pool will be created |
|
161 // Note in the future when CMBufPool deletion is implemented iNoMoreSpace |
|
162 // should be cleared on all pools to allow growth again. |
|
163 if (aPoolChain.iNoMoreSpace) |
|
164 { |
|
165 if (aPoolChain.iLastGrowth > aNumMBufs) |
|
166 { |
|
167 // Try this smaller allocation |
|
168 aPoolChain.iNoMoreSpace = EFalse; |
|
169 } |
|
170 else |
|
171 { |
|
172 iPoolChainLock.Signal(); |
|
173 return KErrNoMBufs; |
|
174 } |
|
175 } |
|
176 aPoolChain.iLastGrowth = aNumMBufs; |
|
177 aPoolChain.iNumMBufsToAdd = aNumMBufs; |
|
178 aPoolChain.iSignalled = ETrue; |
|
179 } |
|
180 |
|
181 } |
|
182 else |
|
183 { |
|
184 // Its possible that first time round we missed this growth attempt |
|
185 if (iSignalled) |
|
186 { |
|
187 // already signalled so just return |
|
188 return KErrNone; |
|
189 } |
|
190 // already signalled but the first time round the growth attempt was missed |
|
191 // this is always possible because to stop the background thread slowing the |
|
192 // these threads we dont lock in the RunL. The RunL is always run in the same |
|
193 // thread so does not need a lock. |
|
194 iPoolChainLock.Wait(); |
|
195 } |
|
196 |
|
197 // Here we have to guard against being completed multiple times because more than |
|
198 // one pool chain can be growing at the same time |
|
199 if (!iSignalled) |
|
200 { |
|
201 iSignalled = ETrue; |
|
202 |
|
203 // iNextMBufSize is the first freepool for a growth attempt |
|
204 iNextMBufSize = aPoolChain.iBufSize; |
|
205 |
|
206 TRequestStatus* pStatus = &iStatus; |
|
207 |
|
208 // We dont need to hold onto the lock now since there is no chance |
|
209 // that the RequestComplete can be called twice |
|
210 iPoolChainLock.Signal(); |
|
211 |
|
212 iMBufMgrOwnerThread.RequestComplete(pStatus, KErrNone); |
|
213 return KErrNone; |
|
214 } |
|
215 |
|
216 iPoolChainLock.Signal(); |
|
217 return KErrNone; |
|
218 } |
|
219 |
|
220 void CMBufPoolManager::RunL() |
|
221 { |
|
222 // Now that we're in the thread that owns pools and ultimately the |
|
223 // memory allocation so attempt to create the new pool |
|
224 |
|
225 CMBufPoolChain* selectedPoolChain(NULL); |
|
226 TInt growThisPoolChain = iNextMBufSize; |
|
227 iNextMBufSize = KNoOutstandingRequests; |
|
228 |
|
229 // There is a chance that there are other pools to grow as well |
|
230 // looking for them now can save future locking and speed allocation. |
|
231 |
|
232 // Note we dont have to catch every growth attempt because background |
|
233 // allocation should be triggered from an early threshold. This allocation |
|
234 // might satisfy the immediate growth requirement so no need to lock. |
|
235 |
|
236 // Ensure that each time RunL is called a different pool growth attempt |
|
237 // by stepping through the available pools looking for the next request. |
|
238 TInt poolChainCount = iPoolChains.Count(); |
|
239 TInt lowestRequest = KNoOutstandingRequests; |
|
240 |
|
241 for (TInt i = 0; i < poolChainCount; i++) |
|
242 { |
|
243 CMBufPoolChain* poolInfo = iPoolChains[i]; |
|
244 TInt thisMBufSize = poolInfo->BufSize(); |
|
245 |
|
246 // locate this growth attempt |
|
247 if (thisMBufSize == growThisPoolChain) |
|
248 { |
|
249 selectedPoolChain = poolInfo; |
|
250 } |
|
251 |
|
252 if (poolInfo->iSignalled) |
|
253 { |
|
254 if (lowestRequest == KNoOutstandingRequests) |
|
255 { |
|
256 lowestRequest = thisMBufSize; |
|
257 } |
|
258 if ( (iNextMBufSize == KNoOutstandingRequests) && |
|
259 (thisMBufSize > growThisPoolChain) ) |
|
260 { |
|
261 // found the next freepool to grow |
|
262 iNextMBufSize = thisMBufSize; |
|
263 break; |
|
264 } |
|
265 } |
|
266 } |
|
267 |
|
268 // Might have wrapped round all the PoolChains |
|
269 if ( (iNextMBufSize == KNoOutstandingRequests) |
|
270 && (lowestRequest != growThisPoolChain) ) |
|
271 { |
|
272 iNextMBufSize = lowestRequest; |
|
273 } |
|
274 |
|
275 // Now prepare for the next pool growth if any |
|
276 if (iNextMBufSize != KNoOutstandingRequests) |
|
277 { |
|
278 #ifdef __CFLOG_ACTIVE |
|
279 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::RunL() - One of several pool growth attempts"))); |
|
280 #endif |
|
281 |
|
282 // Still more requests outstanding |
|
283 // iSignalled = ETrue; |
|
284 iStatus = KRequestPending; |
|
285 |
|
286 SetActive(); |
|
287 |
|
288 // complete the request so we get called again |
|
289 TRequestStatus* pStatus = &iStatus; |
|
290 User::RequestComplete(pStatus, KErrNone); |
|
291 } |
|
292 else |
|
293 { |
|
294 // There are no more outstanding requests so prepare for next |
|
295 // pool creation request |
|
296 iStatus = KRequestPending; |
|
297 |
|
298 // open the door for more allocate requests on other pool chains |
|
299 iSignalled = EFalse; |
|
300 SetActive(); |
|
301 } |
|
302 |
|
303 // No need to surround the pool creation with a lock |
|
304 // allocate a pool & associate with the pool chain |
|
305 CMBufPool* newpool = NULL; |
|
306 CreatePool(newpool, *selectedPoolChain); |
|
307 if (newpool == NULL) |
|
308 { |
|
309 // Pool create fails perhaps due to insufficient memory |
|
310 |
|
311 // Each buffer size gets its own out of space indicator |
|
312 selectedPoolChain->iNoMoreSpace = ETrue; |
|
313 } |
|
314 else |
|
315 { |
|
316 // add the pool to the pool list |
|
317 // No need to lock if synchronous allocation is removed |
|
318 iPoolChainLock.Wait(); |
|
319 selectedPoolChain->iPools.AddLast(*newpool); |
|
320 iPoolChainLock.Signal(); |
|
321 |
|
322 // first grab the freelist lock |
|
323 selectedPoolChain->iLockFreeList.Wait(); |
|
324 selectedPoolChain->ExtendFreeList(newpool); |
|
325 selectedPoolChain->iLockFreeList.Signal(); |
|
326 } |
|
327 |
|
328 // open the door for more allocate requests on this poolchain |
|
329 selectedPoolChain->iSignalled = EFalse; |
|
330 |
|
331 } |
|
332 |
|
333 |
|
334 TInt CMBufPoolManager::Commit() |
|
335 /** |
|
336 Ensures that no additional pool chains can be created (ie. via MMBufSizeAllocator::AddL()) |
|
337 Calling this method is useful (but not mandated) to ensure that operations within MMBufSizeAllocator::AddL do not create any adverse affects |
|
338 |
|
339 @return KErrNone or KErrAlreadyExists if already called. |
|
340 */ |
|
341 { |
|
342 TInt result = KErrAlreadyExists; |
|
343 if (iCommitted == EFalse) |
|
344 { |
|
345 iCommitted = ETrue; |
|
346 result = KErrNone; |
|
347 } |
|
348 return result; |
|
349 } |
|
350 |
|
351 // create a pool chain with the specified values |
|
352 // - Deliberately have not exposed the concept of a pool or chain in the api, as these concepts are intended to be hidden within MBM |
|
353 // as a private implementation detail. |
|
354 // - Mbuf size guidelines; |
|
355 // 1. 128 byte is mandatory for some (poorly writen) legacy code that assumes the existance of mbufs of this size. |
|
356 // b. < 128 byte is acceptable, but could break some (poorly written) legacy code that assumes that minimum mbuf size is 128 |
|
357 // - 128 byte guideline is due to K_MBufSmallSize definition having been made public; |
|
358 // a. Externally - numerous instances within our codebase (and thus similar assumptions are likely within licensee code) that assume |
|
359 // mbufs of at least this size are available for allocation. |
|
360 // b. Internally - When the allocation size is not specified, the value is defaulted to K_MBufSmallSize. Refer ::AllocL notes. |
|
361 // - RMBufCells are assumed to be no larger than K_MBufSmallSize. |
|
362 // Since the first point can't be fixed without a source break, there is little point in not creating a default pool chain of |
|
363 // K_MBufSmallSize size in order to rectify the assumptions made within the other points. |
|
364 void CMBufPoolManager::AddL(TInt aMBufSize, TInt aInitialAllocation, TInt aMinGrowth, TInt aGrowthThreshold, TInt aPoolCeiling) |
|
365 /** |
|
366 Populate a free pool of specified size with RMBuf's. Each RMBuf in this free pool will have the same size. |
|
367 |
|
368 RMbuf size guidelines: |
|
369 At least one free pool with 128 byte RMBuf's is mandatory for some legacy code that assumes the existance of mbufs of this size. |
|
370 RMBuf size < 128 byte is acceptable, but could break some legacy code that assumes that minimum mbuf size is 128 |
|
371 These 128 byte guideline are due to KMBufSmallSize definition having been made public. Ideally, this constant should not be published. |
|
372 Instead, inspect the available sizes via RMBufAllocator::NextMBufSize() or the size of this RMBuf with RMBuf::Size(). |
|
373 DO NOT ASSUME UNDER ANY CIRCUMSTANCES THAT ALL MBUFS ARE THE SAME SIZE! |
|
374 |
|
375 @param aMBufSize the size in bytes of the RMBuf's created. |
|
376 @param aInitialAllocation the number of RMBuf's in the initial free pool. |
|
377 @param aMinGrowth the number of RMBuf's added to the free pool. |
|
378 @param aGrowthThreshold when the free pool has less than this number of RMBuf's it will trigger allocation of more memory for more RMBuf's. |
|
379 */ |
|
380 { |
|
381 // check args |
|
382 // - on the surface it makes sense to declare the args as unsigned and rely on the compiler's type checking instead of writing code |
|
383 // to manually check (which has an inherit performance penalty), but as requested this was deliberately not done because; |
|
384 // a. concerns about strict compilers which warn/error arithmetic operations with literals that are not explicitly designeated as unsigned |
|
385 // eg. 1U versus 1 |
|
386 // b. encourages type casting by user to avoid warnings, which circumvents useful compiler type checking & often leads to unexpected results |
|
387 // eg. type casting -1 to unsigned using a 2's compliment compiler resulting in an unexpectedingly large allocation of 2GB |
|
388 __ASSERT_ALWAYS(aMBufSize > 0, CMBufManager::Panic(EMBuf_PoolManager_NegativeMBufSize)); |
|
389 __ASSERT_ALWAYS(aInitialAllocation >= 0, CMBufManager::Panic(EMBuf_PoolManager_NegativePoolSize)); |
|
390 __ASSERT_ALWAYS(aMinGrowth >= 0, CMBufManager::Panic(EMBuf_PoolManager_NegativeMinGrowth)); |
|
391 __ASSERT_ALWAYS(aGrowthThreshold >= 0, CMBufManager::Panic(EMBuf_PoolManager_NegativeGrowthThreshold)); |
|
392 |
|
393 // ensure we are not already committed - refer CMBufPoolManager::Commit notes |
|
394 if (iCommitted) |
|
395 { |
|
396 User::Leave(KErrNotReady); |
|
397 } |
|
398 |
|
399 TInt alignmentPadding = aMBufSize % KMemoryAlignment; |
|
400 if (aMBufSize == 0) |
|
401 { |
|
402 #ifdef __CFLOG_ACTIVE |
|
403 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested mbufSize=0 serves no useful purpose; accepted anyhow"))); |
|
404 #endif |
|
405 } |
|
406 else if (alignmentPadding != 0) |
|
407 { |
|
408 #ifdef __CFLOG_ACTIVE |
|
409 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested mbufSize=%d is not (armv5) dword aligned, size has been increased to %d"), |
|
410 aMBufSize, aMBufSize + KMemoryAlignment - alignmentPadding)); |
|
411 #endif |
|
412 aMBufSize += KMemoryAlignment - alignmentPadding; |
|
413 } |
|
414 if ((aInitialAllocation * aMBufSize) > iMaxAllocSize) |
|
415 { |
|
416 #ifdef __CFLOG_ACTIVE |
|
417 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested initialAllocation=%d exceeds the maxAllocSize=%d; accepted anyhow"), |
|
418 (aInitialAllocation * aMBufSize), iMaxAllocSize)); |
|
419 #endif |
|
420 } |
|
421 if (aMinGrowth == 0) |
|
422 { |
|
423 #ifdef __CFLOG_ACTIVE |
|
424 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested minGrowth=0 increased to the minimum value of 1"))); |
|
425 #endif |
|
426 aMinGrowth = 1; |
|
427 } |
|
428 else if ((aMinGrowth * aMBufSize) > iMaxAllocSize) |
|
429 { |
|
430 #ifdef __CFLOG_ACTIVE |
|
431 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested minGrowth=%d exceeds the maxAllocSize=%d; accepted anyhow"), |
|
432 (aMinGrowth * aMBufSize), iMaxAllocSize)); |
|
433 #endif |
|
434 } |
|
435 if (aGrowthThreshold > aMinGrowth) |
|
436 { |
|
437 #ifdef __CFLOG_ACTIVE |
|
438 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested growthThreshold=%d exceeds minGrowth=%d, hence potentially requiring multiple/iterative growth allocation; accepted anyhow"), |
|
439 aGrowthThreshold, aMinGrowth)); |
|
440 #endif |
|
441 } |
|
442 |
|
443 // check pool chain already exists |
|
444 TInt index = 0; |
|
445 TInt found = KErrNone; |
|
446 if (found == KErrNone) |
|
447 { |
|
448 CMBufPoolChain poolChain(aMBufSize, *this); |
|
449 found = iPoolChains.FindInOrder(&poolChain, index, TLinearOrder<CMBufPoolChain>(CMBufPoolChain::Compare)); |
|
450 } |
|
451 if (found == KErrNotFound) |
|
452 { |
|
453 // create a new pool chain |
|
454 CMBufPoolChain* chain = CMBufPoolChain::NewL(aMBufSize, aInitialAllocation, aMinGrowth, aGrowthThreshold, aPoolCeiling, *this); |
|
455 CleanupStack::PushL(chain); |
|
456 iPoolChains.InsertL(chain, index); |
|
457 CleanupStack::Pop(); // chain |
|
458 |
|
459 // pre-allocate the initial pool |
|
460 if (aInitialAllocation > 0) |
|
461 { |
|
462 // Lock the freelist so that the MBufs can be added to the freepool |
|
463 chain->iLockFreeList.Wait(); |
|
464 |
|
465 // Use synchronous allocate to ensure that the initial pool allocation gives immediate feedback |
|
466 // to the rootserver or calling method. |
|
467 // This can only be called from the owner thread for CMBufManager |
|
468 // Thus synchronous AllocPool is possible because no conflict with asynchronous |
|
469 // background AllocPool occurs because this also is run from the owner thread |
|
470 // for the CMBufManager. Synchronous AllocPool is not allowed from other threads |
|
471 |
|
472 TInt res = AllocPool(*chain, aInitialAllocation, ETrue); |
|
473 chain->iLockFreeList.Signal(); |
|
474 User::LeaveIfError(res); |
|
475 } |
|
476 } |
|
477 else |
|
478 { |
|
479 CMBufPoolChain* poolChain = iPoolChains[index]; |
|
480 // update existing chain's values - these will take affect the next time they are used (eg. next allocation) |
|
481 poolChain->iMinGrowth = aMinGrowth; |
|
482 poolChain->iGrowthThreshold = aGrowthThreshold; |
|
483 } |
|
484 |
|
485 // maintain/update the largest mbuf size - for background allocation |
|
486 if (iLargestMBufSize < aMBufSize) |
|
487 { |
|
488 iLargestMBufSize = aMBufSize; |
|
489 } |
|
490 } |
|
491 |
|
492 void CMBufPoolManager::CreatePool(CMBufPool* &aNewpool, CMBufPoolChain& aMBufPoolChain) |
|
493 { |
|
494 aNewpool = CMBufPool::New(aMBufPoolChain.iBufSize |
|
495 , aMBufPoolChain.iNumMBufsToAdd |
|
496 , aMBufPoolChain |
|
497 , *iMemoryAllocator); |
|
498 } |
|
499 |
|
500 // Search algorithm to find the pool chain satisfying the request size |
|
501 // Algorithm first narrows down to pools chains with free mbufs to satisfy the request size |
|
502 // Then, searches through the remaining pool chains starting from the largest possible pool chain |
|
503 // towards the smallest pool chain until the whole request is satisfied |
|
504 void CMBufPoolManager::LinearSearchAlloc(RMBufQ& aList, TInt aSize |
|
505 , TInt aMinMBufSize, TInt aMaxMBufSize, TBool aIsAllocPool) |
|
506 { |
|
507 // Check to see if an empty mbuf with zero length is requested |
|
508 TBool zeroLengthMBuf = (aSize == 0); |
|
509 |
|
510 TInt poolChainMax = iPoolChains.Count() - 1; |
|
511 |
|
512 // CMBufPoolChain* start = iPoolChains[0]; |
|
513 // CMBufPoolChain* chain = iPoolChains[poolChainMax]; |
|
514 CMBufPoolChain* chosen = NULL; |
|
515 TInt chainIndex = poolChainMax; |
|
516 // First narrow the pool chains to those that are acceptable |
|
517 // Each pool chain represents a free list of mbufs of a particular size |
|
518 // The mbuf size must be within aMinMBufSize - aMaxMBufSize range |
|
519 // The free pool must have space |
|
520 do |
|
521 { |
|
522 CMBufPoolChain* chain = iPoolChains[chainIndex]; |
|
523 // Look for the free pool with the largest mbufs |
|
524 if ( (chain->iBufSize <= aMaxMBufSize) && |
|
525 (chain->iLenFree > 0) ) |
|
526 { |
|
527 // Check that the chosen free pool is within the limits set |
|
528 if (chain->iBufSize >= aMinMBufSize) |
|
529 { |
|
530 // This pool chain has space so found the largest mbufs |
|
531 chosen = chain; |
|
532 break; |
|
533 } |
|
534 // If reached this point: no pool chain to fulfil the request |
|
535 return; |
|
536 } |
|
537 } |
|
538 while (chainIndex-- != 0); |
|
539 |
|
540 // Check to see a if there is a pool chain to fulfil the request |
|
541 if (chosen == NULL) |
|
542 { |
|
543 return; |
|
544 } |
|
545 |
|
546 TInt allocated = 0; |
|
547 TInt extraMem = 0; |
|
548 |
|
549 // Now find the best free pool and allocate the memory |
|
550 do |
|
551 { |
|
552 CMBufPoolChain* chain = iPoolChains[chainIndex]; |
|
553 // At first iteration, this check is false since chain == chosen |
|
554 // and chosen is greater than aMinMBufSize |
|
555 // Check if chain (iterator - smaller than chosen pool chain) |
|
556 // is smaller than requested min size |
|
557 if (chain->iBufSize < aMinMBufSize) |
|
558 { |
|
559 break; |
|
560 } |
|
561 |
|
562 // Test to see if more than one mbuf would be used to |
|
563 // satisfy the request |
|
564 if ( (chain->iBufSize < aSize) && |
|
565 (chain->iLenFree > 0) ) |
|
566 { |
|
567 // Check if chosen is available, just to be secure |
|
568 // Or we have a chosen chain which could complete in 1 mubuf, so choose it |
|
569 if (chosen == NULL || chosen != chain) |
|
570 { |
|
571 break; |
|
572 } |
|
573 // Chosen is the next largest mbuf size so this allocation |
|
574 // can be satisfied with the chosen free pool |
|
575 allocated = chosen->Alloc(aList, aSize, aIsAllocPool); |
|
576 |
|
577 // Check if the allocation is complete |
|
578 if (allocated >= aSize) |
|
579 { |
|
580 // Test if no smaller chains |
|
581 // or no need to check for smaller |
|
582 if ((chainIndex == 0) || (allocated == aSize)) |
|
583 { |
|
584 // Allocation is complete |
|
585 aSize = 0; |
|
586 chosen = NULL; |
|
587 break; |
|
588 } |
|
589 |
|
590 // By swapping the first mbuf with a smaller mbuf it might |
|
591 // be possible to fit the remainder into a smaller mbuf that |
|
592 // wastes less memory |
|
593 extraMem = chosen->iBufSize + aSize - allocated; |
|
594 CMBufPoolChain* smallerChain = iPoolChains[chainIndex - 1]; |
|
595 // Check to see if the remainder can fit into a smaller mbuf |
|
596 if ( extraMem <= smallerChain->iBufSize && smallerChain->iBufSize >= aMinMBufSize ) |
|
597 { |
|
598 // It can fit |
|
599 // Set request size to this remaining size so that the algorithm |
|
600 // will continue searching for this remaining size |
|
601 aSize = extraMem; |
|
602 // Set chosen to null so that when the search cannot find a |
|
603 // smaller mbuf for remaining size the algorithm will know this |
|
604 chosen = NULL; |
|
605 // No break - continue searching for remainder |
|
606 } |
|
607 else |
|
608 { |
|
609 // Remainder is large to fit in a smaller mbuf |
|
610 // Allocation is complete |
|
611 aSize = 0; |
|
612 chosen = NULL; |
|
613 break; |
|
614 } |
|
615 } |
|
616 else |
|
617 { |
|
618 // No space left in the free pool so look for |
|
619 // a smaller mbuf to satisfy the request |
|
620 aSize -= allocated; |
|
621 } |
|
622 } |
|
623 |
|
624 // Best free pool not found yet |
|
625 // Test to see if this free pool is a better choice |
|
626 if ( (aSize <= chain->iBufSize) && |
|
627 (chain->iLenFree > 0) ) |
|
628 { |
|
629 chosen = chain; |
|
630 } |
|
631 } |
|
632 while (chainIndex-- != 0); |
|
633 |
|
634 // There is a chosen pool but the request is not satisfied yet due to: |
|
635 // 1. Requested size is smaller than the smallest pool chain |
|
636 // 2. Most suitable pool chain has no free space |
|
637 // 3. An empty mbuf with zero length is requested |
|
638 // 4. Request size was assigned with remaining size and a pool chain is found |
|
639 // for that remaining size |
|
640 if ((chosen != NULL) && ((aSize > 0) || (zeroLengthMBuf))) |
|
641 { |
|
642 // This chosen free pool will have to do |
|
643 RMBufQ bList; |
|
644 TInt allocated = chosen->Alloc(bList, aSize, aIsAllocPool); |
|
645 // Test for successful allocation |
|
646 if (allocated >= aSize) |
|
647 { |
|
648 // If this allocation is for remaining size swap the extra mbuf with |
|
649 // the allocated one |
|
650 if (extraMem > 0) |
|
651 { |
|
652 // Allocation worked so swap this smaller mbuf thus saving space |
|
653 RMBuf* first = aList.RemoveLast(); |
|
654 // Free the first mbuf |
|
655 Free(first, ETrue); |
|
656 } |
|
657 aList.Append(bList); |
|
658 aSize = 0; |
|
659 } |
|
660 } |
|
661 |
|
662 // If no chosen pool for remaining size but the allocation was successful |
|
663 if (extraMem > 0) |
|
664 { |
|
665 // Allocation is complete |
|
666 aSize = 0; |
|
667 } |
|
668 |
|
669 // If allocated mbuf is insufficient to fulfill the req empty the list |
|
670 if (aSize > 0) |
|
671 { |
|
672 Free(aList.First(), ETrue); |
|
673 aList.Init(); |
|
674 } |
|
675 } |
|
676 |
|
677 // Finds poolchains that will satisfy the request size using linear search, |
|
678 // and allocates and initialises a chain of MBufs |
|
679 RMBuf* CMBufPoolManager::Alloc(TInt aSize, TInt aMinMBufSize, TInt aMaxMBufSize, TBool aIsAllocPool) |
|
680 { |
|
681 RMBufQ list; |
|
682 |
|
683 TInt poolChainsCount = iPoolChains.Count(); |
|
684 __ASSERT_DEBUG(poolChainsCount != 0, CMBufManager::Panic(EMBuf_NoPoolChain)); |
|
685 |
|
686 #ifdef _DEBUG |
|
687 if (poolChainsCount == 0) |
|
688 { |
|
689 #ifdef __CFLOG_ACTIVE |
|
690 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::Alloc() - Error! no mbuf pool chain exists"))); |
|
691 #endif |
|
692 } |
|
693 else if (iLargestMBufSize < aSize) |
|
694 { |
|
695 #ifdef __CFLOG_ACTIVE |
|
696 __CFLOG_VAR((KSubsysMBufMgr, KComponentPerformance, _L8("CMBufPoolManager::Alloc() - Warning! sub-optimal performance; biggest chain doesn't satisfy the request with one mbuf, aSize=%d chainSize=%d"), |
|
697 aSize, iLargestMBufSize)); |
|
698 #endif |
|
699 } |
|
700 #endif |
|
701 |
|
702 // Do the allocation |
|
703 LinearSearchAlloc(list, aSize, aMinMBufSize, aMaxMBufSize, aIsAllocPool); |
|
704 |
|
705 #ifdef _DEBUG |
|
706 if (list.IsEmpty()) |
|
707 { |
|
708 #ifdef __CFLOG_ACTIVE |
|
709 __CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::Alloc() - Warning! no matching poolChain found, aSize=%d aMinMBufSize=%d aMaxMBufSize=%d"), |
|
710 aSize, aMinMBufSize, aMaxMBufSize)); |
|
711 #endif |
|
712 } |
|
713 #endif |
|
714 |
|
715 // At this point, list should be a linked list of all the RMBufs necessary to satisfy the memory request. |
|
716 // - mark each one to indicate that it's now being used for buffer data. |
|
717 RMBuf* mBuf; |
|
718 for (mBuf = list.First(); mBuf != NULL; mBuf = mBuf->Next()) |
|
719 { |
|
720 __ASSERT_DEBUG(mBuf->Type() == EMBufFree, CMBufManager::Panic(EMBuf_AllreadyAlloc)); |
|
721 mBuf->SetType(EMBufData); |
|
722 #ifdef _MBUF_TEST |
|
723 Mem::Fill(mBuf->Buffer(), mBuf->Size(), '#'); |
|
724 #endif |
|
725 } |
|
726 |
|
727 return list.First(); |
|
728 } |
|
729 |
|
730 // return a chain of MBufs to the pool |
|
731 void CMBufPoolManager::Free(RMBuf* aMBuf, TBool aIsPreAlloc) |
|
732 { |
|
733 |
|
734 TBool sameSize = EFalse; |
|
735 |
|
736 while (aMBuf != NULL) |
|
737 { |
|
738 RMBuf* nextMBuf = aMBuf->Next(); |
|
739 |
|
740 // when aIsPreAlloc is true that means called from Alloc: |
|
741 // total allocation for the request is unsuccessful so freeing the allocated MBufs |
|
742 __ASSERT_DEBUG(aIsPreAlloc || aMBuf->Type() != EMBufFree, CMBufManager::Panic(EMBuf_AllreadyFree)); |
|
743 |
|
744 aMBuf->SetType(EMBufFree); |
|
745 aMBuf->SetData(0, aMBuf->Size()); // reset length to the size of the mbuf, subsequent ::Alloc can update this if required |
|
746 |
|
747 aMBuf->Unlink(); |
|
748 |
|
749 // update pool chain - eg. free list members |
|
750 // placeholder for REQ7864 (de-allocation of mbufs), the return of mbufs to the free list should/could be more intelligent |
|
751 // than merely pre-pending as is currently the case. Eg. examine the pool and corresponding dchunk they belong too to |
|
752 // determine if the mbufs should be given priority to be used or de-allocated in the future |
|
753 // or alternatively leave marked mbuf's as orphans and mark the mbufs that need to be de-allocated in this way in the memory manager |
|
754 CMBufPoolChain* poolChain = static_cast<CMBufPoolChain*>(aMBuf->Pool()); |
|
755 __ASSERT_DEBUG(poolChain->iBufSize > 0, User::Invariant()); |
|
756 |
|
757 if (!sameSize) |
|
758 { |
|
759 poolChain->iLockFreeList.Wait(); |
|
760 } |
|
761 poolChain->iFreeMBufs.Prepend(aMBuf); // prepends a single mbuf, ie. not any mbufs that may be pointed to by this mbuf |
|
762 poolChain->iLenFree += aMBuf->Size(); |
|
763 |
|
764 if (nextMBuf) |
|
765 { |
|
766 sameSize = aMBuf->Size() == nextMBuf->Size(); |
|
767 } |
|
768 |
|
769 aMBuf = nextMBuf; |
|
770 |
|
771 // free mbufs within the chain |
|
772 // - care taken to ensure correct handling of different sized mbufs |
|
773 if (nextMBuf == NULL || !sameSize) |
|
774 { |
|
775 poolChain->iLockFreeList.Signal(); |
|
776 } |
|
777 } |
|
778 |
|
779 // when aIsPreAlloc is true that means called from Alloc: |
|
780 // total allocation for the request is unsuccessful so freeing the allocated MBufs |
|
781 if (!aIsPreAlloc) |
|
782 { |
|
783 iMBufManager.CallBackAfterFree(); |
|
784 } |
|
785 } |
|
786 |
|
787 // allocate a memory pool & merge it into the pool chain |
|
788 TInt CMBufPoolManager::AllocPool(CMBufPoolChain& aPoolChain, TInt aSize, TBool aIsSynchronous) |
|
789 { |
|
790 // verify that the maximum size will not be exceeded ie; ceiling is not yet touched |
|
791 if(aPoolChain.HonourPoolCeiling()) |
|
792 { |
|
793 if(aPoolChain.CanExtend()) |
|
794 { |
|
795 // Alloate as much as we can |
|
796 aSize = (aPoolChain.ExtendSize() < aSize) ? aPoolChain.ExtendSize() : aSize; |
|
797 } |
|
798 else |
|
799 { |
|
800 return KErrNoMBufs; |
|
801 } |
|
802 } |
|
803 else |
|
804 { |
|
805 if ((iAllocSize + aSize * aPoolChain.iBufSize) > iMaxAllocSize) |
|
806 { |
|
807 return KErrNoMBufs; |
|
808 } |
|
809 } |
|
810 |
|
811 /* |
|
812 */ |
|
813 if (aIsSynchronous) |
|
814 { |
|
815 // this is only valid if called from the thread that owns the CMBufManager |
|
816 // the RHeap is created in that thread and its handle is only valid in that thread |
|
817 CMBufPool* newpool = CMBufPool::New(aPoolChain.iBufSize, |
|
818 aSize, aPoolChain, *iMemoryAllocator); |
|
819 if (newpool != NULL) |
|
820 { |
|
821 iPoolChainLock.Wait(); |
|
822 aPoolChain.iPools.AddLast(*newpool); |
|
823 iPoolChainLock.Signal(); |
|
824 |
|
825 aPoolChain.ExtendFreeList(newpool); |
|
826 |
|
827 iAllocSize += aSize * aPoolChain.iBufSize; |
|
828 return KErrNone; |
|
829 } |
|
830 return KErrNoMBufs; |
|
831 } |
|
832 return BackgroundAllocateNewPool(aPoolChain, aSize); |
|
833 } |
|
834 |
|
835 TInt CMBufPoolManager::BytesAvailable() |
|
836 // runtime metrics |
|
837 // The total number of available bytes that MBufMgr has avaiable in it's free lists. |
|
838 { |
|
839 TInt bytes = 0; |
|
840 TUint poolChainsCount = iPoolChains.Count(); |
|
841 for (TUint i = 0; i < poolChainsCount; i++) |
|
842 { |
|
843 bytes += iPoolChains[i]->iLenFree; |
|
844 } |
|
845 return bytes; |
|
846 } |
|
847 |
|
848 TInt CMBufPoolManager::BytesAvailable(TInt aSize) |
|
849 // runtime metrics |
|
850 // The total number of available bytes that MBufMgr has avaiable in a given free list. |
|
851 { |
|
852 TInt index = iPoolChains.FindInOrder((TInt)aSize, CMBufPoolChain::Compare); |
|
853 if (index != KErrNotFound) |
|
854 { |
|
855 return iPoolChains[index]->iLenFree; |
|
856 } |
|
857 return 0; |
|
858 } |
|
859 |
|
860 TInt CMBufPoolManager::NextMBufSize(TInt aSize) |
|
861 // runtime metrics |
|
862 { |
|
863 TInt index = 0; |
|
864 TUint poolChainsCount = iPoolChains.Count(); |
|
865 while(index < poolChainsCount) |
|
866 { |
|
867 if (iPoolChains[index]->iBufSize > aSize ) |
|
868 { |
|
869 return iPoolChains[index]->iBufSize; |
|
870 } |
|
871 ++index; |
|
872 } |
|
873 return KErrNotFound; |
|
874 } |
|
875 |
|
876 TInt CMBufPoolManager::BytesAllocated() |
|
877 { |
|
878 return iMemoryAllocator->AllocBytes(); |
|
879 } |
|
880 |
|
881 #ifdef _MBUF_TEST |
|
882 |
|
883 TInt CMBufPoolManager::__DbgCheckBuffer(RMBuf* aBuf) |
|
884 // |
|
885 // For each pool within the corresponding chain, try to locate aBuf |
|
886 // |
|
887 { |
|
888 if (aBuf==NULL) |
|
889 { |
|
890 return 0; |
|
891 } |
|
892 |
|
893 TInt n=-1; |
|
894 CMBufPool* pool; |
|
895 |
|
896 TInt index = iPoolChains.FindInOrder((TInt)aBuf->Size(), CMBufPoolChain::Compare); |
|
897 if (index != KErrNotFound) |
|
898 { |
|
899 CMBufPoolChain* poolChain = iPoolChains[index]; |
|
900 |
|
901 TDblQueIter<CMBufPool> list(poolChain->iPools); |
|
902 |
|
903 if (poolChain->iPools.IsEmpty()) |
|
904 { |
|
905 return 0; |
|
906 } |
|
907 |
|
908 // iteratively invoke to locate the required mbuf |
|
909 while (n==-1 && (pool = list++, pool!=NULL)) |
|
910 { |
|
911 n = pool->__DbgCheckBuffer(aBuf); |
|
912 } |
|
913 |
|
914 if (n<0) |
|
915 { |
|
916 CMBufManager::Panic(EMBuf_NotAnMBuf); |
|
917 } |
|
918 } |
|
919 return n; |
|
920 } |
|
921 |
|
922 // retrieve free space for all pool chains |
|
923 TUint CMBufPoolManager::__DbgGetBufSpace() |
|
924 { |
|
925 int len = 0; |
|
926 TUint poolChainsCount = iPoolChains.Count(); |
|
927 for (TUint i = 0; i < poolChainsCount; i++) |
|
928 { |
|
929 len += iPoolChains[i]->iLenFree; |
|
930 } |
|
931 return len; |
|
932 } |
|
933 |
|
934 // get free space for pool chain with matching mbuf size |
|
935 TUint CMBufPoolManager::__DbgGetBufSpace(TUint aMBufSize) |
|
936 { |
|
937 TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare); |
|
938 if (index != KErrNotFound) |
|
939 { |
|
940 return iPoolChains[index]->iLenFree; |
|
941 } |
|
942 return 0; |
|
943 } |
|
944 |
|
945 // get used space for all pool chains |
|
946 TUint CMBufPoolManager::__DbgGetBufTotal() |
|
947 { |
|
948 int len = 0; |
|
949 TUint poolChainsCount = iPoolChains.Count(); |
|
950 for (TUint i = 0; i < poolChainsCount; i++) |
|
951 { |
|
952 len += iPoolChains[i]->iLenTotal; |
|
953 } |
|
954 return len; |
|
955 } |
|
956 |
|
957 // get used space for pool chain with matching mbuf size |
|
958 TUint CMBufPoolManager::__DbgGetBufTotal(TUint aMBufSize) |
|
959 { |
|
960 TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare); |
|
961 if (index != KErrNotFound) |
|
962 { |
|
963 return iPoolChains[index]->iLenTotal; |
|
964 } |
|
965 return 0; |
|
966 } |
|
967 |
|
968 // return the first mbuf in the free list belong to the first chain |
|
969 RMBuf* CMBufPoolManager::__DbgMBufChain() |
|
970 { |
|
971 if (iPoolChains.Count() > 0) |
|
972 { |
|
973 return iPoolChains[0]->iFreeMBufs.First(); |
|
974 } |
|
975 return NULL; |
|
976 } |
|
977 // return the first mbuf in the free list belonging to the chain of the specified mbuf size |
|
978 RMBuf* CMBufPoolManager::__DbgMBufChain(TUint aMBufSize) |
|
979 { |
|
980 TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare); |
|
981 if (index != KErrNotFound) |
|
982 { |
|
983 return iPoolChains[index]->iFreeMBufs.First(); |
|
984 } |
|
985 return 0; |
|
986 } |
|
987 |
|
988 // update the max pool limit (debug only) - use the first pool chain |
|
989 void CMBufPoolManager::__DbgSetPoolLimit(TInt aCount) |
|
990 { |
|
991 if (iPoolChains.Count() > 0) |
|
992 { |
|
993 iPoolChains[0]->iDbgPoolLimit = aCount - (aCount % iPoolChains[0]->iBufSize); |
|
994 } |
|
995 } |
|
996 // update the max pool limit (debug only) - for the specified mbuf size |
|
997 void CMBufPoolManager::__DbgSetPoolLimit(TInt aCount, TUint aMBufSize) |
|
998 { |
|
999 TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare); |
|
1000 if (index != KErrNotFound) |
|
1001 { |
|
1002 CMBufPoolChain* poolChain = iPoolChains[index]; |
|
1003 poolChain->iDbgPoolLimit = aCount - (aCount % poolChain->iBufSize); |
|
1004 } |
|
1005 } |
|
1006 |
|
1007 #endif //#ifdef _MBUF_TEST |
|
1008 |
|
1009 // |
|
1010 // MBUF POOLS |
|
1011 // |
|
1012 |
|
1013 // overloaded new operator |
|
1014 // - allocates pools on the RHeap instead of the std thread heap |
|
1015 // - placeholder for substituting RHeap with RChunk for either/all; |
|
1016 // a. creating |
|
1017 // b. growing - req's handle to existing... handle likely stored within CMBM and accessed via a friend |
|
1018 TAny* CMBufPool::operator new(TUint aSize, TInt aExtra, CMBufMemoryAllocator& aMemoryAllocator) __NO_THROW |
|
1019 { |
|
1020 TAny* p = aMemoryAllocator.Alloc(aSize + aExtra); |
|
1021 return p; |
|
1022 } |
|
1023 |
|
1024 void CMBufPool::operator delete(TAny* aPtr) __NO_THROW |
|
1025 { |
|
1026 if (aPtr) |
|
1027 { |
|
1028 ((CMBufPool* )aPtr)->iMemoryAllocator.Free(aPtr); |
|
1029 } |
|
1030 } |
|
1031 |
|
1032 /** |
|
1033 * extra delete operator for exception unwinding in Code Warrior |
|
1034 */ |
|
1035 void CMBufPool::operator delete(TAny* aPtr, TInt /*aExtra*/, CMBufMemoryAllocator& /*aMemoryAllocator*/) __NO_THROW |
|
1036 { |
|
1037 CMBufPool::operator delete(aPtr); |
|
1038 } |
|
1039 |
|
1040 CMBufPool::CMBufPool(TInt aMBufSize, TInt aNumMBufs, CMBufMemoryAllocator& aMemoryAllocator) |
|
1041 : CBase() |
|
1042 , iNumMBufs(aNumMBufs) |
|
1043 , iMBufSize(aMBufSize) |
|
1044 , iMemoryAllocator(aMemoryAllocator) |
|
1045 { |
|
1046 } |
|
1047 |
|
1048 // Create and return a new mbuf pool |
|
1049 CMBufPool* CMBufPool::New(TInt aMBufSize, TInt aNumMBufs, CMBufPoolChain& aMBufPoolChain, CMBufMemoryAllocator& aMemoryAllocator) |
|
1050 { |
|
1051 // allocate pool on the RHeap via an overloaded ::new operator (not obvious here) |
|
1052 TInt rmbufsize = ALIGN_CACHE_UP(sizeof(RMBuf)); |
|
1053 TInt mbufsize = ALIGN_CACHE_UP(aMBufSize); |
|
1054 CMBufPool* pool = new(aNumMBufs * (rmbufsize + mbufsize), aMemoryAllocator) CMBufPool(mbufsize, aNumMBufs, aMemoryAllocator); |
|
1055 if (pool != NULL) |
|
1056 { |
|
1057 TUint8* poolSize = ((TUint8*) pool) + sizeof(CMBufPool); |
|
1058 |
|
1059 // buffers must be aligned so that MBUF_ALIGN() will work |
|
1060 __ASSERT_DEBUG(IS_ALIGNED(poolSize), CMBufManager::Panic(EMBuf_NotAligned)); |
|
1061 |
|
1062 TInt rmbufsize = ALIGN_CACHE_UP(sizeof(RMBuf)); |
|
1063 TInt actualBufStart = (aNumMBufs * rmbufsize); |
|
1064 for (TInt i=0; i<aNumMBufs; i++) |
|
1065 { |
|
1066 // overloaded new operator - in place allocation at the specified address |
|
1067 TUint8* ptr = poolSize + i * rmbufsize; |
|
1068 TInt bufStart = (actualBufStart + (i * mbufsize)) - (i* rmbufsize); |
|
1069 RCommsBuf* buf = new(ptr) RCommsBuf (bufStart, aMBufSize, aMBufPoolChain.Id()); |
|
1070 pool->iList.Append(static_cast<RMBuf*>(buf)); |
|
1071 } |
|
1072 } |
|
1073 return pool; |
|
1074 } |
|
1075 |
|
1076 CMBufPool::~CMBufPool() |
|
1077 // |
|
1078 // |
|
1079 // |
|
1080 { |
|
1081 iLink.Deque(); |
|
1082 } |
|
1083 |
|
1084 |
|
1085 void CMBufPool::Merge(RMBufQ &aFreeList) |
|
1086 // |
|
1087 // |
|
1088 // |
|
1089 { |
|
1090 aFreeList.Append(iList); |
|
1091 } |
|
1092 |
|
1093 #ifdef _MBUF_TEST |
|
1094 TInt CMBufPool::__DbgCheckBuffer(RMBuf* aBuf) |
|
1095 // |
|
1096 // Given an mbuf ptr, returns its number in this pool |
|
1097 // |
|
1098 { |
|
1099 TUint8* p = (TUint8*)aBuf; |
|
1100 TUint8* s = ((TUint8*) this) + sizeof(CMBufPool); |
|
1101 TUint8* e = s + (iNumMBufs * sizeof(RMBuf)); |
|
1102 |
|
1103 if (p<s) |
|
1104 { |
|
1105 return -1; |
|
1106 } |
|
1107 else if (p<e) |
|
1108 { |
|
1109 return 1 + ((p-s) / sizeof(RMBuf)); |
|
1110 } |
|
1111 s = e; |
|
1112 e = s + (iNumMBufs * aBuf->Size()); |
|
1113 if (p>=e) |
|
1114 { |
|
1115 return -1; |
|
1116 } |
|
1117 else |
|
1118 { |
|
1119 CMBufManager::Panic(EMBuf_CorruptMBuf); |
|
1120 } |
|
1121 |
|
1122 return -2 - ((p-s) / aBuf->Size()); |
|
1123 } |
|
1124 #else |
|
1125 TInt CMBufPool::__DbgCheckBuffer(RMBuf* /*aBuf*/) |
|
1126 { |
|
1127 return KErrNone; |
|
1128 } |
|
1129 |
|
1130 #endif |
|
1131 |