1 /* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18 #ifndef PVMF_SOCKET_BUFFER_ALLOCATORS_H_INCLUDED 19 #define PVMF_SOCKET_BUFFER_ALLOCATORS_H_INCLUDED 20 21 #ifndef PVMF_CLIENTSERVER_SOCKET_TUNEABLES_H_INCLUDED 22 #include "pvmf_clientserver_socket_tuneables.h" 23 #endif 24 #ifndef OSCL_DEFALLOC_H_INCLUDED 25 #include "oscl_defalloc.h" 26 #endif 27 #ifndef PVLOGGER_H_INCLUDED 28 #include "pvlogger.h" 29 #endif 30 31 #define PVMF_RESIZE_ALLOC_OVERHEAD 8 32 #define PVMF_RESIZE_ALLOC_BLK_SIZE_OFFSET 4 33 34 // constants 35 const uint PVMF_SOCKET_BUF_DEFAULT_SIZE = 200; 36 37 #define PVMF_SOCKALLOC_LOGERROR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m); 38 #define PVMF_SOCKALLOC_LOGWARNING(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_WARNING,m); 39 #define PVMF_SOCKALLOC_LOGINFOLOW(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iLogger,PVLOGMSG_INFO,m); 40 #define PVMF_SOCKALLOC_LOGINFO(m) PVMF_SOCKALLOC_LOGINFOLOW(m) 41 #define PVMF_SOCKALLOC_LOG_ALLOC_RESIZE_DEALLOC(m) PVMF_SOCKALLOC_LOGINFO(m) 42 #define PVMF_SOCKALLOC_LOG_SEQNUM_ALLOC_DEALLOC(m) PVMF_SOCKALLOC_LOGINFO(m) 43 #define PVMF_SOCKALLOC_LOG_OUT_OF_ORDER_DEALLOC(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iOOOLogger,PVLOGMSG_INFO,m); 44 #define PVMF_SOCKALLOC_LOG_MEMCALLBACK(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iCallBackLogger,PVLOGMSG_INFO,m); 45 #define PVMF_SOCKALLOC_LOG_AVAILABILITY(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iSizeLogger,PVLOGMSG_INFO,m); 46 47 #define PVMF_SOCKALLOC_FILL_MEMBLK_ON_ALLOC 1 48 49 static const char PVMF_SOCKALLOC_FEEDBACK_PORT_NAME[] = "PVMFJitterBufferPortFeedBack"; 50 51 class PVMFSMSharedBufferAllocWithReSizeAllocDeallocObserver 52 { 53 public: 54 virtual void chunkdeallocated(OsclAny* aContextData) = 0; 55 }; 56 57 /* 58 * This allocator is used to allocate socket buffers, for the purpose of 59 * doing a receive. 60 */ 61 class PVMFSocketBufferAllocator : public Oscl_DefAlloc 62 { 63 public: PVMFSocketBufferAllocator(uint32 numChunks,uint32 chunkSize)64 PVMFSocketBufferAllocator(uint32 numChunks, uint32 chunkSize) 65 : alloc(numChunks, chunkSize) 66 { 67 iNumChunks = numChunks; 68 iChunkSize = chunkSize; 69 iNumOutStandingBuffers = 0; 70 IncrementKeepAliveCount(); 71 }; 72 ~PVMFSocketBufferAllocator()73 virtual ~PVMFSocketBufferAllocator() {}; 74 IncrementKeepAliveCount()75 void IncrementKeepAliveCount() 76 { 77 iNumOutStandingBuffers++; 78 } 79 DecrementKeepAliveCount()80 void DecrementKeepAliveCount() 81 { 82 iNumOutStandingBuffers--; 83 } 84 allocate(const uint32 n)85 OsclAny* allocate(const uint32 n) 86 { 87 iNumOutStandingBuffers++; 88 return (alloc.allocate(n)); 89 } 90 deallocate(OsclAny * p)91 void deallocate(OsclAny* p) 92 { 93 iNumOutStandingBuffers--; 94 alloc.deallocate(p); 95 } 96 getNumOutStandingBuffers()97 uint32 getNumOutStandingBuffers() 98 { 99 return iNumOutStandingBuffers; 100 } 101 102 uint32 getAvailableBufferSpace(bool aFirstParentChunkOnly = false) 103 { 104 OSCL_UNUSED_ARG(aFirstParentChunkOnly); 105 if (iNumChunks > iNumOutStandingBuffers) 106 { 107 return ((iNumChunks - iNumOutStandingBuffers)*iChunkSize); 108 } 109 return 0; 110 } 111 void notifyfreechunkavailable(OsclMemPoolFixedChunkAllocatorObserver& aObserver, 112 uint32 aSize, 113 OsclAny* aContextData = NULL) 114 { 115 OSCL_UNUSED_ARG(aSize); 116 alloc.notifyfreechunkavailable(aObserver, aContextData); 117 } 118 CancelFreeChunkAvailableCallback()119 void CancelFreeChunkAvailableCallback() 120 { 121 alloc.CancelFreeChunkAvailableCallback(); 122 } 123 124 private: 125 uint32 iNumChunks; 126 uint32 iChunkSize; 127 OsclMemPoolFixedChunkAllocator alloc; 128 uint32 iNumOutStandingBuffers; 129 }; 130 131 class PVMFSocketBufferCleanupDA : public OsclDestructDealloc 132 { 133 public: PVMFSocketBufferCleanupDA(Oscl_DefAlloc * in_gen_alloc)134 PVMFSocketBufferCleanupDA(Oscl_DefAlloc* in_gen_alloc) : 135 136 137 gen_alloc(in_gen_alloc) {}; 138 ~PVMFSocketBufferCleanupDA()139 virtual ~PVMFSocketBufferCleanupDA() {}; 140 destruct_and_dealloc(OsclAny * ptr)141 virtual void destruct_and_dealloc(OsclAny* ptr) 142 { 143 gen_alloc->deallocate(ptr); 144 /* 145 * in case there are no outstanding buffers delete the allocator 146 */ 147 PVMFSocketBufferAllocator* socketDataAllocator = 148 reinterpret_cast<PVMFSocketBufferAllocator*>(gen_alloc); 149 150 uint32 numBuffers = socketDataAllocator->getNumOutStandingBuffers(); 151 152 if (numBuffers == 0) 153 { 154 OSCL_DELETE((socketDataAllocator)); 155 } 156 } 157 158 private: 159 Oscl_DefAlloc* gen_alloc; 160 }; 161 162 class PVMFSMSharedBufferAllocWithReSize : public Oscl_DefAlloc 163 { 164 public: PVMFSMSharedBufferAllocWithReSize(uint32 aParentChunkSize,const char name[])165 PVMFSMSharedBufferAllocWithReSize(uint32 aParentChunkSize, const char name[]) 166 { 167 iLogger = NULL; 168 iSizeLogger = NULL; 169 iOOOLogger = NULL; 170 iLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize"); 171 iSizeLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize.availability"); 172 iCallBackLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize.memcallback"); 173 iOOOLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize.ooo"); 174 iName = name; 175 176 iNumOutOfOrderDeallocs = 0; 177 iLastDeallocatedSeqNum = 0; 178 iSeqCount = 1; 179 iNumOutStandingBuffers = 0; 180 181 iCallbackPending = false; 182 iCallbackRequestSize = 0;; 183 iObserver = NULL; 184 iNextAvailableContextData = NULL; 185 186 iJJDataSize = 0; 187 iJJDataDbgSize = 0; 188 189 if ((int32)aParentChunkSize <= 0) 190 { 191 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize - Invalid Parent Chunk size")); 192 OSCL_LEAVE(OsclErrArgument); 193 } 194 195 // set buffer resizing to default values 196 if (oscl_strcmp(iName.get_cstr(), PVMF_SOCKALLOC_FEEDBACK_PORT_NAME) == 0) 197 { 198 iiRegrowthSize = DEFAULT_MAX_SOCKETMEMPOOL_RESIZELEN_FEEDBACK_PORT; 199 } 200 else 201 { 202 iiRegrowthSize = DEFAULT_MAX_SOCKETMEMPOOL_RESIZELEN_INPUT_PORT; 203 } 204 iiMaxNumGrows = DEFAULT_MAX_NUM_SOCKETMEMPOOL_RESIZES; 205 iiNumGrows = 0; 206 207 iDeallocObserver = NULL; 208 iDeallocNotificationContextData = NULL; 209 210 CreateParentChunk(aParentChunkSize); 211 212 IncrementKeepAliveCount(); 213 } 214 PVMFSMSharedBufferAllocWithReSize(uint32 aParentChunkSize,const char name[],int aMaxNumGrows,int aGrowSize)215 PVMFSMSharedBufferAllocWithReSize(uint32 aParentChunkSize, const char name[], 216 int aMaxNumGrows, int aGrowSize) 217 { 218 iLogger = NULL; 219 iSizeLogger = NULL; 220 iOOOLogger = NULL; 221 iLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize"); 222 iSizeLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize.availability"); 223 iCallBackLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize.memcallback"); 224 iOOOLogger = PVLogger::GetLoggerObject("PVMFSMSharedBufferAllocWithReSize.ooo"); 225 iName = name; 226 iCallbackPending = false; 227 iNumOutOfOrderDeallocs = 0; 228 iLastDeallocatedSeqNum = -1; 229 iSeqCount = 0; 230 iNumOutStandingBuffers = 0; 231 232 iJJDataSize = 0; 233 iJJDataDbgSize = 0; 234 if ((int32)aParentChunkSize <= 0) 235 { 236 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize - Invalid Parent Chunk size")); 237 OSCL_LEAVE(OsclErrArgument); 238 } 239 240 // set buffer resizing to specified values 241 iiRegrowthSize = aGrowSize; 242 iiMaxNumGrows = aMaxNumGrows; 243 iiNumGrows = 0; 244 245 iDeallocObserver = NULL; 246 iDeallocNotificationContextData = NULL; 247 248 CreateParentChunk(aParentChunkSize); 249 IncrementKeepAliveCount(); 250 } 251 CreateParentChunk(uint32 aSize)252 void CreateParentChunk(uint32 aSize) 253 { 254 ParentChunkContainer parentChunkContainer; 255 256 parentChunkContainer.id = iParentChunkContainerVec.size(); 257 parentChunkContainer.iParentChunkSize = aSize; 258 parentChunkContainer.iParentChunkStart = 259 (uint8*)(alloc.ALLOCATE(aSize)); 260 parentChunkContainer.iParentChunkEnd = 261 parentChunkContainer.iParentChunkStart + aSize; 262 parentChunkContainer.iAllocationPtr = 263 parentChunkContainer.iParentChunkStart; 264 265 iParentChunkContainerVec.push_back(parentChunkContainer); 266 PVMF_SOCKALLOC_LOGINFO((0, "PVMFSMSharedBufferAllocWithReSize::CreateParentChunk - Name=%s, Size=%d", iName.get_cstr(), aSize)); 267 } 268 ~PVMFSMSharedBufferAllocWithReSize()269 virtual ~PVMFSMSharedBufferAllocWithReSize() 270 { 271 Oscl_Vector<ParentChunkContainer, OsclMemAllocator>::iterator it; 272 273 for (it = iParentChunkContainerVec.begin(); 274 it != iParentChunkContainerVec.end(); 275 it++) 276 { 277 alloc.deallocate(it->iParentChunkStart); 278 } 279 280 if (iNumOutOfOrderDeallocs != 0) 281 { 282 OSCL_ASSERT(false); 283 } 284 285 iParentChunkContainerVec.clear(); 286 iLogger = NULL; 287 iJJDataSize = 0; 288 iJJDataDbgSize = 0; 289 iNumOutStandingBuffers = 0; 290 iSeqCount = 0; 291 iLastDeallocatedSeqNum = -1; 292 iNumOutOfOrderDeallocs = 0; 293 iDeallocObserver = NULL; 294 }; 295 296 /* 297 * This allocator is used to create shared buffer which could have a lifetime 298 * that is longer than the module that actually created the allocator. Hence 299 * it is implemented in such a way that this allocator would de destroyed when 300 * all the outstanding buffers allocated by this alloacator are deallocated. Or 301 * in other words this allocator would be destroyed if and when iNumOutStandingBuffers 302 * becomes zero. This could cause problems when due to transient nature of data flow 303 * iNumOutStandingBuffers could become zero when the data flow drys up temporarily. 304 * Under such a scenario we would end up deleting the allocator prematurely. Inorder 305 * to avoid this, these keep alive mechanisms are provided. This ensures that the 306 * module that created the allocator can make sure that the allocator is alive atleast 307 * till its lifetime. Therefore allocator's life is the maximum of: 308 * (buffer life times, allocator creator's life time) 309 */ IncrementKeepAliveCount()310 void IncrementKeepAliveCount() 311 { 312 iDecKeepAliveCalled = false; 313 iNumOutStandingBuffers++; 314 PVMF_SOCKALLOC_LOGINFO((0, "PVMFSMSharedBufferAllocWithReSize::IncrementKeepAliveCount - Name=%s, iNumOutStandingBuffers=%d", iName.get_cstr(), iNumOutStandingBuffers)); 315 } 316 DecrementKeepAliveCount()317 void DecrementKeepAliveCount() 318 { 319 iDecKeepAliveCalled = true; 320 iNumOutStandingBuffers--; 321 PVMF_SOCKALLOC_LOGINFO((0, "PVMFSMSharedBufferAllocWithReSize::DecrementKeepAliveCount - Name=%s, iNumOutStandingBuffers=%d", iName.get_cstr(), iNumOutStandingBuffers)); 322 } 323 324 struct StatBlock 325 { StatBlockStatBlock326 StatBlock() 327 { 328 size = 0; 329 seqNum = 0; 330 }; 331 332 uint32 size; 333 uint32 seqNum; 334 }; 335 336 struct OutOfOrderBlockContainer 337 { OutOfOrderBlockContainerOutOfOrderBlockContainer338 OutOfOrderBlockContainer() 339 { 340 ptr = NULL; 341 seqNum = 0; 342 }; OutOfOrderBlockContainerOutOfOrderBlockContainer343 OutOfOrderBlockContainer(const OsclAny* p, uint32 s) 344 { 345 ptr = p; 346 seqNum = s; 347 }; 348 349 const OsclAny* ptr; 350 uint32 seqNum; 351 }; 352 353 class ReassemblyBlock 354 { 355 356 public: pnext(p)357 ReassemblyBlock(const OsclAny* ptr, uint32 seqNum, ReassemblyBlock* p = NULL) : pnext(p) 358 { 359 rangeStart = rangeEnd = seqNum; 360 blocks.push_back(OutOfOrderBlockContainer(ptr, seqNum)); 361 } 362 ~ReassemblyBlock()363 ~ReassemblyBlock() { } 364 IsInRange(uint32 seq)365 bool IsInRange(uint32 seq) 366 { 367 return (seq >= rangeStart - 1) && (seq <= rangeEnd + 1); 368 } IsInRange(ReassemblyBlock & block)369 bool IsInRange(ReassemblyBlock& block) 370 { 371 return (block.rangeStart == rangeEnd + 1); 372 } IsLess(uint32 seq)373 bool IsLess(uint32 seq) 374 { 375 return seq < rangeStart; 376 } Merge(ReassemblyBlock & block)377 void Merge(ReassemblyBlock& block) 378 { 379 for (uint i = 0; i < block.blocks.size(); i++) 380 { 381 blocks.push_back(block.blocks[i]); 382 rangeEnd++; 383 } 384 385 rangeEnd = block.rangeEnd; 386 } Insert(const OsclAny * ptr,uint32 seqNum)387 bool Insert(const OsclAny* ptr, uint32 seqNum) 388 { 389 if (seqNum == rangeEnd + 1) 390 { 391 blocks.push_back(OutOfOrderBlockContainer(ptr, seqNum)); 392 rangeEnd++; 393 return true; 394 } 395 else if (seqNum == rangeStart - 1) 396 { 397 blocks.push_front(OutOfOrderBlockContainer(ptr, seqNum)); 398 rangeStart--; 399 return true; 400 } 401 else 402 { 403 //OSCL_ASSERT(false); 404 return false; 405 } 406 } 407 Blocks()408 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator>* Blocks() 409 { 410 return &blocks; 411 } 412 ReassemblyBlock* pnext; 413 414 private: 415 uint32 rangeStart; 416 uint32 rangeEnd; 417 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator> blocks; 418 }; 419 420 class ReassemblyBlockList 421 { 422 public: ReassemblyBlockList()423 ReassemblyBlockList() 424 { 425 phead = NULL; 426 } ~ReassemblyBlockList()427 ~ReassemblyBlockList() { } 428 Insert(const OsclAny * ptr,uint32 seq)429 bool Insert(const OsclAny* ptr, uint32 seq) 430 { 431 bool oRet = true; 432 ReassemblyBlock** pp = &phead; 433 while (1) 434 { 435 if (*pp == NULL) 436 { 437 *pp = OSCL_NEW(ReassemblyBlock, (ptr, seq)); 438 break; 439 } 440 else if ((*pp)->IsInRange(seq)) 441 { 442 oRet = (*pp)->Insert(ptr, seq); 443 break; 444 } 445 else if ((*pp)->IsLess(seq)) 446 { 447 ReassemblyBlock* p = *pp; 448 *pp = OSCL_NEW(ReassemblyBlock, (ptr, seq, p)); 449 break; 450 } 451 else 452 { 453 pp = &(*pp)->pnext; 454 } 455 } 456 pp = &phead; 457 while ((*pp)->pnext != NULL) 458 { 459 if ((*pp)->IsInRange(*((*pp)->pnext))) 460 { 461 (*pp)->Merge(*((*pp)->pnext)); 462 ReassemblyBlock* p = (*pp)->pnext; 463 (*pp)->pnext = (*pp)->pnext->pnext; 464 OSCL_DELETE(p); 465 } 466 else 467 { 468 pp = &(*pp)->pnext; 469 } 470 } 471 return oRet; 472 } 473 GetDeletables(uint32 seqNum)474 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator>* GetDeletables(uint32 seqNum) 475 { 476 if (phead == NULL) 477 { 478 return NULL; 479 } 480 else if (phead->IsInRange(seqNum)) 481 { 482 return phead->Blocks(); 483 } 484 else 485 { 486 return NULL; 487 } 488 } Prune()489 void Prune() 490 { 491 OSCL_ASSERT(phead != NULL); 492 ReassemblyBlock* p = phead; 493 phead = p->pnext; 494 OSCL_DELETE(p); 495 } 496 /////// START: clean the head GetHeadDeletables(uint32 headSeqNum)497 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator>* GetHeadDeletables(uint32 headSeqNum) 498 { 499 ReassemblyBlock *my_ptr = phead; 500 501 while (my_ptr != NULL) 502 { 503 if (my_ptr->IsInRange(headSeqNum)) 504 { //ok, we got a consecutive chunk end with headSeqNum-1 505 return my_ptr->Blocks(); 506 } 507 508 my_ptr = my_ptr->pnext; 509 } 510 return NULL; 511 } PruneHead(Oscl_Vector<OutOfOrderBlockContainer,OsclMemAllocator> * ptrBlk)512 void PruneHead(Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator>* ptrBlk) 513 { 514 OSCL_ASSERT(phead != NULL); 515 if (phead->Blocks() == ptrBlk) 516 { 517 OSCL_DELETE(phead); 518 phead = NULL; 519 return; 520 } 521 522 ReassemblyBlock *myParent_ptr = phead; 523 ReassemblyBlock *my_ptr = myParent_ptr->pnext; 524 525 while (my_ptr != NULL) 526 { 527 if (my_ptr->Blocks() == ptrBlk) 528 { 529 OSCL_DELETE(my_ptr); 530 myParent_ptr->pnext = NULL; 531 return; 532 } 533 534 myParent_ptr = my_ptr; 535 my_ptr = my_ptr->pnext; 536 } 537 OSCL_ASSERT(false); 538 } 539 /////// END: clean the head 540 private: 541 ReassemblyBlock* phead; 542 }; 543 544 545 struct ParentChunkContainer 546 { ParentChunkContainerParentChunkContainer547 ParentChunkContainer() 548 { 549 id = 0xFFFFFFFF; 550 iParentChunkStart = NULL; 551 iParentChunkEnd = NULL; 552 iAllocationPtr = NULL; 553 iEndOfLastDeallocatedBlock = NULL; 554 iParentChunkSize = 0; 555 }; 556 uint32 id; 557 uint8* iParentChunkStart; 558 uint8* iParentChunkEnd; 559 uint32 iParentChunkSize; 560 uint8* iAllocationPtr; 561 uint8* iEndOfLastDeallocatedBlock; 562 }; 563 564 enum PVMF_RESIZE_ALLOC_ERROR_CODE 565 { 566 PVMF_RESIZE_ALLOC_SUCCESS, 567 PVMF_RESIZE_ALLOC_NO_MEMORY, 568 PVMF_RESIZE_ALLOC_MEMORY_CORRUPT, 569 PVMF_RESIZE_OUT_OF_ORDER_BLOCK 570 }; 571 572 PVMF_RESIZE_ALLOC_ERROR_CODE AllocateInParentChunk(ParentChunkContainer * aPCContainer,OsclAny * & aRequestPtr,const uint32 aReqBlkSize)573 AllocateInParentChunk(ParentChunkContainer* aPCContainer, 574 OsclAny*& aRequestPtr, 575 const uint32 aReqBlkSize) 576 { 577 uint32 n = aReqBlkSize + PVMF_RESIZE_ALLOC_OVERHEAD; 578 uint32 availSize = FindLargestContiguousFreeBlock(aPCContainer); 579 if (n > availSize) 580 { 581 PVMF_SOCKALLOC_LOGINFO((0, "PVMFSMSharedBufferAllocWithReSize::AllocateInParentChunk - No Memory1 Name=%s, ChunkID=%d, ReqSize=%d, AvailSize=%d", iName.get_cstr(), aPCContainer->id, n, availSize)); 582 return (PVMF_RESIZE_ALLOC_NO_MEMORY); 583 } 584 /* 585 * Check and see if the block being allocated would 586 * cause a wrap around of the "iAllocationPtr" 587 */ 588 if ((aPCContainer->iAllocationPtr + n) > aPCContainer->iParentChunkEnd) 589 { 590 /* 591 * This implies that the requested block is larger 592 * than whats left towards the end of the parent chunk. 593 * Since we cannot provide memory in fragments, we 594 * have to ignore this chunk, wrap the allocation ptr 595 * to start of the parent chunk and check for alloc size. 596 */ 597 aPCContainer->iAllocationPtr = aPCContainer->iParentChunkStart; 598 } 599 /* 600 * Next check if we can accomodate this request in one 601 * contiguous block between the current alloc ptr and 602 * last deallocated ptr. Please note that we make use 603 * of the fact that deallocation happens sequentially. 604 * Or in other words blocks are freed in the order 605 * in which they are allocated 606 * 607 * There are two possibilites: 608 * 1) iAllocationPtr < iEndOfLastDeallocatedBlock - This means 609 * that a wrap around has happenned, and we need to check 610 * if there is a large enough block between the two ptrs. 611 * Please note that we assume that the space between 612 * iAllocationPtr and iEndOfLastDeallocatedBlock is all free. 613 * Reason being that blocks are deallocated in the same 614 * order in which they are allocated. 615 * 616 * 2) iAllocationPtr > iEndOfLastDeallocatedBlock - This means 617 * we are ok. Any discrepancies must have been detected 618 * by earlier checks. 619 */ 620 if (aPCContainer->iAllocationPtr < aPCContainer->iEndOfLastDeallocatedBlock) 621 { 622 uint32 diff = (aPCContainer->iEndOfLastDeallocatedBlock - 623 aPCContainer->iAllocationPtr); 624 if (diff >= n) 625 { 626 iNumOutStandingBuffers++; 627 } 628 else 629 { 630 /* 631 * We do not have a large enough block to 632 * satisfy this request. 633 */ 634 PVMF_SOCKALLOC_LOGINFO((0, "PVMFSMSharedBufferAllocWithReSize::AllocateInParentChunk - No Memory2 Name=%s, ChunkID=%d, ReqSize=%d, AvailSize=%d", iName.get_cstr(), aPCContainer->id, n, diff)); 635 return (PVMF_RESIZE_ALLOC_NO_MEMORY); 636 } 637 } 638 else 639 { 640 iNumOutStandingBuffers++; 641 } 642 /* Set sequence number */ 643 oscl_memcpy(aPCContainer->iAllocationPtr, &iSeqCount, sizeof(uint32)); 644 /* Set size */ 645 oscl_memcpy((aPCContainer->iAllocationPtr + PVMF_RESIZE_ALLOC_BLK_SIZE_OFFSET), 646 &aReqBlkSize, 647 sizeof(uint32)); 648 aRequestPtr = (OsclAny*)(aPCContainer->iAllocationPtr + 649 PVMF_RESIZE_ALLOC_OVERHEAD); 650 651 #if PVMF_SOCKALLOC_FILL_MEMBLK_ON_ALLOC 652 uint32 value = 0x00; 653 oscl_memset(aRequestPtr, value, aReqBlkSize); 654 #endif 655 // need to remove begin and end variables because of compiler warnings 656 PVMF_SOCKALLOC_LOG_SEQNUM_ALLOC_DEALLOC((0, "PVMFSMSharedBufferAllocWithReSize::allocate - Alloc SeqNum=%d", iSeqCount)); 657 658 PVMF_SOCKALLOC_LOG_ALLOC_RESIZE_DEALLOC((0, "PVMFSMReSize::allocate - " 659 "SeqNum=%d, PtrS=0x%x, PtrE=0x%x, Begin=%d, End=%d, AllocSize=%d, LastDeallocPtr=0x%x, Avail=%d", 660 iSeqCount, 661 aPCContainer->iAllocationPtr, 662 aPCContainer->iAllocationPtr + n, 663 (aPCContainer->iAllocationPtr - aPCContainer->iParentChunkStart), 664 (aPCContainer->iAllocationPtr - aPCContainer->iParentChunkStart) + n, 665 n, 666 aPCContainer->iEndOfLastDeallocatedBlock, 667 getTotalAvailableBufferSpace())); 668 aPCContainer->iAllocationPtr += n; 669 670 PVMF_SOCKALLOC_LOG_AVAILABILITY((0, "PVMFSMSBAWithReSize::allocate - Name=%s, SN=%d, Alloc=%d, Avail=%d, BufsOS=%d", 671 iName.get_cstr(), iSeqCount, n, getTotalAvailableBufferSpace(), iNumOutStandingBuffers)); 672 673 iSeqCount++; 674 675 iJJDataSize += aReqBlkSize; 676 iJJDataDbgSize += aReqBlkSize; 677 678 return (PVMF_RESIZE_ALLOC_SUCCESS); 679 } 680 allocate(const uint32 n)681 OsclAny* allocate(const uint32 n) 682 { 683 OsclAny* requestPtr = NULL; 684 PVMF_RESIZE_ALLOC_ERROR_CODE errCode; 685 686 Oscl_Vector<ParentChunkContainer, OsclMemAllocator>::iterator it; 687 688 for (it = iParentChunkContainerVec.begin(); 689 it != iParentChunkContainerVec.end(); 690 it++) 691 { 692 errCode = AllocateInParentChunk(it, requestPtr, n); 693 694 if (errCode == PVMF_RESIZE_ALLOC_MEMORY_CORRUPT) 695 { 696 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::allocate - MEMORY CHUNKS CORRUPT!!! Name=%s", iName.get_cstr())); 697 OSCL_LEAVE(OsclErrCorrupt); 698 } 699 else if (errCode == PVMF_RESIZE_ALLOC_SUCCESS) 700 { 701 return requestPtr; 702 } 703 } 704 /* 705 * This implies that we cannot accomodate the request in any 706 * of the existing chunks. Allocate a new parent chunk. 707 */ 708 if (iiNumGrows == iiMaxNumGrows) 709 { 710 //PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::allocate - Unable to add an another buffer. Limit exceeded.", iName.get_cstr())); 711 OSCL_LEAVE(OsclErrNoMemory); // not graceful - can I return NULL instead? TBD. 712 } 713 iiNumGrows++; 714 CreateParentChunk(iiRegrowthSize); 715 716 PVMF_SOCKALLOC_LOGINFO((0, "PVMFSMSharedBufferAllocWithReSize::allocate - EXPANDING JITTER BUFFER - Name=%s, Size=%d", iName.get_cstr(), iiRegrowthSize)); 717 718 ParentChunkContainer newPCContainer = iParentChunkContainerVec.back(); 719 720 errCode = AllocateInParentChunk(&newPCContainer, requestPtr, n); 721 iParentChunkContainerVec[iParentChunkContainerVec.size()-1] = newPCContainer; 722 723 if (errCode == PVMF_RESIZE_ALLOC_MEMORY_CORRUPT) 724 { 725 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::allocate - MEMORY CHUNKS CORRUPT!!! Name=%s", iName.get_cstr())); 726 OSCL_LEAVE(OsclErrCorrupt); 727 } 728 else if (errCode == PVMF_RESIZE_ALLOC_NO_MEMORY) 729 { 730 /* Too big of a request */ 731 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::allocate - TOO BIG A REQUEST Name=%s, ReqSize=%d", iName.get_cstr(), n)); 732 OSCL_LEAVE(OsclErrNoMemory); 733 } 734 return requestPtr; 735 } 736 FindParentChunk(const OsclAny * p)737 ParentChunkContainer* FindParentChunk(const OsclAny* p) 738 { 739 const uint8* deallocPtr = reinterpret_cast<const uint8*>(p); 740 741 Oscl_Vector<ParentChunkContainer, OsclMemAllocator>::iterator it; 742 743 for (it = iParentChunkContainerVec.begin(); 744 it != iParentChunkContainerVec.end(); 745 it++) 746 { 747 if ((deallocPtr >= it->iParentChunkStart) && 748 (deallocPtr < it->iParentChunkEnd)) 749 { 750 return (it); 751 } 752 } 753 return NULL; 754 } 755 756 PVMF_RESIZE_ALLOC_ERROR_CODE 757 DeallocateFromParentChunk(ParentChunkContainer* aPCContainer, 758 const OsclAny* aDeallocPtr, 759 bool oEnableOutofOrderCheck = true) 760 { 761 uint32 seqNum = 0; 762 uint32 blkSize = 0; 763 uint8* p = ((uint8*)(aDeallocPtr) - PVMF_RESIZE_ALLOC_OVERHEAD); 764 /* Get the corresponding block size & seqnum from the pointer itself */ 765 oscl_memcpy(&seqNum, (OsclAny*)p, sizeof(uint32)); 766 oscl_memcpy(&blkSize, (OsclAny*)(p + PVMF_RESIZE_ALLOC_BLK_SIZE_OFFSET), sizeof(uint32)); 767 blkSize += PVMF_RESIZE_ALLOC_OVERHEAD; 768 if (oEnableOutofOrderCheck) 769 { 770 iJJDataSize -= (blkSize - PVMF_RESIZE_ALLOC_OVERHEAD); 771 if (seqNum != (uint32)(iLastDeallocatedSeqNum + 1)) 772 { 773 if (seqNum + 1 == iSeqCount) 774 {//just allocated, now free, so we pretend we didn't allocate this one to increase mem efficiency 775 if (aPCContainer->iAllocationPtr != p + blkSize) 776 { 777 PVMF_SOCKALLOC_LOG_ALLOC_RESIZE_DEALLOC((0, "SM ATTN seqNum %d blkSize %d iAlloc 0x%x p 0x%x Ln %d" 778 , seqNum, blkSize, aPCContainer->iAllocationPtr, p, __LINE__)); 779 PVMF_SOCKALLOC_LOG_ALLOC_RESIZE_DEALLOC((0, "SM ATTN start 0x%x end 0x%x lastD 0x%x Ln %d" 780 , aPCContainer->iParentChunkStart, aPCContainer->iParentChunkEnd, aPCContainer->iEndOfLastDeallocatedBlock, __LINE__)); 781 } 782 783 iJJDataDbgSize -= (blkSize - PVMF_RESIZE_ALLOC_OVERHEAD); 784 785 aPCContainer->iAllocationPtr = p; 786 787 iNumOutStandingBuffers--; 788 iSeqCount--; 789 return (PVMF_RESIZE_ALLOC_SUCCESS); 790 } 791 792 bool oRet = iOutOfOrderBlocks.Insert(aDeallocPtr, seqNum); 793 if (oRet == true) 794 { 795 iNumOutOfOrderDeallocs++; 796 } 797 PVMF_SOCKALLOC_LOG_OUT_OF_ORDER_DEALLOC((0, "PVMFSMSharedBufferAllocWithReSize::DeallocateFromParentChunk - OOO Dealloc SeqNum=%d, Size=%d, Ptr=0x%x, NumOOODeallocs=%d", seqNum, blkSize, p, iNumOutOfOrderDeallocs)); 798 return (PVMF_RESIZE_OUT_OF_ORDER_BLOCK); 799 } 800 801 } 802 803 iJJDataDbgSize -= (blkSize - PVMF_RESIZE_ALLOC_OVERHEAD); 804 805 iLastDeallocatedSeqNum = (int32)(seqNum); 806 aPCContainer->iEndOfLastDeallocatedBlock = ((uint8*)p + blkSize); 807 808 if (aPCContainer->iEndOfLastDeallocatedBlock == aPCContainer->iAllocationPtr) 809 { 810 aPCContainer->iEndOfLastDeallocatedBlock = NULL; 811 aPCContainer->iAllocationPtr = aPCContainer->iParentChunkStart; 812 } 813 iNumOutStandingBuffers--; 814 815 #if PVMF_SOCKALLOC_FILL_MEMBLK_ON_ALLOC 816 uint32 value = 0x00; 817 oscl_memset(p, value, blkSize); 818 #endif 819 // need to remove begin and end variables because of compiler warnings 820 PVMF_SOCKALLOC_LOG_SEQNUM_ALLOC_DEALLOC((0, "PVMFSMSharedBufferAllocWithReSize::DeallocateFromParentChunk - Dealloc SeqNum=%d", iLastDeallocatedSeqNum)); 821 PVMF_SOCKALLOC_LOG_ALLOC_RESIZE_DEALLOC((0, "PVMFSMReSize::Dealloc - " 822 "SeqNum=%d, PtrS=0x%x, PtrE=0x%x, Begin=%d, End=%d, BlockSize=%d, LastDeallocatedPtr=0x%x, Avail=%d", 823 seqNum, 824 p, 825 p + blkSize, 826 ((uint8*)p - aPCContainer->iParentChunkStart), 827 ((uint8*)p - aPCContainer->iParentChunkStart) + blkSize, 828 blkSize, 829 aPCContainer->iEndOfLastDeallocatedBlock, 830 getTotalAvailableBufferSpace())); 831 PVMF_SOCKALLOC_LOG_AVAILABILITY((0, "PVMFSMSBAWithReSize::DeallocateFromParentChunk - Name=%s, SN=%d, Dealloc=%d, Avail=%d, BufsOS=%d", 832 iName.get_cstr(), seqNum, blkSize, getTotalAvailableBufferSpace(), iNumOutStandingBuffers)); 833 return (PVMF_RESIZE_ALLOC_SUCCESS); 834 } 835 836 PVMF_RESIZE_ALLOC_ERROR_CODE SearchAndDeallocateAnyPrevOutofOrderBlocks(uint32 aSeqNum)837 SearchAndDeallocateAnyPrevOutofOrderBlocks(uint32 aSeqNum) 838 { 839 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator>* deleteList = 840 iOutOfOrderBlocks.GetDeletables(aSeqNum); 841 842 if (deleteList == NULL) 843 { 844 return (PVMF_RESIZE_ALLOC_SUCCESS); 845 } 846 847 for (uint i = 0; i < (*deleteList).size(); i++) 848 { 849 DeallocateOutofOrderBlock((*deleteList)[i].ptr); 850 iNumOutOfOrderDeallocs--; 851 } 852 853 iOutOfOrderBlocks.Prune(); 854 return (PVMF_RESIZE_ALLOC_SUCCESS); 855 } 856 DeallocateOutofOrderBlock(const OsclAny * p)857 void DeallocateOutofOrderBlock(const OsclAny* p) 858 { 859 ParentChunkContainer* parentChunkContainer = FindParentChunk(p); 860 861 if (parentChunkContainer == NULL) 862 { 863 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::DeallocateOutofOrderBlock - INVALID PTR!!! Name=%s", iName.get_cstr())); 864 OSCL_LEAVE(OsclErrArgument); 865 } 866 bool oEnableOutofOrderCheck = false; 867 if (DeallocateFromParentChunk(parentChunkContainer, p, oEnableOutofOrderCheck) == PVMF_RESIZE_ALLOC_MEMORY_CORRUPT) 868 { 869 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::DeallocateOutofOrderBlock - CORRUPT PTR!!! Name=%s", iName.get_cstr())); 870 OSCL_LEAVE(OsclErrArgument); 871 } 872 } 873 PurgeOutofOrderBlockVec()874 void PurgeOutofOrderBlockVec() 875 { 876 if (iOutofOrderBlockVec.size() > 0) 877 { 878 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator>::iterator it; 879 uint32 count = iOutofOrderBlockVec.size(); 880 if (count != iNumOutOfOrderDeallocs) 881 { 882 OSCL_ASSERT(false); 883 } 884 while (iOutofOrderBlockVec.size() > 0) 885 { 886 it = iOutofOrderBlockVec.begin(); 887 DeallocateOutofOrderBlock(it->ptr); 888 iOutofOrderBlockVec.erase(it); 889 } 890 } 891 } 892 deallocate(OsclAny * p)893 virtual void deallocate(OsclAny* p) 894 { 895 ParentChunkContainer* parentChunkContainer = FindParentChunk(p); 896 if (parentChunkContainer == NULL) 897 { 898 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::deallocate - INVALID PTR!!! Name=%s", iName.get_cstr())); 899 OSCL_LEAVE(OsclErrArgument); 900 } 901 /* Deallocate the current ptr */ 902 PVMF_RESIZE_ALLOC_ERROR_CODE errCode = DeallocateFromParentChunk(parentChunkContainer, p); 903 904 if (errCode == PVMF_RESIZE_ALLOC_MEMORY_CORRUPT) 905 { 906 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::deallocate - CORRUPT PTR - 2!!! Name=%s", iName.get_cstr())); 907 OSCL_LEAVE(OsclErrArgument); 908 } 909 else if ((errCode == PVMF_RESIZE_ALLOC_SUCCESS) || (errCode == PVMF_RESIZE_OUT_OF_ORDER_BLOCK)) 910 { 911 if (iDeallocObserver != NULL) 912 { 913 iDeallocObserver->chunkdeallocated(iDeallocNotificationContextData); 914 } 915 /* Deallocate any out of order blocks */ 916 if (iNumOutOfOrderDeallocs > 0) 917 { 918 SearchAndDeallocateAnyPrevOutofOrderBlocks(iLastDeallocatedSeqNum); 919 } 920 921 if (iNumOutOfOrderDeallocs > 0) 922 {//delete from head, maybe? 923 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator>* deleteList = 924 iOutOfOrderBlocks.GetHeadDeletables(iSeqCount); 925 926 if (NULL != deleteList) 927 { 928 for (int32 i = (*deleteList).size() - 1; i >= 0; i--) 929 { 930 uint8* p = (uint8*)((*deleteList)[i].ptr); 931 ParentChunkContainer* parentChunkContainer = FindParentChunk(p); 932 933 if (parentChunkContainer == NULL) 934 { 935 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::deallocate - INVALID PTR!!! Name=%s Ln %d", iName.get_cstr(), __LINE__)); 936 OSCL_LEAVE(OsclErrArgument); 937 } 938 uint32 seqNum = 0; 939 uint32 blkSize = 0; 940 p -= PVMF_RESIZE_ALLOC_OVERHEAD; 941 /* Get the corresponding block size & seqnum from the pointer itself */ 942 oscl_memcpy(&seqNum, (OsclAny*)p, sizeof(uint32)); 943 oscl_memcpy(&blkSize, (OsclAny*)(p + PVMF_RESIZE_ALLOC_BLK_SIZE_OFFSET), sizeof(uint32)); 944 945 if (seqNum + 1 != iSeqCount) 946 { 947 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::deallocate - ERROR seqNum %d iSeqCount %d Name=%s", seqNum, iSeqCount, iName.get_cstr())); 948 OSCL_LEAVE(OsclErrArgument); 949 } 950 951 if (p + blkSize + PVMF_RESIZE_ALLOC_OVERHEAD != parentChunkContainer->iAllocationPtr) 952 {//just for logging wrap-around 953 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::deallocate - p 0x%x iAllocPtr 0x%x seqNum %d iSeqCount %d Name=%s", 954 p, parentChunkContainer->iAllocationPtr, seqNum, iSeqCount, iName.get_cstr())); 955 } 956 parentChunkContainer->iAllocationPtr = p; 957 958 OSCL_ASSERT(parentChunkContainer->iAllocationPtr != parentChunkContainer->iEndOfLastDeallocatedBlock); 959 960 iNumOutOfOrderDeallocs--; 961 iNumOutStandingBuffers--; 962 iSeqCount--; 963 iJJDataDbgSize -= blkSize; 964 } 965 966 iOutOfOrderBlocks.PruneHead(deleteList); 967 } 968 } 969 } 970 CheckAndNotifyFreeChunkAvailable(); 971 } 972 973 PVMF_RESIZE_ALLOC_ERROR_CODE ReSizeFromParentChunk(ParentChunkContainer * aPCContainer,OsclAny * aPtr,uint32 aBytesToReclaim)974 ReSizeFromParentChunk(ParentChunkContainer* aPCContainer, 975 OsclAny* aPtr, 976 uint32 aBytesToReclaim) 977 { 978 uint32 seqNum = 0; 979 uint32 blkSize = 0; 980 uint8* p = ((uint8*)(aPtr) - PVMF_RESIZE_ALLOC_OVERHEAD); 981 /* Get the corresponding block size & seqnum from the pointer itself */ 982 oscl_memcpy(&seqNum, (OsclAny*)p, sizeof(uint32)); 983 oscl_memcpy(&blkSize, (OsclAny*)(p + PVMF_RESIZE_ALLOC_BLK_SIZE_OFFSET), sizeof(uint32)); 984 if (aBytesToReclaim > blkSize) 985 { 986 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::ReSizeFromParentChunk - Invalid Reclaim Size - Name=%s, ChunkID=%d, SeqNum=%d, Ptr=0x%x, BlockSize=%d, ReclaimSize=%d", iName.get_cstr(), aPCContainer->id, seqNum, p, blkSize, aBytesToReclaim)); 987 return (PVMF_RESIZE_ALLOC_MEMORY_CORRUPT); 988 } 989 blkSize -= aBytesToReclaim; 990 aPCContainer->iAllocationPtr -= aBytesToReclaim; 991 992 iJJDataSize -= aBytesToReclaim; 993 iJJDataDbgSize -= aBytesToReclaim; 994 if (iSeqCount > seqNum + 1) 995 { 996 //Resize can ONLY be applied to the buffer just allocated. 997 PVMF_SOCKALLOC_LOGERROR((0, "Resize ERROR seq %d iSeqCount %d iJJDataSize %d", seqNum, iSeqCount, iJJDataSize)); 998 return (PVMF_RESIZE_ALLOC_MEMORY_CORRUPT); 999 } 1000 /* reset the block size */ 1001 oscl_memcpy((OsclAny*)(p + PVMF_RESIZE_ALLOC_BLK_SIZE_OFFSET), 1002 &blkSize, 1003 sizeof(uint32)); 1004 // need to remove begin and end variables because of compiler warnings 1005 PVMF_SOCKALLOC_LOG_ALLOC_RESIZE_DEALLOC((0, "PVMFSMReSize::ReSize - " 1006 "SeqNum=%d, PtrS=0x%x, PtrE=0x%x, AllocPtr=0x%x, Begin=%d, End=%d, NewSize=%d, Avail=%d", 1007 seqNum, 1008 p, 1009 p + blkSize + PVMF_RESIZE_ALLOC_OVERHEAD, 1010 aPCContainer->iAllocationPtr, 1011 (p - aPCContainer->iParentChunkStart), 1012 (p - aPCContainer->iParentChunkStart) + blkSize + PVMF_RESIZE_ALLOC_OVERHEAD, 1013 blkSize, 1014 getTotalAvailableBufferSpace())); 1015 PVMF_SOCKALLOC_LOG_AVAILABILITY((0, "PVMFSMSBAWithReSize::ReSizeFromParentChunk - Name=%s, SN=%d, Reclaim=%d, Avail=%d", 1016 iName.get_cstr(), seqNum, aBytesToReclaim, getTotalAvailableBufferSpace())); 1017 return (PVMF_RESIZE_ALLOC_SUCCESS); 1018 } 1019 resize(OsclAny * p,uint32 aBytesToReclaim)1020 void resize(OsclAny* p, uint32 aBytesToReclaim) 1021 { 1022 ParentChunkContainer* parentChunkContainer = FindParentChunk(p); 1023 1024 if (parentChunkContainer == NULL) 1025 { 1026 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::resize - INVALID PTR!!! Name=%s", iName.get_cstr())); 1027 OSCL_LEAVE(OsclErrArgument); 1028 } 1029 if (ReSizeFromParentChunk(parentChunkContainer, 1030 p, 1031 aBytesToReclaim) == PVMF_RESIZE_ALLOC_MEMORY_CORRUPT) 1032 { 1033 PVMF_SOCKALLOC_LOGERROR((0, "PVMFSMSharedBufferAllocWithReSize::resize - INVALID PTR!!! Name=%s", iName.get_cstr())); 1034 OSCL_LEAVE(OsclErrArgument); 1035 } 1036 CheckAndNotifyFreeChunkAvailable(); 1037 } 1038 getNumOutStandingBuffers()1039 uint32 getNumOutStandingBuffers() 1040 { 1041 return iNumOutStandingBuffers; 1042 } 1043 getTotalBufferSize()1044 uint32 getTotalBufferSize() 1045 { 1046 uint32 totalsize = 0; 1047 Oscl_Vector<ParentChunkContainer, OsclMemAllocator>::iterator it; 1048 for (it = iParentChunkContainerVec.begin(); 1049 it != iParentChunkContainerVec.end(); 1050 it++) 1051 { 1052 totalsize += it->iParentChunkSize; 1053 } 1054 return (totalsize); 1055 } 1056 getTotalAvailableBufferSpace()1057 uint32 getTotalAvailableBufferSpace() 1058 { 1059 uint32 freespace = 0; 1060 Oscl_Vector<ParentChunkContainer, OsclMemAllocator>::iterator it; 1061 if ((iNumOutStandingBuffers == 1) && 1062 (iDecKeepAliveCalled == false)) 1063 { 1064 // all outstanding buffers have been freed 1065 freespace = getTotalBufferSize(); 1066 for (it = iParentChunkContainerVec.begin(); 1067 it != iParentChunkContainerVec.end(); 1068 it++) 1069 { 1070 it->iEndOfLastDeallocatedBlock = NULL; 1071 it->iAllocationPtr = it->iParentChunkStart; 1072 } 1073 } 1074 else 1075 { 1076 for (it = iParentChunkContainerVec.begin(); 1077 it != iParentChunkContainerVec.end(); 1078 it++) 1079 { 1080 freespace += FindLargestContiguousFreeBlock(it); 1081 } 1082 } 1083 return (freespace); 1084 } 1085 getActualDataSize()1086 uint32 getActualDataSize() 1087 { 1088 return iJJDataSize; 1089 } 1090 getTrueBufferSpace()1091 uint32 getTrueBufferSpace() 1092 { 1093 uint32 truespace = 0; 1094 Oscl_Vector<ParentChunkContainer, OsclMemAllocator>::iterator it; 1095 if ((iNumOutStandingBuffers == 1) && 1096 (iDecKeepAliveCalled == false)) 1097 { 1098 // all outstanding buffers have been freed 1099 truespace = getTotalBufferSize(); 1100 for (it = iParentChunkContainerVec.begin(); 1101 it != iParentChunkContainerVec.end(); 1102 it++) 1103 { 1104 it->iEndOfLastDeallocatedBlock = NULL; 1105 it->iAllocationPtr = it->iParentChunkStart; 1106 } 1107 } 1108 else 1109 { 1110 for (it = iParentChunkContainerVec.begin(); 1111 it != iParentChunkContainerVec.end(); 1112 it++) 1113 { 1114 uint32 maxSize = 0; 1115 if (it != NULL) 1116 { 1117 if (it->iEndOfLastDeallocatedBlock == NULL) 1118 { 1119 /* 1120 * Implies that there is no deallocations have happenned 1121 */ 1122 maxSize = 1123 (it->iParentChunkEnd - it->iAllocationPtr); 1124 } 1125 else 1126 { 1127 if (it->iAllocationPtr <= it->iEndOfLastDeallocatedBlock) 1128 { 1129 maxSize = 1130 (it->iEndOfLastDeallocatedBlock - it->iAllocationPtr); 1131 } 1132 else 1133 { 1134 uint32 free_end = 1135 (it->iParentChunkEnd - it->iAllocationPtr); 1136 uint32 free_begin = 1137 (it->iEndOfLastDeallocatedBlock - it->iParentChunkStart); 1138 maxSize = free_end + free_begin; 1139 } 1140 } 1141 } 1142 truespace += maxSize; 1143 } 1144 } 1145 PVMF_SOCKALLOC_LOG_AVAILABILITY((0, "SM alloc space new1 %d new2 %d kspace %d Ln %d", iJJDataSize, iJJDataDbgSize, truespace, __LINE__)); 1146 return (truespace); 1147 } 1148 1149 FindLargestContiguousFreeBlock(ParentChunkContainer * aPtr)1150 uint32 FindLargestContiguousFreeBlock(ParentChunkContainer* aPtr) 1151 { 1152 ParentChunkContainer* it = aPtr; 1153 uint32 maxSize = 0; 1154 if (it != NULL) 1155 { 1156 if (it->iEndOfLastDeallocatedBlock == NULL) 1157 { 1158 /* 1159 * Implies that there is no deallocations have happenned 1160 */ 1161 maxSize = 1162 (it->iParentChunkEnd - it->iAllocationPtr); 1163 } 1164 else 1165 { 1166 /* 1167 * There are two possibilites: 1168 * 1) iAllocationPtr < iEndOfLastDeallocatedBlock - This means 1169 * that a wrap around has happenned, and we need to check 1170 * if there is a large enough block between the two ptrs. 1171 * Please note that we assume that the space between 1172 * iAllocationPtr and iEndOfLastDeallocatedBlock is all free. 1173 * Reason being that blocks are deallocated in the same 1174 * order in which they are allocated. 1175 * 1176 * 2) iAllocationPtr > iEndOfLastDeallocatedBlock - This means 1177 * we are ok. 1178 * 1179 */ 1180 if (it->iAllocationPtr <= it->iEndOfLastDeallocatedBlock) 1181 { 1182 maxSize = 1183 (it->iEndOfLastDeallocatedBlock - it->iAllocationPtr); 1184 } 1185 else 1186 { 1187 uint32 free_end = 1188 (it->iParentChunkEnd - it->iAllocationPtr); 1189 uint32 free_begin = 1190 (it->iEndOfLastDeallocatedBlock - it->iParentChunkStart); 1191 if (free_end > free_begin) 1192 { 1193 maxSize = free_end; 1194 } 1195 else 1196 { 1197 maxSize = free_begin; 1198 } 1199 } 1200 } 1201 } 1202 return (maxSize); 1203 } 1204 1205 1206 uint32 getAvailableBufferSpace(bool aFirstParentChunkOnly = false) 1207 { 1208 uint32 freespace = 0; 1209 Oscl_Vector<ParentChunkContainer, OsclMemAllocator>::iterator it; 1210 if (aFirstParentChunkOnly) 1211 { 1212 /* 1213 * Since we cannot inform the server about buffer growth, we 1214 * should only send free space from the first allocated chunk. 1215 */ 1216 it = iParentChunkContainerVec.begin(); 1217 freespace = FindLargestContiguousFreeBlock(it); 1218 } 1219 else 1220 { 1221 for (it = iParentChunkContainerVec.begin(); 1222 it != iParentChunkContainerVec.end(); 1223 it++) 1224 { 1225 uint32 size = FindLargestContiguousFreeBlock(it); 1226 if (size > freespace) 1227 { 1228 freespace = size; 1229 } 1230 } 1231 } 1232 return (freespace); 1233 } 1234 1235 void notifyfreechunkavailable(OsclMemPoolFixedChunkAllocatorObserver& aObserver, 1236 uint32 aSize, 1237 OsclAny* aContextData = NULL) 1238 { 1239 PVMF_SOCKALLOC_LOG_MEMCALLBACK((0, "notifyfreechunkavailable - reqSize=%d", (aSize + PVMF_RESIZE_ALLOC_OVERHEAD))); 1240 iCallbackPending = true; 1241 iCallbackRequestSize = aSize + PVMF_RESIZE_ALLOC_OVERHEAD; 1242 iObserver = &aObserver; 1243 iNextAvailableContextData = aContextData; 1244 } 1245 CancelFreeChunkAvailableCallback()1246 void CancelFreeChunkAvailableCallback() 1247 { 1248 iCallbackPending = false; 1249 iCallbackRequestSize = 0; 1250 iObserver = NULL; 1251 } 1252 CheckAndNotifyFreeChunkAvailable()1253 void CheckAndNotifyFreeChunkAvailable() 1254 { 1255 if (iCallbackPending == true) 1256 { 1257 uint32 availSize = getTrueBufferSpace(); 1258 1259 PVMF_SOCKALLOC_LOG_MEMCALLBACK((0, "CheckAndNotifyFreeChunkAvailable() availSize %d", availSize)); 1260 if (availSize > iCallbackRequestSize) 1261 { 1262 PVMF_SOCKALLOC_LOG_MEMCALLBACK((0, "CheckAndNotifyFreeChunkAvailable() availSize(%d) > iCallbackRequestSize(%d)", availSize, iCallbackRequestSize)); 1263 if (iObserver == NULL) 1264 return; 1265 OsclMemPoolFixedChunkAllocatorObserver* MyObserver = iObserver; 1266 PVMF_SOCKALLOC_LOG_MEMCALLBACK((0, "CheckAndNotifyFreeChunkAvailable() MyObserver(0x%x) iObserver(0x%x) ", MyObserver, iObserver)); 1267 CancelFreeChunkAvailableCallback(); 1268 PVMF_SOCKALLOC_LOG_MEMCALLBACK((0, "CheckAndNotifyFreeChunkAvailable MyObserver(0x%x)", MyObserver)); 1269 MyObserver->freechunkavailable(iNextAvailableContextData); 1270 PVMF_SOCKALLOC_LOG_MEMCALLBACK((0, "CheckAndNotifyFreeChunkAvailable() iNextAvailableContextData %d out", iNextAvailableContextData)); 1271 } 1272 } 1273 } 1274 1275 void NotifyDeallocations(PVMFSMSharedBufferAllocWithReSizeAllocDeallocObserver& aObserver, 1276 OsclAny* aContextData = NULL) 1277 { 1278 iDeallocObserver = &aObserver; 1279 iDeallocNotificationContextData = aContextData; 1280 } 1281 CancelDeallocationNotifications()1282 void CancelDeallocationNotifications() 1283 { 1284 iDeallocObserver = NULL; 1285 iDeallocNotificationContextData = NULL; 1286 } 1287 1288 private: 1289 Oscl_Vector<ParentChunkContainer, OsclMemAllocator> iParentChunkContainerVec; 1290 1291 OsclMemAllocator alloc; 1292 1293 uint32 iNumOutOfOrderDeallocs; 1294 Oscl_Vector<OutOfOrderBlockContainer, OsclMemAllocator> iOutofOrderBlockVec; 1295 1296 int32 iLastDeallocatedSeqNum; 1297 uint32 iSeqCount; 1298 uint32 iNumOutStandingBuffers; 1299 PVLogger *iLogger; 1300 PVLogger *iSizeLogger; 1301 PVLogger *iCallBackLogger; 1302 PVLogger *iOOOLogger; 1303 uint32 iJJDataSize; 1304 uint32 iJJDataDbgSize; 1305 OSCL_HeapString<OsclMemAllocator> iName; 1306 ReassemblyBlockList iOutOfOrderBlocks; 1307 1308 // buffer resize parameters 1309 uint iiMaxNumGrows; 1310 uint iiNumGrows; 1311 uint iiRegrowthSize; 1312 1313 //callback related params 1314 bool iCallbackPending; 1315 uint32 iCallbackRequestSize; 1316 OsclMemPoolFixedChunkAllocatorObserver* iObserver; 1317 OsclAny* iNextAvailableContextData; 1318 1319 bool iDecKeepAliveCalled; 1320 1321 PVMFSMSharedBufferAllocWithReSizeAllocDeallocObserver* iDeallocObserver; 1322 OsclAny* iDeallocNotificationContextData; 1323 }; 1324 1325 class PVMFSMSharedBufferAllocWithReSizeCleanupDA : public OsclDestructDealloc 1326 { 1327 public: PVMFSMSharedBufferAllocWithReSizeCleanupDA(Oscl_DefAlloc * in_gen_alloc)1328 PVMFSMSharedBufferAllocWithReSizeCleanupDA(Oscl_DefAlloc* in_gen_alloc) : 1329 gen_alloc(in_gen_alloc) {}; 1330 ~PVMFSMSharedBufferAllocWithReSizeCleanupDA()1331 virtual ~PVMFSMSharedBufferAllocWithReSizeCleanupDA() {}; 1332 destruct_and_dealloc(OsclAny * ptr)1333 virtual void destruct_and_dealloc(OsclAny* ptr) 1334 { 1335 /* 1336 * get number of outstanding buffers from the allocator 1337 */ 1338 Oscl_DefAlloc* myalloc = gen_alloc; 1339 PVMFSMSharedBufferAllocWithReSize* socketDataAllocator = 1340 reinterpret_cast<PVMFSMSharedBufferAllocWithReSize*>(myalloc); 1341 gen_alloc->deallocate(ptr); 1342 1343 uint32 numBuffers = socketDataAllocator->getNumOutStandingBuffers(); 1344 1345 /* 1346 * get the number of buffers deallocated, after the pointer has 1347 * been deallocated. A single dealloc call can potentially deallocate 1348 * multiple buffers (if there are many out of order blocks). 1349 */ 1350 /* 1351 * in case there are no outstanding buffers delete the allocator 1352 */ 1353 if (numBuffers == 0) 1354 { 1355 OSCL_DELETE((socketDataAllocator)); 1356 } 1357 } 1358 1359 private: 1360 Oscl_DefAlloc* gen_alloc; 1361 }; 1362 1363 class PVMFSharedSocketDataBufferAlloc 1364 { 1365 public: PVMFSharedSocketDataBufferAlloc(Oscl_DefAlloc * in_gen_alloc)1366 PVMFSharedSocketDataBufferAlloc(Oscl_DefAlloc* in_gen_alloc) 1367 { 1368 iResizeAlloc = false; 1369 if (in_gen_alloc) 1370 { 1371 gen_alloc = in_gen_alloc; 1372 iBufferOverhead = 0; 1373 } 1374 else 1375 { 1376 OSCL_LEAVE(OsclErrArgument); 1377 } 1378 } 1379 PVMFSharedSocketDataBufferAlloc(PVMFSMSharedBufferAllocWithReSize * in_gen_alloc)1380 PVMFSharedSocketDataBufferAlloc(PVMFSMSharedBufferAllocWithReSize* in_gen_alloc) 1381 { 1382 iResizeAlloc = false; 1383 if (in_gen_alloc) 1384 { 1385 iResizeAlloc = true; 1386 gen_alloc = in_gen_alloc; 1387 iBufferOverhead = 0; 1388 uint aligned_class_size = 1389 oscl_mem_aligned_size(sizeof(PVMFSimpleMediaBuffer)); 1390 uint aligned_cleanup_size = 1391 oscl_mem_aligned_size(sizeof(PVMFSMSharedBufferAllocWithReSizeCleanupDA)); 1392 uint aligned_refcnt_size = 1393 oscl_mem_aligned_size(sizeof(OsclRefCounterDA)); 1394 iBufferOverhead = (aligned_refcnt_size + 1395 aligned_cleanup_size + 1396 aligned_class_size); 1397 1398 } 1399 else 1400 { 1401 OSCL_LEAVE(OsclErrArgument); 1402 } 1403 }; 1404 ~PVMFSharedSocketDataBufferAlloc()1405 virtual ~PVMFSharedSocketDataBufferAlloc() 1406 { 1407 }; 1408 createSharedBuffer(uint32 size)1409 OsclSharedPtr<PVMFMediaDataImpl> createSharedBuffer(uint32 size) 1410 { 1411 if (size == 0) 1412 { 1413 size = PVMF_SOCKET_BUF_DEFAULT_SIZE; 1414 } 1415 1416 uint aligned_in_size = oscl_mem_aligned_size(size); 1417 1418 if (iResizeAlloc) 1419 { 1420 uint8* my_ptr; 1421 OsclRefCounter* my_refcnt; 1422 1423 uint aligned_class_size = 1424 oscl_mem_aligned_size(sizeof(PVMFSimpleMediaBuffer)); 1425 1426 uint aligned_cleanup_size = 1427 oscl_mem_aligned_size(sizeof(PVMFSMSharedBufferAllocWithReSizeCleanupDA)); 1428 1429 uint aligned_refcnt_size = 1430 oscl_mem_aligned_size(sizeof(OsclRefCounterDA)); 1431 1432 my_ptr = (uint8*) gen_alloc->allocate(aligned_refcnt_size + 1433 aligned_cleanup_size + 1434 aligned_class_size + 1435 aligned_in_size); 1436 1437 PVMFSMSharedBufferAllocWithReSizeCleanupDA *my_cleanup = 1438 OSCL_PLACEMENT_NEW(my_ptr + aligned_refcnt_size, PVMFSMSharedBufferAllocWithReSizeCleanupDA(gen_alloc)); 1439 1440 my_refcnt = 1441 OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterDA(my_ptr, my_cleanup)); 1442 1443 my_ptr += aligned_refcnt_size + aligned_cleanup_size; 1444 1445 void* ptr; 1446 ptr = my_ptr + aligned_class_size; 1447 1448 PVMFMediaDataImpl* media_data_ptr = 1449 new(my_ptr) PVMFSimpleMediaBuffer(ptr, 1450 aligned_in_size, 1451 my_refcnt); 1452 1453 OsclSharedPtr<PVMFMediaDataImpl> shared_media_data(media_data_ptr, 1454 my_refcnt); 1455 return shared_media_data; 1456 } 1457 else 1458 { 1459 uint8* my_ptr; 1460 OsclRefCounter* my_refcnt; 1461 1462 uint aligned_class_size = 1463 oscl_mem_aligned_size(sizeof(PVMFSimpleMediaBuffer)); 1464 1465 uint aligned_cleanup_size = 1466 oscl_mem_aligned_size(sizeof(PVMFSocketBufferCleanupDA)); 1467 1468 uint aligned_refcnt_size = 1469 oscl_mem_aligned_size(sizeof(OsclRefCounterDA)); 1470 1471 my_ptr = (uint8*) gen_alloc->allocate(aligned_refcnt_size + 1472 aligned_cleanup_size + 1473 aligned_class_size + 1474 aligned_in_size); 1475 1476 PVMFSocketBufferCleanupDA *my_cleanup = 1477 OSCL_PLACEMENT_NEW(my_ptr + aligned_refcnt_size, PVMFSocketBufferCleanupDA(gen_alloc)); 1478 1479 my_refcnt = 1480 OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterDA(my_ptr, my_cleanup)); 1481 1482 my_ptr += aligned_refcnt_size + aligned_cleanup_size; 1483 1484 void* ptr; 1485 ptr = my_ptr + aligned_class_size; 1486 1487 PVMFMediaDataImpl* media_data_ptr = 1488 new(my_ptr) PVMFSimpleMediaBuffer(ptr, 1489 aligned_in_size, 1490 my_refcnt); 1491 1492 OsclSharedPtr<PVMFMediaDataImpl> shared_media_data(media_data_ptr, 1493 my_refcnt); 1494 return shared_media_data; 1495 } 1496 } 1497 ResizeMemoryFragment(OsclSharedPtr<PVMFMediaDataImpl> & aSharedBuffer)1498 void ResizeMemoryFragment(OsclSharedPtr<PVMFMediaDataImpl>& aSharedBuffer) 1499 { 1500 if (iResizeAlloc) 1501 { 1502 OsclRefCounterMemFrag memFrag; 1503 aSharedBuffer->getMediaFragment(0, memFrag); 1504 uint32 currCapacity = memFrag.getCapacity(); 1505 uint32 bytesUsed = memFrag.getMemFragSize(); 1506 1507 //uint32 alignedBytesUsed = bytesUsed; 1508 uint32 alignedBytesUsed = oscl_mem_aligned_size(bytesUsed); 1509 1510 if (alignedBytesUsed < currCapacity) 1511 { 1512 uint32 bytesToReclaim = (currCapacity - alignedBytesUsed); 1513 PVMFSMSharedBufferAllocWithReSize* socketDataAllocator = 1514 reinterpret_cast<PVMFSMSharedBufferAllocWithReSize*>(gen_alloc); 1515 /* Account for the overhead */ 1516 uint8* memFragPtr = (uint8*)(memFrag.getMemFragPtr()); 1517 uint8* ptr = (memFragPtr - iBufferOverhead); 1518 socketDataAllocator->resize((OsclAny*)ptr, bytesToReclaim); 1519 aSharedBuffer->setCapacity(alignedBytesUsed); 1520 } 1521 } 1522 } 1523 1524 uint32 getAvailableBufferSpace(bool aFirstParentChunkOnly = false) 1525 { 1526 if (iResizeAlloc) 1527 { 1528 PVMFSMSharedBufferAllocWithReSize* socketDataAllocator = 1529 reinterpret_cast<PVMFSMSharedBufferAllocWithReSize*>(gen_alloc); 1530 return (socketDataAllocator->getAvailableBufferSpace(aFirstParentChunkOnly)); 1531 } 1532 else 1533 { 1534 PVMFSocketBufferAllocator* socketDataAllocator = 1535 reinterpret_cast<PVMFSocketBufferAllocator*>(gen_alloc); 1536 return (socketDataAllocator->getAvailableBufferSpace(aFirstParentChunkOnly)); 1537 } 1538 } 1539 void notifyfreechunkavailable(OsclMemPoolFixedChunkAllocatorObserver& aObserver, 1540 uint32 aSize, 1541 OsclAny* aContextData = NULL) 1542 { 1543 if (iResizeAlloc) 1544 { 1545 PVMFSMSharedBufferAllocWithReSize* socketDataAllocator = 1546 reinterpret_cast<PVMFSMSharedBufferAllocWithReSize*>(gen_alloc); 1547 socketDataAllocator->notifyfreechunkavailable(aObserver, (aSize + iBufferOverhead), aContextData); 1548 } 1549 else 1550 { 1551 PVMFSocketBufferAllocator* socketDataAllocator = 1552 reinterpret_cast<PVMFSocketBufferAllocator*>(gen_alloc); 1553 socketDataAllocator->notifyfreechunkavailable(aObserver, (aSize + iBufferOverhead), aContextData); 1554 } 1555 } 1556 CancelFreeChunkAvailableCallback()1557 void CancelFreeChunkAvailableCallback() 1558 { 1559 if (iResizeAlloc) 1560 { 1561 PVMFSMSharedBufferAllocWithReSize* socketDataAllocator = 1562 reinterpret_cast<PVMFSMSharedBufferAllocWithReSize*>(gen_alloc); 1563 socketDataAllocator->CancelFreeChunkAvailableCallback(); 1564 } 1565 else 1566 { 1567 PVMFSocketBufferAllocator* socketDataAllocator = 1568 reinterpret_cast<PVMFSocketBufferAllocator*>(gen_alloc); 1569 socketDataAllocator->CancelFreeChunkAvailableCallback(); 1570 } 1571 } 1572 1573 private: 1574 bool iResizeAlloc; 1575 uint iBufferOverhead; 1576 Oscl_DefAlloc* gen_alloc; 1577 }; 1578 1579 class PVMFSharedSocketDataBufferAllocCleanupSA : public OsclDestructDealloc 1580 { 1581 public: ~PVMFSharedSocketDataBufferAllocCleanupSA()1582 virtual ~PVMFSharedSocketDataBufferAllocCleanupSA() {}; 1583 destruct_and_dealloc(OsclAny * ptr)1584 virtual void destruct_and_dealloc(OsclAny* ptr) 1585 { 1586 uint8* tmp_ptr = (uint8*) ptr; 1587 1588 uint aligned_refcnt_size = 1589 oscl_mem_aligned_size(sizeof(OsclRefCounterSA<PVMFSharedSocketDataBufferAllocCleanupSA>)); 1590 1591 tmp_ptr += aligned_refcnt_size; 1592 PVMFSharedSocketDataBufferAlloc* socketDataBufferAlloc = 1593 reinterpret_cast<PVMFSharedSocketDataBufferAlloc*>(tmp_ptr); 1594 1595 socketDataBufferAlloc->~PVMFSharedSocketDataBufferAlloc(); 1596 OsclMemAllocator alloc; 1597 alloc.deallocate(ptr); 1598 } 1599 }; 1600 1601 1602 #endif //PVMF_STREAMING_BUFFER_ALLOCATORS_H_INCLUDED 1603