1// BlockReferenceManager.cpp
2
3#include <new>
4
5#include "AllocationInfo.h"
6#include "Block.h"
7#include "BlockAllocator.h"		// only for BA_PANIC
8#include "BlockReferenceManager.h"
9#include "Debug.h"
10
11static const int kBlockReferenceTableSize = 128;
12
13// constructor
14BlockReferenceManager::BlockReferenceManager()
15	: fTables(10),
16	  fFreeList(NULL)
17{
18}
19
20// destructor
21BlockReferenceManager::~BlockReferenceManager()
22{
23}
24
25// AllocateReference
26BlockReference *
27BlockReferenceManager::AllocateReference()
28{
29	BlockReference *reference = NULL;
30	if (!fFreeList)
31		_AddTable();
32	if (fFreeList) {
33		reference = fFreeList;
34		fFreeList = *(BlockReference**)fFreeList;
35	}
36	return reference;
37}
38
39// FreeReference
40void
41BlockReferenceManager::FreeReference(BlockReference *reference)
42{
43	if (reference) {
44		*(BlockReference**)reference = fFreeList;
45		fFreeList = reference;
46	}
47}
48
49// CheckReference
50bool
51BlockReferenceManager::CheckReference(BlockReference *reference)
52{
53	if (reference) {
54		uint32 address = (uint32)reference;
55		int32 tableCount = fTables.CountItems();
56		for (int32 i = 0; i < tableCount; i++) {
57			Table *table = &fTables.ItemAt(i);
58			uint32 first = (uint32)table->GetReferences();
59			uint32 last = (uint32)(table->GetReferences() + table->GetSize());
60			if (first <= address && address < last)
61				return true;
62		}
63	}
64	FATAL(("BlockReference %p does not exist!\n", reference));
65	BA_PANIC("BlockReference doesn't exist.");
66	return false;
67}
68
69// GetAllocationInfo
70void
71BlockReferenceManager::GetAllocationInfo(AllocationInfo &info)
72{
73	info.AddListAllocation(fTables.GetCapacity(), sizeof(Table));
74	int32 count = fTables.CountItems();
75	for (int32 i = 0; i < count; i++) {
76		Table &table = fTables.ItemAt(i);
77		info.AddOtherAllocation(table.GetSize() * sizeof(BlockReference));
78	}
79}
80
81// _AddTable
82status_t
83BlockReferenceManager::_AddTable()
84{
85	status_t error = B_OK;
86	// add a new table
87	Table dummy;
88	if (fTables.AddItem(dummy)) {
89		int32 index = fTables.CountItems() - 1;
90		Table &table = fTables.ItemAt(index);
91		error = table.Init(kBlockReferenceTableSize);
92		if (error == B_OK) {
93			// add the references to the free list
94			uint32 count = table.GetSize();
95			BlockReference *references = table.GetReferences();
96			for (uint32 i = 0; i < count; i++) {
97				BlockReference *reference = references + i;
98				*(BlockReference**)reference = fFreeList;
99				fFreeList = reference;
100			}
101		} else
102			fTables.RemoveItem(index);
103	} else
104		SET_ERROR(error, B_NO_MEMORY);
105	return error;
106}
107
108
109// Table
110
111// destructor
112BlockReferenceManager::Table::~Table()
113{
114	if (fReferences)
115		delete[] fReferences;
116}
117
118// Init
119status_t
120BlockReferenceManager::Table::Init(int32 size)
121{
122	status_t error = (size > 0 ? B_OK : B_BAD_VALUE);
123	if (error == B_OK) {
124		fReferences = new(std::nothrow) BlockReference[size];
125		if (fReferences)
126			fSize = size;
127		else
128			SET_ERROR(error, B_NO_MEMORY);
129	}
130	return error;
131}
132
133