1 /* 2 * Copyright (c) 2003 Marcus Overhagen 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <BlockCache.h> 24 #include <Debug.h> 25 #include <string.h> 26 #include <stdlib.h> 27 #include <new> 28 29 #define MAGIC1 0x9183f4d9 30 #define MAGIC2 0xa6b3c87d 31 32 struct BBlockCache::_FreeBlock { 33 DEBUG_ONLY( uint32 magic1; ) 34 _FreeBlock *next; 35 DEBUG_ONLY( uint32 magic2; ) 36 }; 37 38 39 // The requirements set by the BeBook's description of the destructor, 40 // as well as Get() function, allowing the caller to dispose of the 41 // memory, do not allow to allocate one large block to be used as pool. 42 // Thus we need to create multiple small ones. 43 // We maintain a list of free blocks. 44 45 BBlockCache::BBlockCache(uint32 blockCount, 46 size_t blockSize, 47 uint32 allocationType) 48 : fFreeList(0), 49 fBlockSize(blockSize), 50 fFreeBlocks(0), 51 fBlockCount(blockCount), 52 fLocker("some BBlockCache lock"), 53 fAlloc(0), 54 fFree(0) 55 { 56 switch (allocationType) { 57 case B_OBJECT_CACHE: 58 fAlloc = &operator new[]; 59 fFree = &operator delete[]; 60 break; 61 case B_MALLOC_CACHE: 62 default: 63 fAlloc = &malloc; 64 fFree = &free; 65 break; 66 } 67 68 // To properly maintain a list of free buffers, a buffer must be 69 // large enough to contain the _FreeBlock struct that is used. 70 if (blockSize < sizeof(_FreeBlock)) 71 blockSize = sizeof(_FreeBlock); 72 73 // should have at least one block 74 if (blockCount == 0) 75 blockCount = 1; 76 77 // create blocks and put them into the free list 78 while (blockCount--) { 79 _FreeBlock *block = reinterpret_cast<_FreeBlock *>(fAlloc(blockSize)); 80 if (!block) 81 break; 82 fFreeBlocks++; 83 block->next = fFreeList; 84 fFreeList = block; 85 DEBUG_ONLY(block->magic1 = MAGIC1); 86 DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)block->next); 87 } 88 } 89 90 BBlockCache::~BBlockCache() 91 { 92 // walk the free list and deallocate all blocks 93 fLocker.Lock(); 94 while (fFreeList) { 95 ASSERT(fFreeList->magic1 == MAGIC1); 96 ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)fFreeList->next); 97 void *pointer = fFreeList; 98 fFreeList = fFreeList->next; 99 DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 100 fFree(pointer); 101 } 102 fLocker.Unlock(); 103 } 104 105 void * 106 BBlockCache::Get(size_t blockSize) 107 { 108 if (!fLocker.Lock()) 109 return 0; 110 void *pointer; 111 if (blockSize == fBlockSize && fFreeList != 0) { 112 // we can take a block from the list 113 ASSERT(fFreeList->magic1 == MAGIC1); 114 ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)fFreeList->next); 115 pointer = fFreeList; 116 fFreeList = fFreeList->next; 117 fFreeBlocks--; 118 DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 119 } else { 120 if (blockSize < sizeof(_FreeBlock)) 121 blockSize = sizeof(_FreeBlock); 122 pointer = fAlloc(blockSize); 123 DEBUG_ONLY(if (pointer) memset(pointer, 0xCC, sizeof(_FreeBlock))); 124 } 125 fLocker.Unlock(); 126 return pointer; 127 } 128 129 void 130 BBlockCache::Save(void *pointer, size_t blockSize) 131 { 132 if (!fLocker.Lock()) 133 return; 134 if (blockSize == fBlockSize && fFreeBlocks < fBlockCount) { 135 // the block needs to be returned to the cache 136 _FreeBlock *block = reinterpret_cast<_FreeBlock *>(pointer); 137 block->next = fFreeList; 138 fFreeList = block; 139 fFreeBlocks++; 140 DEBUG_ONLY(block->magic1 = MAGIC1); 141 DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)block->next); 142 } else { 143 DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 144 fFree(pointer); 145 } 146 fLocker.Unlock(); 147 } 148 149 void BBlockCache::_ReservedBlockCache1() {} 150 void BBlockCache::_ReservedBlockCache2() {} 151