1188ad70fSbeveloper /* 2188ad70fSbeveloper * Copyright (c) 2003 Marcus Overhagen 3188ad70fSbeveloper * 4188ad70fSbeveloper * Permission is hereby granted, free of charge, to any person obtaining a 5188ad70fSbeveloper * copy of this software and associated documentation files (the "Software"), 6188ad70fSbeveloper * to deal in the Software without restriction, including without limitation 7188ad70fSbeveloper * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8188ad70fSbeveloper * and/or sell copies of the Software, and to permit persons to whom the 9188ad70fSbeveloper * Software is furnished to do so, subject to the following conditions: 10188ad70fSbeveloper * 11188ad70fSbeveloper * The above copyright notice and this permission notice shall be included in 12188ad70fSbeveloper * all copies or substantial portions of the Software. 13188ad70fSbeveloper * 14188ad70fSbeveloper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15188ad70fSbeveloper * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16188ad70fSbeveloper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17188ad70fSbeveloper * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18188ad70fSbeveloper * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19188ad70fSbeveloper * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20188ad70fSbeveloper * DEALINGS IN THE SOFTWARE. 21188ad70fSbeveloper */ 22e75560e6Sejakowatz 23c109ab72SStefano Ceccherini #include <BlockCache.h> 24188ad70fSbeveloper #include <Debug.h> 25188ad70fSbeveloper #include <string.h> 26*6cb536ddShaydentech #include <stdlib.h> 27188ad70fSbeveloper #include <new> 28c109ab72SStefano Ceccherini 29188ad70fSbeveloper #define MAGIC1 0x9183f4d9 30188ad70fSbeveloper #define MAGIC2 0xa6b3c87d 31e75560e6Sejakowatz 32188ad70fSbeveloper // The requirements set by the BeBook's description of the destructor, 33188ad70fSbeveloper // as well as Get() function, allowing the caller to dispose of the 34188ad70fSbeveloper // memory, do not allow to allocate one large block to be used as pool. 35188ad70fSbeveloper // Thus we need to create multiple small ones. 36188ad70fSbeveloper // We maintain a list of free blocks. If more blocks with a size of blockSize 37188ad70fSbeveloper // are allocated than available, the variable fExcessBlocks is used to avoid 38188ad70fSbeveloper // growing the pool of free buffers 39188ad70fSbeveloper 40ad159f43Sbeveloper BBlockCache::BBlockCache(uint32 blockCount, 41188ad70fSbeveloper size_t blockSize, 42188ad70fSbeveloper uint32 allocationType) 43188ad70fSbeveloper : fFreeList(0), 44188ad70fSbeveloper fBlockSize(blockSize), 45188ad70fSbeveloper fExcessBlocks(0), 46a54e42d7Sbeveloper fLocker("some BBlockCache lock"), 47188ad70fSbeveloper fAlloc(0), 48188ad70fSbeveloper fFree(0) 49e75560e6Sejakowatz { 50188ad70fSbeveloper switch (allocationType) { 51188ad70fSbeveloper case B_OBJECT_CACHE: 52188ad70fSbeveloper fAlloc = &operator new[]; 53188ad70fSbeveloper fFree = &operator delete[]; 54188ad70fSbeveloper break; 55188ad70fSbeveloper case B_MALLOC_CACHE: 56a54e42d7Sbeveloper default: 57188ad70fSbeveloper fAlloc = &malloc; 58188ad70fSbeveloper fFree = &free; 59188ad70fSbeveloper break; 60e75560e6Sejakowatz } 61e75560e6Sejakowatz 62188ad70fSbeveloper // To properly maintain a list of free buffers, a buffer must be 63188ad70fSbeveloper // large enough to contain the _FreeBlock struct that is used. 64188ad70fSbeveloper if (blockSize < sizeof(_FreeBlock)) 65188ad70fSbeveloper blockSize = sizeof(_FreeBlock); 66c109ab72SStefano Ceccherini 67ad159f43Sbeveloper // should have at least one block 68ad159f43Sbeveloper if (blockCount == 0) 69ad159f43Sbeveloper blockCount = 1; 70ad159f43Sbeveloper 71188ad70fSbeveloper // create blocks and put them into the free list 726ecb8ce9Sbeveloper while (blockCount--) { 73188ad70fSbeveloper _FreeBlock *block = reinterpret_cast<_FreeBlock *>(fAlloc(blockSize)); 74188ad70fSbeveloper if (!block) 75188ad70fSbeveloper break; 76188ad70fSbeveloper block->next = fFreeList; 77188ad70fSbeveloper fFreeList = block; 78188ad70fSbeveloper DEBUG_ONLY(block->magic1 = MAGIC1); 79188ad70fSbeveloper DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)block->next); 80e75560e6Sejakowatz } 81e75560e6Sejakowatz } 82e75560e6Sejakowatz 83e75560e6Sejakowatz BBlockCache::~BBlockCache() 84e75560e6Sejakowatz { 85188ad70fSbeveloper // walk the free list and deallocate all blocks 86188ad70fSbeveloper fLocker.Lock(); 87188ad70fSbeveloper while (fFreeList) { 88188ad70fSbeveloper ASSERT(fFreeList->magic1 == MAGIC1); 89188ad70fSbeveloper ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)fFreeList->next); 90188ad70fSbeveloper void *pointer = fFreeList; 91188ad70fSbeveloper fFreeList = fFreeList->next; 92188ad70fSbeveloper DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 93188ad70fSbeveloper fFree(pointer); 94e75560e6Sejakowatz } 95188ad70fSbeveloper fLocker.Unlock(); 96188ad70fSbeveloper } 97c109ab72SStefano Ceccherini 98e75560e6Sejakowatz void * 99188ad70fSbeveloper BBlockCache::Get(size_t blockSize) 100e75560e6Sejakowatz { 101188ad70fSbeveloper if (!fLocker.Lock()) 102188ad70fSbeveloper return 0; 103188ad70fSbeveloper void *pointer; 104188ad70fSbeveloper if (blockSize == fBlockSize && fFreeList != 0) { 105188ad70fSbeveloper // we can take a block from the list 106188ad70fSbeveloper ASSERT(fFreeList->magic1 == MAGIC1); 107188ad70fSbeveloper ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)fFreeList->next); 108188ad70fSbeveloper pointer = fFreeList; 109188ad70fSbeveloper fFreeList = fFreeList->next; 110188ad70fSbeveloper DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 111188ad70fSbeveloper } else { 112188ad70fSbeveloper // we need to allocate a new block 113188ad70fSbeveloper if (blockSize == fBlockSize) { 114188ad70fSbeveloper // we now have one more block than wanted 115188ad70fSbeveloper fExcessBlocks++; 116e75560e6Sejakowatz } 117188ad70fSbeveloper if (blockSize < sizeof(_FreeBlock)) 118188ad70fSbeveloper blockSize = sizeof(_FreeBlock); 119188ad70fSbeveloper pointer = fAlloc(blockSize); 120188ad70fSbeveloper DEBUG_ONLY(if (pointer) memset(pointer, 0xCC, sizeof(_FreeBlock))); 121e75560e6Sejakowatz } 122188ad70fSbeveloper fLocker.Unlock(); 123188ad70fSbeveloper return pointer; 124e75560e6Sejakowatz } 125c109ab72SStefano Ceccherini 126e75560e6Sejakowatz void 127188ad70fSbeveloper BBlockCache::Save(void *pointer, size_t blockSize) 128e75560e6Sejakowatz { 129188ad70fSbeveloper if (!fLocker.Lock()) 130e75560e6Sejakowatz return; 131188ad70fSbeveloper if (blockSize == fBlockSize && fExcessBlocks <= 0) { 132188ad70fSbeveloper // the block needs to be returned to the cache 133188ad70fSbeveloper _FreeBlock *block = reinterpret_cast<_FreeBlock *>(pointer); 134188ad70fSbeveloper block->next = fFreeList; 135188ad70fSbeveloper fFreeList = block; 136188ad70fSbeveloper DEBUG_ONLY(block->magic1 = MAGIC1); 137188ad70fSbeveloper DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)block->next); 138188ad70fSbeveloper } else { 139188ad70fSbeveloper // the block needs to be deallocated 140188ad70fSbeveloper if (blockSize == fBlockSize) { 141188ad70fSbeveloper fExcessBlocks--; 142188ad70fSbeveloper ASSERT(fExcessBlocks >= 0); 143e75560e6Sejakowatz } 144188ad70fSbeveloper DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock))); 145188ad70fSbeveloper fFree(pointer); 146e75560e6Sejakowatz } 147188ad70fSbeveloper fLocker.Unlock(); 148e75560e6Sejakowatz } 149b93355abSbeveloper 150b93355abSbeveloper void BBlockCache::_ReservedBlockCache1() {} 151b93355abSbeveloper void BBlockCache::_ReservedBlockCache2() {} 152