/*
 * Copyright 2011, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */
 
 
#include "TeamMemoryBlockManager.h"
 
#include <new>
 
#include <AutoDeleter.h>
#include <AutoLocker.h>
 
#include "TeamMemoryBlock.h"
 
 
struct TeamMemoryBlockManager::Key {
	target_addr_t address;
 
	Key(target_addr_t address)
		:
		address(address)
	{
	}
 
	uint32 HashValue() const
	{
		return (uint32)address;
	}
 
	bool operator==(const Key& other) const
	{
		return address == other.address;
	}
};
 
 
struct TeamMemoryBlockManager::MemoryBlockEntry : Key {
	TeamMemoryBlock*	block;
	MemoryBlockEntry*	next;
 
	MemoryBlockEntry(TeamMemoryBlock* block)
		:
		Key(block->BaseAddress()),
		block(block)
	{
	}
 
	~MemoryBlockEntry()
	{
	}
};
 
 
struct TeamMemoryBlockManager::MemoryBlockHashDefinition {
	typedef Key					KeyType;
	typedef	MemoryBlockEntry	ValueType;
 
	size_t HashKey(const Key& key) const
	{
		return key.HashValue();
	}
 
	size_t Hash(const MemoryBlockEntry* value) const
	{
		return value->HashValue();
	}
 
	bool Compare(const Key& key, const MemoryBlockEntry* value) const
	{
		return key == *value;
	}
 
	MemoryBlockEntry*& GetLink(MemoryBlockEntry* value) const
	{
		return value->next;
	}
};
 
 
TeamMemoryBlockManager::TeamMemoryBlockManager()
	:
	fActiveBlocks(NULL),
	fDeadBlocks(NULL)
{
}
 
 
TeamMemoryBlockManager::~TeamMemoryBlockManager()
{
	_Cleanup();
}
 
 
status_t
TeamMemoryBlockManager::Init()
{
	status_t result = fLock.InitCheck();
	if (result != B_OK)
		return result;
 
	fActiveBlocks = new(std::nothrow) MemoryBlockTable();
	if (fActiveBlocks == NULL)
		return B_NO_MEMORY;
	ObjectDeleter<MemoryBlockTable> activeDeleter(fActiveBlocks);
	result = fActiveBlocks->Init();
	if (result != B_OK)
		return result;
 
	fDeadBlocks = new(std::nothrow) DeadBlockTable();
	if (fDeadBlocks == NULL)
		return B_NO_MEMORY;
 
	activeDeleter.Detach();
 
	return B_OK;
}
 
 
TeamMemoryBlock*
TeamMemoryBlockManager::GetMemoryBlock(target_addr_t address)
{
	AutoLocker<BLocker> lock(fLock);
 
	address &= ~(B_PAGE_SIZE - 1);
	MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
	if (entry != NULL) {
		if (entry->block->AcquireReference() != 0)
			return entry->block;
 
		// this block already had its last reference released,
		// move it to the dead list and create a new one instead.
		_MarkDeadBlock(address);
	}
 
	TeamMemoryBlockOwner* owner = new(std::nothrow) TeamMemoryBlockOwner(this);
	if (owner == NULL)
		return NULL;
	ObjectDeleter<TeamMemoryBlockOwner> ownerDeleter(owner);
 
	TeamMemoryBlock* block = new(std::nothrow) TeamMemoryBlock(address,
		owner);
	if (block == NULL)
		return NULL;
	ObjectDeleter<TeamMemoryBlock> blockDeleter(block);
 
	entry = new(std::nothrow) MemoryBlockEntry(block);
	if (entry == NULL)
		return NULL;
 
	ownerDeleter.Detach();
	blockDeleter.Detach();
	fActiveBlocks->Insert(entry);
 
	return entry->block;
}
 
 
void
TeamMemoryBlockManager::_Cleanup()
{
	if (fActiveBlocks != NULL) {
		MemoryBlockEntry* entry = fActiveBlocks->Clear(true);
 
		while (entry != NULL) {
			MemoryBlockEntry* next = entry->next;
			delete entry;
			entry = next;
		}
 
		delete fActiveBlocks;
		fActiveBlocks = NULL;
	}
}
 
 
void
TeamMemoryBlockManager::_MarkDeadBlock(target_addr_t address)
{
	MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
	if (entry != NULL) {
		fActiveBlocks->Remove(entry);
		fDeadBlocks->Insert(entry->block);
		delete entry;
	}
}
 
 
void
TeamMemoryBlockManager::_RemoveBlock(target_addr_t address)
{
	AutoLocker<BLocker> lock(fLock);
	MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
	if (entry != NULL) {
		fActiveBlocks->Remove(entry);
		delete entry;
		return;
	}
 
	DeadBlockTable::Iterator iterator = fDeadBlocks->GetIterator();
	while (iterator.HasNext()) {
		TeamMemoryBlock* block = iterator.Next();
		if (block->BaseAddress() == address) {
			fDeadBlocks->Remove(block);
			break;
		}
	}
}
 
 
TeamMemoryBlockOwner::TeamMemoryBlockOwner(TeamMemoryBlockManager* manager)
	:
	fBlockManager(manager)
{
}
 
 
TeamMemoryBlockOwner::~TeamMemoryBlockOwner()
{
}
 
 
void
TeamMemoryBlockOwner::RemoveBlock(TeamMemoryBlock* block)
{
	fBlockManager->_RemoveBlock(block->BaseAddress());
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: next.