xref: /haiku/src/kits/debugger/debug_managers/TeamMemoryBlockManager.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
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 
17 struct 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 
38 struct 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 
55 struct 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 
81 TeamMemoryBlockManager::TeamMemoryBlockManager()
82 	:
83 	fActiveBlocks(NULL),
84 	fDeadBlocks(NULL)
85 {
86 }
87 
88 
89 TeamMemoryBlockManager::~TeamMemoryBlockManager()
90 {
91 	_Cleanup();
92 }
93 
94 
95 status_t
96 TeamMemoryBlockManager::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 
120 TeamMemoryBlock*
121 TeamMemoryBlockManager::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 
159 void
160 TeamMemoryBlockManager::_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 
177 void
178 TeamMemoryBlockManager::_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 
189 void
190 TeamMemoryBlockManager::_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 
211 TeamMemoryBlockOwner::TeamMemoryBlockOwner(TeamMemoryBlockManager* manager)
212 	:
213 	fBlockManager(manager)
214 {
215 }
216 
217 
218 TeamMemoryBlockOwner::~TeamMemoryBlockOwner()
219 {
220 }
221 
222 
223 void
224 TeamMemoryBlockOwner::RemoveBlock(TeamMemoryBlock* block)
225 {
226 	fBlockManager->_RemoveBlock(block->BaseAddress());
227 }
228