xref: /haiku/src/kits/support/BlockCache.cpp (revision 6cb536dd5b3bc9af928849111f8ddabbee4ee251)
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