|
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 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Buffer Manager for Protocols |
|
15 // |
|
16 // |
|
17 |
|
18 |
|
19 |
|
20 #include <comms-infras/cfperfmetrics.h> |
|
21 #include "mbufmanager.h" |
|
22 #include "es_prot.h" // for ESocketTimerPriority |
|
23 #include <e32hal.h> |
|
24 #include <comms-infras/cfmacro.h> |
|
25 #include "MBufPoolChain.h" |
|
26 #include "MBufTimer.h" |
|
27 #include "MBufPool.h" |
|
28 #include "MBufSizeAllocator.h" |
|
29 #include "MBufPoolManager.h" |
|
30 #include "MBufMemoryAllocator.h" |
|
31 #include <cflog.h> |
|
32 #include <comms-infras/commsbufpond.h> |
|
33 #include <comms-infras/commsbufpondop.h> |
|
34 #include <comms-infras/mbufasyncrequest.h> |
|
35 |
|
36 #ifdef __CFLOG_ACTIVE |
|
37 __CFLOG_STMT(_LIT8(KComponent, "Manager");) |
|
38 __CFLOG_STMT(_LIT8(KSubsysMBufMgr, "MBufMgr");) // subsystem name |
|
39 #endif |
|
40 |
|
41 /** |
|
42 MBuf Private Heap Limits |
|
43 |
|
44 @internalTechnology |
|
45 */ |
|
46 static const TInt KMBufFreePriority = 20; |
|
47 |
|
48 |
|
49 // The asynchronous allocations have to be requested by the thread that created the MBufMgr |
|
50 // This we do by having a requester object in that thread which gets completed by the other |
|
51 // threads to trigger the request |
|
52 NONSHARABLE_CLASS(CRequestAsyncAlloc) : public CActive |
|
53 { |
|
54 public: |
|
55 static CRequestAsyncAlloc* NewL(); |
|
56 virtual ~CRequestAsyncAlloc(); |
|
57 |
|
58 void StartWaitForRequest(); |
|
59 void MakeRequest(); |
|
60 private: |
|
61 CRequestAsyncAlloc(); |
|
62 void ConstructL(); |
|
63 |
|
64 virtual void DoCancel(); |
|
65 virtual void RunL(); |
|
66 RCriticalSection iCritSec; |
|
67 RThread iMBufMgrOwnerThread; |
|
68 TBool iSignalled; |
|
69 }; |
|
70 |
|
71 |
|
72 CRequestAsyncAlloc::CRequestAsyncAlloc() |
|
73 : CActive(0) |
|
74 { |
|
75 } |
|
76 |
|
77 CRequestAsyncAlloc* CRequestAsyncAlloc::NewL() |
|
78 { |
|
79 CRequestAsyncAlloc* This = new(ELeave) CRequestAsyncAlloc; |
|
80 CleanupStack::PushL(This); |
|
81 This->ConstructL(); |
|
82 CleanupStack::Pop(This); |
|
83 return This; |
|
84 } |
|
85 |
|
86 void CRequestAsyncAlloc::ConstructL() |
|
87 { |
|
88 User::LeaveIfError(iCritSec.CreateLocal()); |
|
89 iMBufMgrOwnerThread.Duplicate(RThread()); |
|
90 CActiveScheduler::Add(this); |
|
91 } |
|
92 |
|
93 CRequestAsyncAlloc::~CRequestAsyncAlloc() |
|
94 { |
|
95 Deque(); |
|
96 iCritSec.Close(); |
|
97 iMBufMgrOwnerThread.Close(); |
|
98 } |
|
99 |
|
100 void CRequestAsyncAlloc::StartWaitForRequest() |
|
101 { |
|
102 __ASSERT_DEBUG(!IsActive(), CMBufManager::Panic(EMBuf_AlreadyActive)); |
|
103 iStatus = KRequestPending; |
|
104 SetActive(); |
|
105 } |
|
106 |
|
107 void CRequestAsyncAlloc::MakeRequest() |
|
108 { |
|
109 NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications |
|
110 // This is being most likely being called from the context of some thread other than the |
|
111 // MBufMgr owner, and there's a distinct risk of more than one thread being OOB at the same |
|
112 // time since it's a common pool. So here we have to guard against being completed multiple |
|
113 // times, using a critical section because there's a tiny but real risk of a completion from |
|
114 // another thread in between a test upon IsActive() and our completion of it, which could give |
|
115 // a stray event panic |
|
116 if(!iSignalled) |
|
117 { |
|
118 // We're almost certainly the only thread doing this; now check again inside the critsec to be sure |
|
119 iCritSec.Wait(); |
|
120 if(!iSignalled) |
|
121 { |
|
122 iSignalled = ETrue; |
|
123 TRequestStatus* pStatus = &iStatus; |
|
124 iMBufMgrOwnerThread.RequestComplete(pStatus, KErrNone); |
|
125 } |
|
126 iCritSec.Signal(); |
|
127 } |
|
128 } |
|
129 |
|
130 |
|
131 void CRequestAsyncAlloc::DoCancel() |
|
132 { |
|
133 NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications |
|
134 if(!iSignalled) |
|
135 { |
|
136 // We're almost certainly the only thread doing this; now check again inside the critsec to be sure |
|
137 iCritSec.Wait(); |
|
138 if(!iSignalled) |
|
139 { |
|
140 iSignalled = ETrue; |
|
141 TRequestStatus* pStatus = &iStatus; |
|
142 User::RequestComplete(pStatus, KErrCancel); |
|
143 } |
|
144 iCritSec.Signal(); |
|
145 } |
|
146 } |
|
147 |
|
148 void CRequestAsyncAlloc::RunL() |
|
149 { |
|
150 // Now that we're in the thread that owns the timer we can reset it |
|
151 CMBufManager::Context()->WatchDogReset(); |
|
152 // Ready for the next cry of OOB distress |
|
153 iStatus = KRequestPending; |
|
154 iSignalled = EFalse; |
|
155 SetActive(); |
|
156 } |
|
157 |
|
158 // |
|
159 // MBUF MANAGER |
|
160 // |
|
161 |
|
162 CMBufManager::CMBufManager() |
|
163 /** |
|
164 MBUF MANAGER |
|
165 */ |
|
166 { |
|
167 #ifdef __CFLOG_ACTIVE |
|
168 __CFLOG_1(KSubsysMBufMgr, KComponent, _L8("CMBufManager %x:\tCMBufManager()"), this); |
|
169 #endif |
|
170 |
|
171 iAllocsPending.SetOffset(_FOFF(CCommsBufAsyncRequest,iLink)); |
|
172 #ifdef SYMBIAN_NETWORKING_PERFMETRICS |
|
173 CommsFW::CPerfMetricStore::AddClient(this, AddToPerfLog); |
|
174 #endif |
|
175 } |
|
176 |
|
177 |
|
178 void CMBufManager::Panic(TMBufPanic aPanic) |
|
179 /** |
|
180 For use by mbuf related classes |
|
181 */ |
|
182 { |
|
183 _LIT(mbuf,"MBuf"); |
|
184 User::Panic(mbuf, aPanic); |
|
185 } |
|
186 |
|
187 |
|
188 CMBufManager::~CMBufManager() |
|
189 // |
|
190 // |
|
191 // |
|
192 { |
|
193 #ifdef SYMBIAN_NETWORKING_PERFMETRICS |
|
194 CommsFW::CPerfMetricStore::RemoveClient(this); |
|
195 #endif |
|
196 |
|
197 if (iRequestAsyncAlloc) |
|
198 { |
|
199 iRequestAsyncAlloc->Cancel(); |
|
200 delete iRequestAsyncAlloc; |
|
201 iRequestAsyncAlloc = NULL; |
|
202 } |
|
203 |
|
204 while (!iAllocsPending.IsEmpty()) |
|
205 { |
|
206 CancelRequest(*iAllocsPending.First()); |
|
207 } |
|
208 |
|
209 if (iFreeCB!=NULL) |
|
210 { |
|
211 delete iFreeCB; |
|
212 } |
|
213 |
|
214 iAsynAllocLock.Close(); |
|
215 |
|
216 delete iTimer; |
|
217 |
|
218 if (iMBufPoolManager) |
|
219 { |
|
220 delete iMBufPoolManager; |
|
221 } |
|
222 Dll::SetTls(NULL); |
|
223 } |
|
224 |
|
225 |
|
226 EXPORT_C MCommsBufPondIntf* CMBufManager::New(RArray <TCommsBufPoolCreateInfo>& aPoolInfo, RLibrary& aLibrary, TInt aMaxHeapSize) |
|
227 { |
|
228 CMBufManager* self = new CMBufManager(aLibrary); |
|
229 if (self) |
|
230 { |
|
231 Dll::SetTls(self); |
|
232 TRAPD( err, self->ConstructL(aPoolInfo, aMaxHeapSize)); |
|
233 if( err != KErrNone) |
|
234 { |
|
235 Dll::SetTls(NULL); |
|
236 delete self; |
|
237 return NULL; |
|
238 } |
|
239 |
|
240 } |
|
241 return self; |
|
242 } |
|
243 |
|
244 void CMBufManager::ConstructL(RArray <TCommsBufPoolCreateInfo>& aPoolInfo, TInt aMaxHeapSize) |
|
245 { |
|
246 // Calculate the total heapsize |
|
247 TInt totalHeapSize = aMaxHeapSize; |
|
248 if(aMaxHeapSize == 0) |
|
249 { |
|
250 for (TInt i = 0; i < aPoolInfo.Count(); ++i) |
|
251 { |
|
252 totalHeapSize += (aPoolInfo[i].iCeiling * (ALIGN_UP(sizeof(RMBuf)) + ALIGN_UP(aPoolInfo[i].iBufSize))); |
|
253 } |
|
254 } |
|
255 ConstructL(totalHeapSize); |
|
256 for (TInt i = 0; i < aPoolInfo.Count(); ++i) |
|
257 { |
|
258 iMBufPoolManager->AddL(aPoolInfo[i].iBufSize, aPoolInfo[i].iInitialBufs, aPoolInfo[i].iGrowByBufs, aPoolInfo[i].iMinFreeBufs, aPoolInfo[i].iCeiling * aPoolInfo[i].iBufSize); |
|
259 } |
|
260 } |
|
261 |
|
262 CMBufManager::CMBufManager(RLibrary& aLibrary) |
|
263 : iLibrary(aLibrary) |
|
264 { |
|
265 #ifdef __CFLOG_ACTIVE |
|
266 __CFLOG_1(KSubsysMBufMgr, KComponent, _L8("CMBufManager %x:\tCMBufManager()"), this); |
|
267 #endif |
|
268 |
|
269 iAllocsPending.SetOffset(_FOFF(CCommsBufAsyncRequest,iLink)); |
|
270 #ifdef SYMBIAN_NETWORKING_PERFMETRICS |
|
271 CommsFW::CPerfMetricStore::AddClient(this, AddToPerfLog); |
|
272 #endif |
|
273 } |
|
274 |
|
275 void CMBufManager::ConstructL(TInt aMaxHeapSize) |
|
276 // |
|
277 // |
|
278 // |
|
279 { |
|
280 User::LeaveIfError(iAsynAllocLock.CreateLocal()); |
|
281 |
|
282 TCallBack c(FreeCallBack, this); |
|
283 |
|
284 // create an instance of the mbuf pool manager |
|
285 // - used to handle all pool allocation manipulation, also used as a concrete class for limited public interfaces exposed |
|
286 // to the client |
|
287 |
|
288 iMBufPoolManager = CMBufPoolManager::NewL(aMaxHeapSize, *this); |
|
289 CleanupStack::PushL(iMBufPoolManager); |
|
290 |
|
291 iFreeCB = new(ELeave) CAsyncCallBack(c, KMBufFreePriority); |
|
292 CleanupStack::PushL(iFreeCB); |
|
293 |
|
294 iTimer=CDeltaTimer::NewL(EMBufMgrTimerPriority, KMbufManTimerGranularity); |
|
295 CleanupStack::PushL(iTimer); |
|
296 |
|
297 iTimerThreadId = RThread().Id(); |
|
298 |
|
299 iRequestAsyncAlloc = CRequestAsyncAlloc::NewL(); |
|
300 |
|
301 iRequestAsyncAlloc->StartWaitForRequest(); |
|
302 |
|
303 CleanupStack::Pop(iTimer); |
|
304 CleanupStack::Pop(iFreeCB); |
|
305 CleanupStack::Pop(iMBufPoolManager); |
|
306 } |
|
307 |
|
308 CMBufManager* CMBufManager::Context() |
|
309 // There is a single system-wide MBuf manager. |
|
310 { |
|
311 CMBufManager* pMgr = STATIC_CAST(CMBufManager*, Dll::Tls()); |
|
312 __ASSERT_ALWAYS(pMgr != NULL, Panic(EMBuf_NoManager)); |
|
313 return pMgr; |
|
314 } |
|
315 |
|
316 void CMBufManager::SetContext() |
|
317 // There is a single system-wide MBuf manager. |
|
318 { |
|
319 Dll::SetTls(this); |
|
320 } |
|
321 |
|
322 void CMBufManager::Release(RLibrary& aLib) |
|
323 { |
|
324 aLib = iLibrary; |
|
325 delete this; |
|
326 } |
|
327 |
|
328 MCommsBufPondDbg& CMBufManager::CommsBufPondDbg() |
|
329 { |
|
330 return *this; |
|
331 } |
|
332 |
|
333 TInt CMBufManager::BytesAvailable() const |
|
334 { |
|
335 __ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager)); |
|
336 return iMBufPoolManager->BytesAvailable(); |
|
337 } |
|
338 |
|
339 TInt CMBufManager::BytesAvailable(TInt aSize) const |
|
340 { |
|
341 __ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager)); |
|
342 return iMBufPoolManager->BytesAvailable(aSize); |
|
343 } |
|
344 |
|
345 |
|
346 #ifdef _MBUF_TEST |
|
347 // misc. sanity checks - all pool chains |
|
348 void CMBufManager::__DbgCheckChain(RMBuf* aMBuf, TMBufType aType, TInt aLength, TInt aSize) |
|
349 // |
|
350 // Check that an MBuf chain if of the required length and that all bufs are |
|
351 // of the requred type. |
|
352 // |
|
353 { |
|
354 CMBufManager* mgr = CMBufManager::Context(); |
|
355 |
|
356 TInt siz=0, len=0; |
|
357 |
|
358 RMBuf* m; |
|
359 RMBuf* p = NULL; |
|
360 TMBufIter iter(aMBuf); |
|
361 |
|
362 while (m = iter++, m!=NULL) |
|
363 { |
|
364 mgr->__DbgCheckBuffer(m); |
|
365 |
|
366 len += m->Length(); |
|
367 siz += m->Size(); |
|
368 if (m->Type()!=aType) |
|
369 Panic(EMBuf_CheckFailType); |
|
370 p = m; // so we know what the previous one was when it panics under the debugger |
|
371 (void)p->Last(); |
|
372 } |
|
373 |
|
374 if (aSize!=0 && siz!=aSize) |
|
375 Panic(EMBuf_CheckFailSize); |
|
376 |
|
377 if (aLength!=0 && len!=aLength) |
|
378 Panic(EMBuf_CheckFailLength); |
|
379 } |
|
380 |
|
381 |
|
382 TInt CMBufManager::__DbgCheckBuffer(RMBuf* aBuf) |
|
383 // |
|
384 // For each pool within the corresponding chain, try to locate aBuf |
|
385 // |
|
386 { |
|
387 return iMBufPoolManager->__DbgCheckBuffer(aBuf); |
|
388 } |
|
389 |
|
390 #else //#ifdef _MBUF_TEST |
|
391 void CMBufManager::__DbgCheckChain(RMBuf* /*aMBuf*/, TMBufType /*aType*/, TInt /*aLength*/, TInt /*aSize*/) |
|
392 { |
|
393 return; |
|
394 } |
|
395 |
|
396 TInt CMBufManager::__DbgCheckBuffer(RMBuf* /*aBuf*/) |
|
397 { |
|
398 return KErrNone; |
|
399 } |
|
400 |
|
401 #endif |
|
402 |
|
403 |
|
404 void CMBufManager::WatchDogReset() |
|
405 { |
|
406 if (iWatchDogIsPending) |
|
407 { |
|
408 iWatchDogIsPending=EFalse; |
|
409 MBufTimer::Remove(iWatchDog); |
|
410 } |
|
411 if(!iAllocsPending.IsEmpty()) |
|
412 { |
|
413 TCallBack c(WatchDogExpire, this); |
|
414 iWatchDogIsPending=ETrue; |
|
415 iWatchDog.Set(c); |
|
416 MBufTimer::Queue(KMBufWatchDogTime,iWatchDog); |
|
417 } |
|
418 } |
|
419 |
|
420 TInt CMBufManager::WatchDogExpire(TAny* aPtr) |
|
421 { |
|
422 ((CMBufManager*)aPtr)->iWatchDogIsPending=EFalse; |
|
423 ((CMBufManager*)aPtr)->CompleteAsyncAllocs(EFalse); // if required, do not allocate new pools |
|
424 ((CMBufManager*)aPtr)->CompleteAsyncAllocs(ETrue); // if required, do allocate new pools |
|
425 return 0; |
|
426 } |
|
427 |
|
428 |
|
429 void CMBufManager::StartRequest(CCommsBufAsyncRequest& aRequest) |
|
430 // |
|
431 // |
|
432 // |
|
433 { |
|
434 iAsynAllocLock.Wait(); |
|
435 iAllocsPending.AddLast(aRequest); |
|
436 iAsynAllocLock.Signal(); |
|
437 iRequestAsyncAlloc->MakeRequest(); |
|
438 } |
|
439 |
|
440 |
|
441 void CMBufManager::CancelRequest(CCommsBufAsyncRequest& aRequest) |
|
442 // |
|
443 // |
|
444 // |
|
445 { |
|
446 aRequest.iLink.Deque(); |
|
447 aRequest.Complete(KErrCancel); |
|
448 |
|
449 if (iRequestAsyncAlloc) |
|
450 { |
|
451 iRequestAsyncAlloc->MakeRequest(); |
|
452 } |
|
453 } |
|
454 |
|
455 // attempt to complete outstanding asynchronous allocation requests |
|
456 // - typically called after some mbufs have been freed |
|
457 void CMBufManager::CompleteAsyncAllocs(TBool aIsAllocPool) |
|
458 { |
|
459 TBool reset = ETrue; |
|
460 CCommsBufAsyncRequest *req; |
|
461 |
|
462 #ifdef __CFLOG_ACTIVE |
|
463 __CFLOG_1(KSubsysMBufMgr, KComponent, _L8("CMBufManager %x:\tCompleteAsyncAllocs() called"), this); |
|
464 #endif |
|
465 |
|
466 // first lock the pending list |
|
467 iAsynAllocLock.Wait(); |
|
468 TDblQueIter<CCommsBufAsyncRequest> iter(iAllocsPending); |
|
469 |
|
470 // attempt to allocate each outstanding asynchronous allocation request |
|
471 // - deliberately so, the request is attempted without extending the pool (as this is done from a watchdog timer as a last resort) |
|
472 while (req = iter++, req != NULL) |
|
473 { |
|
474 // if null size specified, then allocate a default sized mbuf |
|
475 // - to avoid a SC break, the default size is hard coded to K_MBufSmallSize for consumers that assume that this length will be returned |
|
476 TInt reqSize = req->iSize; |
|
477 if (reqSize == 0) // trs; does it make sense to request an allocation without specifying a length? kept as is to avoid a SC break |
|
478 reqSize = KMBufSmallSize; |
|
479 |
|
480 |
|
481 RMBuf* mBufs = Alloc(reqSize, req->iMinSize, req->iMaxSize, aIsAllocPool); |
|
482 if (mBufs) |
|
483 { |
|
484 RMBufQ& q = static_cast<RMBufQ&>(req->iBufQ); |
|
485 q = mBufs; |
|
486 req->Complete(KErrNone); |
|
487 |
|
488 if (aIsAllocPool) // not done for pool allocation growth to ensure FC with the factored out implementation; CompleteLargeRequests() |
|
489 reset = EFalse; |
|
490 } |
|
491 } |
|
492 |
|
493 iAsynAllocLock.Signal(); |
|
494 |
|
495 // only reset the watch dog if there are no pending requests left or a request was completed, otherwise big pending requests might |
|
496 // be stalled by a continual trickle of small allocs and frees. |
|
497 if (iAllocsPending.IsEmpty() || reset) |
|
498 WatchDogReset(); |
|
499 } |
|
500 |
|
501 // refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant |
|
502 RMBuf* CMBufManager::AllocL(TInt aSize) |
|
503 // |
|
504 // Allocate and initialise a chain of MBufs |
|
505 // Total data length is set to exact size. |
|
506 // |
|
507 { |
|
508 RMBuf* buf = Alloc(aSize); |
|
509 if(!buf) |
|
510 { |
|
511 User::Leave(KErrNoMBufs); |
|
512 } |
|
513 return buf; |
|
514 } |
|
515 |
|
516 void CMBufManager::Free(RCommsBuf* aBuf) |
|
517 { |
|
518 iMBufPoolManager->Free(static_cast<RMBuf*>(aBuf), EFalse); |
|
519 } |
|
520 |
|
521 TInt CMBufManager::LargestBufSize() const |
|
522 /** Returns the size of the largest MBuf that the manager can provide. |
|
523 @return the size of the largest MBuf that the manager can provide. |
|
524 */ |
|
525 { |
|
526 // iLargestMBufSize is needed for legacy functionallity when the MBufSize is not specified |
|
527 // in RMBufChain::Align(TInt aSize). It is updated in MBufPoolManager as new pools are created |
|
528 __ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager)); |
|
529 return iMBufPoolManager->LargestMBufSize(); |
|
530 } |
|
531 |
|
532 TInt CMBufManager::NextBufSize(TInt aSize) const |
|
533 /** Used to obtains the sizes of the MBufs that the manager can provide. |
|
534 @param the size to start searching from. |
|
535 @return the size of the next MBuf that is greater than aSize, KErrNotFound if there is no MBuf bigger than aSize. |
|
536 */ |
|
537 { |
|
538 __ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager)); |
|
539 return iMBufPoolManager->NextMBufSize(aSize); |
|
540 } |
|
541 |
|
542 // allocate and initialise a chain of MBufs |
|
543 // - total data length is set to exact size |
|
544 // - overloaded variants are deliberately not exported because; |
|
545 // a. likely that this interface will be deprecated in the future and thus we don't want to unnecessarily extend it (ie. more maintenance) |
|
546 // b. easy to export them down the track, but not so easy to go the other way |
|
547 RMBuf* CMBufManager::Alloc(TInt aSize, const RMBufChain& aMBufChain) |
|
548 { |
|
549 // select min/max mbuf size constraints based upon an existing mbuf |
|
550 if (aMBufChain.First()) |
|
551 return Alloc(aSize, aMBufChain.First()->Size(), aMBufChain.First()->Size()); |
|
552 else |
|
553 return Alloc(aSize); |
|
554 } |
|
555 RMBuf* CMBufManager::Alloc(TInt aSize) |
|
556 { |
|
557 return Alloc(aSize, 0, KMaxTInt); |
|
558 } |
|
559 RMBuf* CMBufManager::Alloc(TInt aSize, TInt aMinMBufSize) |
|
560 { |
|
561 return Alloc(aSize, aMinMBufSize, KMaxTInt); |
|
562 } |
|
563 RMBuf* CMBufManager::Alloc(TInt aSize, TInt aMinMBufSize, TInt aMaxMBufSize) |
|
564 { |
|
565 return Alloc(aSize, aMinMBufSize, aMaxMBufSize, ETrue); |
|
566 } |
|
567 RMBuf* CMBufManager::Alloc(TInt aSize, TInt aMinMBufSize, TInt aMaxMBufSize, TBool aIsAllocPool) |
|
568 { |
|
569 // check args |
|
570 // - regarding use of TInt instead of TUint, refer comments in CMBufPoolManager::AddL |
|
571 __ASSERT_ALWAYS(aSize >= 0, Panic(EMBuf_SillyAlloc)); |
|
572 __ASSERT_DEBUG(aMinMBufSize >= 0, Panic(EMBuf_NegativeMinMBufSize)); |
|
573 __ASSERT_DEBUG(aMaxMBufSize >= 0, Panic(EMBuf_NegativeMaxMBufSize)); |
|
574 __ASSERT_DEBUG(aMaxMBufSize >= aMinMBufSize, Panic(EMBuf_MinExceedsMaxMBufSize)); |
|
575 |
|
576 #ifdef SYMBIAN_NETWORKING_PERFMETRICS |
|
577 TInt bucket = Min(aSize / KBucketSize, KNumBuckets - 1); |
|
578 #endif |
|
579 #ifdef _MBUF_TEST |
|
580 // Silly value here - the point is that the value won't be changed by this, so we can |
|
581 // emulate what happens if the system repeatedly fails to allocate the memory. |
|
582 if (iDbgFailAfter != 0 && --iDbgFailAfter == 0) |
|
583 { |
|
584 #ifdef SYMBIAN_NETWORKING_PERFMETRICS |
|
585 // REQ7862 fix up the iLock this might be free list lock from pool manager - perhaps all this goes to pool manager |
|
586 iLock.Wait(); |
|
587 ++iBuckets[bucket]; |
|
588 ++iNumOOBs; |
|
589 // REQ7862 fix up the iLock this might be free list lock from pool manager - perhaps all this goes to pool manager |
|
590 iLock.Signal(); |
|
591 #endif |
|
592 return NULL; |
|
593 } |
|
594 #endif |
|
595 |
|
596 #ifdef SYMBIAN_NETWORKING_PERFMETRICS |
|
597 ++iBuckets[bucket]; |
|
598 #endif |
|
599 |
|
600 |
|
601 |
|
602 return iMBufPoolManager->Alloc(aSize, aMinMBufSize, aMaxMBufSize, aIsAllocPool); |
|
603 } |
|
604 |
|
605 RMBuf* CMBufManager::FromHandle(TInt /* aHandle */) |
|
606 { |
|
607 ASSERT(0); |
|
608 return NULL; |
|
609 } |
|
610 |
|
611 TInt CMBufManager::Store(TDes8& /*aStore*/) const |
|
612 { |
|
613 // Not supported |
|
614 ASSERT(0); |
|
615 return 0; |
|
616 } |
|
617 |
|
618 void CMBufManager::CallBackAfterFree() |
|
619 { |
|
620 if (!iAllocsPending.IsEmpty()) |
|
621 iFreeCB->CallBack(); |
|
622 } |
|
623 |
|
624 TInt CMBufManager::FreeCallBack(TAny* aPtr) |
|
625 { |
|
626 ((CMBufManager*)aPtr)->CompleteAsyncAllocs(EFalse); // attempt allocation without attempting to allocate any new pools |
|
627 return 0; |
|
628 } |
|
629 |
|
630 CDeltaTimer* CMBufManager::Timer() |
|
631 // |
|
632 // return context for the global timer. |
|
633 // |
|
634 { |
|
635 return Context()->iTimer; |
|
636 } |
|
637 |
|
638 // retrieve free space for all pool chains |
|
639 TUint CMBufManager::__DbgGetBufSpace() |
|
640 { |
|
641 #ifdef _MBUF_TEST |
|
642 return iMBufPoolManager->__DbgGetBufSpace(); |
|
643 #else |
|
644 return 0; |
|
645 #endif |
|
646 } |
|
647 |
|
648 // get free space for pool chain with matching mbuf size |
|
649 TUint CMBufManager::__DbgGetBufSpace(TUint aMBufSize) |
|
650 { |
|
651 #ifdef _MBUF_TEST |
|
652 return iMBufPoolManager->__DbgGetBufSpace(aMBufSize); |
|
653 #else |
|
654 aMBufSize = aMBufSize; |
|
655 return 0; |
|
656 #endif |
|
657 } |
|
658 |
|
659 // get used space for all pool chains |
|
660 TUint CMBufManager::__DbgGetBufTotal() |
|
661 { |
|
662 #ifdef _MBUF_TEST |
|
663 return iMBufPoolManager->__DbgGetBufTotal(); |
|
664 #else |
|
665 return 0; |
|
666 #endif |
|
667 } |
|
668 |
|
669 // get used space for pool chain with matching mbuf size |
|
670 TUint CMBufManager::__DbgGetBufTotal(TUint aMBufSize) |
|
671 { |
|
672 #ifdef _MBUF_TEST |
|
673 return iMBufPoolManager->__DbgGetBufTotal(aMBufSize); |
|
674 #else |
|
675 aMBufSize = aMBufSize; |
|
676 return 0; |
|
677 #endif |
|
678 } |
|
679 |
|
680 // return the first mbuf in the free list belong to the first chain |
|
681 RCommsBuf* CMBufManager::__DbgBufChain() |
|
682 { |
|
683 #ifdef _MBUF_TEST |
|
684 return iMBufPoolManager->__DbgMBufChain(); |
|
685 #else |
|
686 return NULL; |
|
687 #endif |
|
688 } |
|
689 // return the first mbuf in the free list belonging to the chain of the specified mbuf size |
|
690 RCommsBuf* CMBufManager::__DbgBufChain(TUint aMBufSize) |
|
691 { |
|
692 #ifdef _MBUF_TEST |
|
693 return iMBufPoolManager->__DbgMBufChain(aMBufSize); |
|
694 #else |
|
695 aMBufSize = aMBufSize; |
|
696 return NULL; |
|
697 #endif |
|
698 } |
|
699 |
|
700 // update the max pool limit (debug only) - use the first pool chain if none specified |
|
701 void CMBufManager::__DbgSetPoolLimit(TInt aCount) |
|
702 { |
|
703 #ifdef _MBUF_TEST |
|
704 iMBufPoolManager->__DbgSetPoolLimit(aCount); |
|
705 #else |
|
706 aCount = aCount; |
|
707 #endif |
|
708 } |
|
709 |
|
710 // update the max pool limit (debug only) - for the specified mbuf size |
|
711 void CMBufManager::__DbgSetPoolLimit(TInt aCount, TUint aMBufSize) |
|
712 { |
|
713 #ifdef _MBUF_TEST |
|
714 iMBufPoolManager->__DbgSetPoolLimit(aCount, aMBufSize); |
|
715 #else |
|
716 aCount = aCount; |
|
717 aMBufSize = aMBufSize; |
|
718 #endif |
|
719 } |
|
720 |
|
721 // set a fail allocation count |
|
722 void CMBufManager::__DbgSetFailAfter(TInt aCount) |
|
723 { |
|
724 #ifdef _MBUF_TEST |
|
725 iDbgFailAfter = aCount; |
|
726 #else |
|
727 aCount = aCount; |
|
728 #endif |
|
729 } |
|
730 |
|
731 // get the allocation size - note only valid if called from the CMBufManager owner thread |
|
732 TInt CMBufManager::__DbgGetHeapSize() |
|
733 { |
|
734 #ifdef _MBUF_TEST |
|
735 if (iMBufPoolManager) |
|
736 return iMBufPoolManager->BytesAllocated(); |
|
737 else |
|
738 return 0; |
|
739 #else |
|
740 return 0; |
|
741 #endif |
|
742 } |
|
743 |
|
744 |
|
745 #ifdef SYMBIAN_NETWORKING_PERFMETRICS |
|
746 |
|
747 TBool CMBufManager::AddToPerfLog(TAny* aSelf, TDes8& aBuffer, TDes8Overflow* aOverflowHandler) |
|
748 { |
|
749 CMBufManager* self = static_cast<CMBufManager*>(aSelf); |
|
750 __ASSERT_COMPILE(KNumBuckets == 13); // cross-check against below |
|
751 _LIT8(KFormat, "MBuf OOB:%u, reqs:%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u"); |
|
752 aBuffer.AppendFormat(KFormat, aOverflowHandler, self->iNumOOBs, self->iBuckets[0], |
|
753 self->iBuckets[1], self->iBuckets[2], self->iBuckets[3], self->iBuckets[4], self->iBuckets[5], self->iBuckets[6], |
|
754 self->iBuckets[7], self->iBuckets[8], self->iBuckets[9], self->iBuckets[10], self->iBuckets[11], self->iBuckets[12]); |
|
755 return EFalse; |
|
756 } |
|
757 |
|
758 #endif |
|
759 |
|
760 |
|
761 |
|
762 #ifndef __NOT_OWN_MBUFMGR_DLL // Used by t_esock in the PPP testsuite |
|
763 |
|
764 #endif |
|
765 |