1188ad70fSbeveloper/*
2188ad70fSbeveloper * Copyright (c) 2003 Marcus Overhagen
3e01de522SMichael Lotz *
4e01de522SMichael Lotz * Permission is hereby granted, free of charge, to any person obtaining a
5e01de522SMichael Lotz * copy of this software and associated documentation files (the "Software"),
6e01de522SMichael Lotz * to deal in the Software without restriction, including without limitation
7e01de522SMichael Lotz * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e01de522SMichael Lotz * 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:
10e01de522SMichael Lotz *
11e01de522SMichael Lotz * The above copyright notice and this permission notice shall be included in
12188ad70fSbeveloper * all copies or substantial portions of the Software.
13e01de522SMichael Lotz *
14e01de522SMichael Lotz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e01de522SMichael Lotz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e01de522SMichael Lotz * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17e01de522SMichael Lotz * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18e01de522SMichael Lotz * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19e01de522SMichael Lotz * 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>
266cb536ddShaydentech#include <stdlib.h>
27188ad70fSbeveloper#include <new>
28188ad70fSbeveloper
29e01de522SMichael Lotz
30188ad70fSbeveloper#define MAGIC1		0x9183f4d9
31188ad70fSbeveloper#define MAGIC2		0xa6b3c87d
32188ad70fSbeveloper
33e01de522SMichael Lotz
34340eed61SIngo Weinholdstruct BBlockCache::_FreeBlock {
35340eed61SIngo Weinhold	DEBUG_ONLY(	uint32		magic1;	)
36340eed61SIngo Weinhold				_FreeBlock *next;
37340eed61SIngo Weinhold	DEBUG_ONLY(	uint32		magic2;	)
38340eed61SIngo Weinhold};
39340eed61SIngo Weinhold
40340eed61SIngo Weinhold
41188ad70fSbeveloper// The requirements set by the BeBook's description of the destructor,
42188ad70fSbeveloper// as well as Get() function, allowing the caller to dispose of the
43188ad70fSbeveloper// memory, do not allow to allocate one large block to be used as pool.
44188ad70fSbeveloper// Thus we need to create multiple small ones.
45369eef13SIngo Weinhold// We maintain a list of free blocks.
46188ad70fSbeveloper
47e01de522SMichael LotzBBlockCache::BBlockCache(uint32 blockCount, size_t blockSize,
48e01de522SMichael Lotz	uint32 allocationType)
49e01de522SMichael Lotz	:
50e01de522SMichael Lotz	fFreeList(0),
51e01de522SMichael Lotz	fBlockSize(blockSize),
52e01de522SMichael Lotz	fFreeBlocks(0),
53e01de522SMichael Lotz	fBlockCount(blockCount),
54a54e42d7Sbeveloper	fLocker("some BBlockCache lock"),
55188ad70fSbeveloper	fAlloc(0),
56e01de522SMichael Lotz	fFree(0)
57e75560e6Sejakowatz{
58188ad70fSbeveloper	switch (allocationType) {
59188ad70fSbeveloper		case B_OBJECT_CACHE:
60188ad70fSbeveloper			fAlloc = &operator new[];
61188ad70fSbeveloper			fFree = &operator delete[];
62188ad70fSbeveloper			break;
63188ad70fSbeveloper		case B_MALLOC_CACHE:
64a54e42d7Sbeveloper		default:
65188ad70fSbeveloper			fAlloc = &malloc;
66188ad70fSbeveloper			fFree = &free;
67188ad70fSbeveloper			break;
68188ad70fSbeveloper	}
69e75560e6Sejakowatz
70188ad70fSbeveloper	// To properly maintain a list of free buffers, a buffer must be
71188ad70fSbeveloper	// large enough to contain the _FreeBlock struct that is used.
72188ad70fSbeveloper	if (blockSize < sizeof(_FreeBlock))
73188ad70fSbeveloper		blockSize = sizeof(_FreeBlock);
74e01de522SMichael Lotz
75ad159f43Sbeveloper	// should have at least one block
76ad159f43Sbeveloper	if (blockCount == 0)
77ad159f43Sbeveloper		blockCount = 1;
78e01de522SMichael Lotz
79188ad70fSbeveloper	// create blocks and put them into the free list
806ecb8ce9Sbeveloper	while (blockCount--) {
81188ad70fSbeveloper		_FreeBlock *block = reinterpret_cast<_FreeBlock *>(fAlloc(blockSize));
82188ad70fSbeveloper		if (!block)
83188ad70fSbeveloper			break;
8416ce9822Sbeveloper		fFreeBlocks++;
85188ad70fSbeveloper		block->next = fFreeList;
86188ad70fSbeveloper		fFreeList = block;
87188ad70fSbeveloper		DEBUG_ONLY(block->magic1 = MAGIC1);
884ad0585eSUrias McCullough		DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)(addr_t)block->next);
89e75560e6Sejakowatz	}
90e75560e6Sejakowatz}
91e75560e6Sejakowatz
92e01de522SMichael Lotz
93e75560e6SejakowatzBBlockCache::~BBlockCache()
94e75560e6Sejakowatz{
95188ad70fSbeveloper	// walk the free list and deallocate all blocks
96188ad70fSbeveloper	fLocker.Lock();
97188ad70fSbeveloper	while (fFreeList) {
98188ad70fSbeveloper		ASSERT(fFreeList->magic1 == MAGIC1);
994ad0585eSUrias McCullough		ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)(addr_t)fFreeList->next);
100188ad70fSbeveloper		void *pointer = fFreeList;
101188ad70fSbeveloper		fFreeList = fFreeList->next;
102188ad70fSbeveloper		DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock)));
103188ad70fSbeveloper		fFree(pointer);
104188ad70fSbeveloper	}
105188ad70fSbeveloper	fLocker.Unlock();
106e75560e6Sejakowatz}
107e75560e6Sejakowatz
108e01de522SMichael Lotz
109e75560e6Sejakowatzvoid *
110188ad70fSbeveloperBBlockCache::Get(size_t blockSize)
111e75560e6Sejakowatz{
112188ad70fSbeveloper	if (!fLocker.Lock())
113188ad70fSbeveloper		return 0;
114188ad70fSbeveloper	void *pointer;
115188ad70fSbeveloper	if (blockSize == fBlockSize && fFreeList != 0) {
116188ad70fSbeveloper		// we can take a block from the list
117188ad70fSbeveloper		ASSERT(fFreeList->magic1 == MAGIC1);
1184ad0585eSUrias McCullough		ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)(addr_t)fFreeList->next);
119188ad70fSbeveloper		pointer = fFreeList;
120188ad70fSbeveloper		fFreeList = fFreeList->next;
121369eef13SIngo Weinhold		fFreeBlocks--;
122188ad70fSbeveloper		DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock)));
123188ad70fSbeveloper	} else {
124188ad70fSbeveloper		if (blockSize < sizeof(_FreeBlock))
125188ad70fSbeveloper			blockSize = sizeof(_FreeBlock);
126188ad70fSbeveloper		pointer = fAlloc(blockSize);
127188ad70fSbeveloper		DEBUG_ONLY(if (pointer) memset(pointer, 0xCC, sizeof(_FreeBlock)));
128e75560e6Sejakowatz	}
129188ad70fSbeveloper	fLocker.Unlock();
130188ad70fSbeveloper	return pointer;
131e75560e6Sejakowatz}
132e75560e6Sejakowatz
133e01de522SMichael Lotz
134188ad70fSbevelopervoid
135188ad70fSbeveloperBBlockCache::Save(void *pointer, size_t blockSize)
136e75560e6Sejakowatz{
137188ad70fSbeveloper	if (!fLocker.Lock())
138e75560e6Sejakowatz		return;
139369eef13SIngo Weinhold	if (blockSize == fBlockSize && fFreeBlocks < fBlockCount) {
140188ad70fSbeveloper		// the block needs to be returned to the cache
141188ad70fSbeveloper		_FreeBlock *block = reinterpret_cast<_FreeBlock *>(pointer);
142188ad70fSbeveloper		block->next = fFreeList;
143188ad70fSbeveloper		fFreeList = block;
144369eef13SIngo Weinhold		fFreeBlocks++;
145188ad70fSbeveloper		DEBUG_ONLY(block->magic1 = MAGIC1);
1464ad0585eSUrias McCullough		DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)(addr_t)block->next);
147188ad70fSbeveloper	} else {
148188ad70fSbeveloper		DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock)));
149188ad70fSbeveloper		fFree(pointer);
150e75560e6Sejakowatz	}
151188ad70fSbeveloper	fLocker.Unlock();
152e75560e6Sejakowatz}
153b93355abSbeveloper
154e01de522SMichael Lotz
155b93355abSbevelopervoid BBlockCache::_ReservedBlockCache1() {}
156b93355abSbevelopervoid BBlockCache::_ReservedBlockCache2() {}
157