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 30 #define MAGIC1 0x9183f4d9 31 #define MAGIC2 0xa6b3c87d 32 33 34 struct BBlockCache::_FreeBlock { 35 DEBUG_ONLY( uint32 magic1; ) 36 _FreeBlock *next; 37 DEBUG_ONLY( uint32 magic2; ) 38 }; 39 40 41 // The requirements set by the BeBook's description of the destructor, 42 // as well as Get() function, allowing the caller to dispose of the 43 // memory, do not allow to allocate one large block to be used as pool. 44 // Thus we need to create multiple small ones. 45 // We maintain a list of free blocks. 46 47 BBlockCache::BBlockCache(uint32 blockCount, size_t blockSize, 48 uint32 allocationType) 49 : 50 fFreeList(0), 51 fBlockSize(blockSize), 52 fFreeBlocks(0), 53 fBlockCount(blockCount), 54 fLocker("some BBlockCache lock"), 55 fAlloc(0), 56 fFree(0) 57 { 58 switch (allocationType) { 59 case B_OBJECT_CACHE: 60 fAlloc = &operator new[]; 61 fFree = &operator delete[]; 62 break; 63 case B_MALLOC_CACHE: 64 default: 65 fAlloc = &malloc; 66 fFree = &free; 67 break; 68 } 69 70 // To properly maintain a list of free buffers, a buffer must be 71 // large enough to contain the _FreeBlock struct that is used. 72 if (blockSize < sizeof(_FreeBlock)) 73 blockSize = sizeof(_FreeBlock); 74 75 // should have at least one block 76 if (blockCount == 0) 77 blockCount = 1; 78 79 // create blocks and put them into the free list 80 while (blockCount--) { 81 _FreeBlock *block = reinterpret_cast<_FreeBlock *>(fAlloc(blockSize)); 82 if (!block) 83 break; 84 fFreeBlocks++; 85 block->next = fFreeList; 86 fFreeList = block; 87 DEBUG_ONLY(block->magic1 = MAGIC1); 88 DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)(addr_t)block->next); 89 } 90 } 91 92 93 BBlockCache::~BBlockCache() 94 { 95 // walk the free list and deallocate all blocks 96 fLocker.Lock(); 97 while (fFreeList) { 98 ASSERT(fFreeList->magic1 == MAGIC1); 99 ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)(addr_t)fFreeList->next); 100 void *pointer = fFreeList; 101 fFreeList = fFreeList->next; 102 DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 103 fFree(pointer); 104 } 105 fLocker.Unlock(); 106 } 107 108 109 void * 110 BBlockCache::Get(size_t blockSize) 111 { 112 if (!fLocker.Lock()) 113 return 0; 114 void *pointer; 115 if (blockSize == fBlockSize && fFreeList != 0) { 116 // we can take a block from the list 117 ASSERT(fFreeList->magic1 == MAGIC1); 118 ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)(addr_t)fFreeList->next); 119 pointer = fFreeList; 120 fFreeList = fFreeList->next; 121 fFreeBlocks--; 122 DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 123 } else { 124 if (blockSize < sizeof(_FreeBlock)) 125 blockSize = sizeof(_FreeBlock); 126 pointer = fAlloc(blockSize); 127 DEBUG_ONLY(if (pointer) memset(pointer, 0xCC, sizeof(_FreeBlock))); 128 } 129 fLocker.Unlock(); 130 return pointer; 131 } 132 133 134 void 135 BBlockCache::Save(void *pointer, size_t blockSize) 136 { 137 if (!fLocker.Lock()) 138 return; 139 if (blockSize == fBlockSize && fFreeBlocks < fBlockCount) { 140 // the block needs to be returned to the cache 141 _FreeBlock *block = reinterpret_cast<_FreeBlock *>(pointer); 142 block->next = fFreeList; 143 fFreeList = block; 144 fFreeBlocks++; 145 DEBUG_ONLY(block->magic1 = MAGIC1); 146 DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)(addr_t)block->next); 147 } else { 148 DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 149 fFree(pointer); 150 } 151 fLocker.Unlock(); 152 } 153 154 155 void BBlockCache::_ReservedBlockCache1() {} 156 void BBlockCache::_ReservedBlockCache2() {} 157