1/*
2 * Copyright 2011, Rene Gollent, rene@gollent.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "TeamMemoryBlockManager.h"
8
9#include <new>
10
11#include <AutoDeleter.h>
12#include <AutoLocker.h>
13
14#include "TeamMemoryBlock.h"
15
16
17struct TeamMemoryBlockManager::Key {
18	target_addr_t address;
19
20	Key(target_addr_t address)
21		:
22		address(address)
23	{
24	}
25
26	uint32 HashValue() const
27	{
28		return (uint32)address;
29	}
30
31	bool operator==(const Key& other) const
32	{
33		return address == other.address;
34	}
35};
36
37
38struct TeamMemoryBlockManager::MemoryBlockEntry : Key {
39	TeamMemoryBlock*	block;
40	MemoryBlockEntry*	next;
41
42	MemoryBlockEntry(TeamMemoryBlock* block)
43		:
44		Key(block->BaseAddress()),
45		block(block)
46	{
47	}
48
49	~MemoryBlockEntry()
50	{
51	}
52};
53
54
55struct TeamMemoryBlockManager::MemoryBlockHashDefinition {
56	typedef Key					KeyType;
57	typedef	MemoryBlockEntry	ValueType;
58
59	size_t HashKey(const Key& key) const
60	{
61		return key.HashValue();
62	}
63
64	size_t Hash(const MemoryBlockEntry* value) const
65	{
66		return value->HashValue();
67	}
68
69	bool Compare(const Key& key, const MemoryBlockEntry* value) const
70	{
71		return key == *value;
72	}
73
74	MemoryBlockEntry*& GetLink(MemoryBlockEntry* value) const
75	{
76		return value->next;
77	}
78};
79
80
81TeamMemoryBlockManager::TeamMemoryBlockManager()
82	:
83	fActiveBlocks(NULL),
84	fDeadBlocks(NULL)
85{
86}
87
88
89TeamMemoryBlockManager::~TeamMemoryBlockManager()
90{
91	_Cleanup();
92}
93
94
95status_t
96TeamMemoryBlockManager::Init()
97{
98	status_t result = fLock.InitCheck();
99	if (result != B_OK)
100		return result;
101
102	fActiveBlocks = new(std::nothrow) MemoryBlockTable();
103	if (fActiveBlocks == NULL)
104		return B_NO_MEMORY;
105	ObjectDeleter<MemoryBlockTable> activeDeleter(fActiveBlocks);
106	result = fActiveBlocks->Init();
107	if (result != B_OK)
108		return result;
109
110	fDeadBlocks = new(std::nothrow) DeadBlockTable();
111	if (fDeadBlocks == NULL)
112		return B_NO_MEMORY;
113
114	activeDeleter.Detach();
115
116	return B_OK;
117}
118
119
120TeamMemoryBlock*
121TeamMemoryBlockManager::GetMemoryBlock(target_addr_t address)
122{
123	AutoLocker<BLocker> lock(fLock);
124
125	address &= ~(B_PAGE_SIZE - 1);
126	MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
127	if (entry != NULL) {
128		if (entry->block->AcquireReference() != 0)
129			return entry->block;
130
131		// this block already had its last reference released,
132		// move it to the dead list and create a new one instead.
133		_MarkDeadBlock(address);
134	}
135
136	TeamMemoryBlockOwner* owner = new(std::nothrow) TeamMemoryBlockOwner(this);
137	if (owner == NULL)
138		return NULL;
139	ObjectDeleter<TeamMemoryBlockOwner> ownerDeleter(owner);
140
141	TeamMemoryBlock* block = new(std::nothrow) TeamMemoryBlock(address,
142		owner);
143	if (block == NULL)
144		return NULL;
145	ObjectDeleter<TeamMemoryBlock> blockDeleter(block);
146
147	entry = new(std::nothrow) MemoryBlockEntry(block);
148	if (entry == NULL)
149		return NULL;
150
151	ownerDeleter.Detach();
152	blockDeleter.Detach();
153	fActiveBlocks->Insert(entry);
154
155	return entry->block;
156}
157
158
159void
160TeamMemoryBlockManager::_Cleanup()
161{
162	if (fActiveBlocks != NULL) {
163		MemoryBlockEntry* entry = fActiveBlocks->Clear(true);
164
165		while (entry != NULL) {
166			MemoryBlockEntry* next = entry->next;
167			delete entry;
168			entry = next;
169		}
170
171		delete fActiveBlocks;
172		fActiveBlocks = NULL;
173	}
174}
175
176
177void
178TeamMemoryBlockManager::_MarkDeadBlock(target_addr_t address)
179{
180	MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
181	if (entry != NULL) {
182		fActiveBlocks->Remove(entry);
183		fDeadBlocks->Insert(entry->block);
184		delete entry;
185	}
186}
187
188
189void
190TeamMemoryBlockManager::_RemoveBlock(target_addr_t address)
191{
192	AutoLocker<BLocker> lock(fLock);
193	MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
194	if (entry != NULL) {
195		fActiveBlocks->Remove(entry);
196		delete entry;
197		return;
198	}
199
200	DeadBlockTable::Iterator iterator = fDeadBlocks->GetIterator();
201	while (iterator.HasNext()) {
202		TeamMemoryBlock* block = iterator.Next();
203		if (block->BaseAddress() == address) {
204			fDeadBlocks->Remove(block);
205			break;
206		}
207	}
208}
209
210
211TeamMemoryBlockOwner::TeamMemoryBlockOwner(TeamMemoryBlockManager* manager)
212	:
213	fBlockManager(manager)
214{
215}
216
217
218TeamMemoryBlockOwner::~TeamMemoryBlockOwner()
219{
220}
221
222
223void
224TeamMemoryBlockOwner::RemoveBlock(TeamMemoryBlock* block)
225{
226	fBlockManager->_RemoveBlock(block->BaseAddress());
227}
228