|
|
|
@ -0,0 +1,55 @@ |
|
|
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later |
|
|
|
|
|
|
|
#pragma once |
|
|
|
|
|
|
|
#include <mutex> |
|
|
|
#include <boost/icl/interval_set.hpp> |
|
|
|
|
|
|
|
namespace Common { |
|
|
|
|
|
|
|
class FreeRegionManager { |
|
|
|
public: |
|
|
|
explicit FreeRegionManager() = default; |
|
|
|
~FreeRegionManager() = default; |
|
|
|
|
|
|
|
void SetAddressSpace(void* start, size_t size) { |
|
|
|
this->FreeBlock(start, size); |
|
|
|
} |
|
|
|
|
|
|
|
std::pair<void*, size_t> FreeBlock(void* block_ptr, size_t size) { |
|
|
|
std::scoped_lock lk(m_mutex); |
|
|
|
|
|
|
|
// Check to see if we are adjacent to any regions. |
|
|
|
auto start_address = reinterpret_cast<uintptr_t>(block_ptr); |
|
|
|
auto end_address = start_address + size; |
|
|
|
auto it = m_free_regions.find({start_address - 1, end_address + 1}); |
|
|
|
|
|
|
|
// If we are, join with them, ensuring we stay in bounds. |
|
|
|
if (it != m_free_regions.end()) { |
|
|
|
start_address = std::min(start_address, it->lower()); |
|
|
|
end_address = std::max(end_address, it->upper()); |
|
|
|
} |
|
|
|
|
|
|
|
// Free the relevant region. |
|
|
|
m_free_regions.insert({start_address, end_address}); |
|
|
|
|
|
|
|
// Return the adjusted pointers. |
|
|
|
block_ptr = reinterpret_cast<void*>(start_address); |
|
|
|
size = end_address - start_address; |
|
|
|
return {block_ptr, size}; |
|
|
|
} |
|
|
|
|
|
|
|
void AllocateBlock(void* block_ptr, size_t size) { |
|
|
|
std::scoped_lock lk(m_mutex); |
|
|
|
|
|
|
|
auto address = reinterpret_cast<uintptr_t>(block_ptr); |
|
|
|
m_free_regions.subtract({address, address + size}); |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
std::mutex m_mutex; |
|
|
|
boost::icl::interval_set<uintptr_t> m_free_regions; |
|
|
|
}; |
|
|
|
|
|
|
|
} // namespace Common |