xref: /haiku/src/kits/support/BlockCache.cpp (revision e01de52283efe0bd8fa107bd493df302c070204e)
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 
BBlockCache(uint32 blockCount,size_t blockSize,uint32 allocationType)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 
~BBlockCache()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 *
Get(size_t blockSize)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
Save(void * pointer,size_t blockSize)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 
_ReservedBlockCache1()155 void BBlockCache::_ReservedBlockCache1() {}
_ReservedBlockCache2()156 void BBlockCache::_ReservedBlockCache2() {}
157