mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-12 16:16:35 +00:00
kern: use tree for IoPool regions instead of list
This commit is contained in:
parent
d5ebf13094
commit
c058376b3b
3 changed files with 42 additions and 13 deletions
|
@ -24,10 +24,10 @@ namespace ams::kern {
|
|||
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
||||
private:
|
||||
using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_pool_list_node>::ListType;
|
||||
using IoRegionTree = util::IntrusiveRedBlackTreeBaseTraits<KIoRegion>::TreeType<KIoRegion>;
|
||||
private:
|
||||
KLightLock m_lock;
|
||||
IoRegionList m_io_region_list;
|
||||
IoRegionTree m_io_region_tree;
|
||||
ams::svc::IoPoolType m_pool_type;
|
||||
bool m_is_initialized;
|
||||
public:
|
||||
|
|
|
@ -23,11 +23,30 @@ namespace ams::kern {
|
|||
class KProcess;
|
||||
class KIoPool;
|
||||
|
||||
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList> {
|
||||
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList>, public util::IntrusiveRedBlackTreeBaseNode<KIoRegion> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
|
||||
private:
|
||||
friend class KProcess;
|
||||
friend class KIoPool;
|
||||
public:
|
||||
using RedBlackKeyType = KPhysicalAddress;
|
||||
|
||||
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; }
|
||||
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KIoRegion &v) { return v.GetAddress(); }
|
||||
|
||||
template<typename T> requires (std::same_as<T, KIoRegion> || std::same_as<T, RedBlackKeyType>)
|
||||
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KIoRegion &rhs) {
|
||||
const RedBlackKeyType lval = GetRedBlackKey(lhs);
|
||||
const RedBlackKeyType rval = GetRedBlackKey(rhs);
|
||||
|
||||
if (lval < rval) {
|
||||
return -1;
|
||||
} else if (lval == rval) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
private:
|
||||
KLightLock m_lock;
|
||||
KIoPool *m_pool;
|
||||
|
@ -38,7 +57,6 @@ namespace ams::kern {
|
|||
bool m_is_initialized;
|
||||
bool m_is_mapped;
|
||||
util::IntrusiveListNode m_process_list_node;
|
||||
util::IntrusiveListNode m_pool_list_node;
|
||||
public:
|
||||
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
|
||||
|
||||
|
@ -51,12 +69,12 @@ namespace ams::kern {
|
|||
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
|
||||
Result Unmap(KProcessAddress address, size_t size);
|
||||
|
||||
bool Overlaps(KPhysicalAddress address, size_t size) const {
|
||||
constexpr bool Overlaps(KPhysicalAddress address, size_t size) const {
|
||||
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
||||
ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
||||
constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace ams::kern {
|
|||
|
||||
/* Check if the address/size falls within any allowable extents. */
|
||||
for (const auto &extents : g_io_region_extents) {
|
||||
if (extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
|
||||
if (extents.size != 0 && extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +106,23 @@ namespace ams::kern {
|
|||
KScopedLightLock lk(m_lock);
|
||||
|
||||
/* Check that the desired range isn't already in our pool. */
|
||||
for (const auto ®ion : m_io_region_list) {
|
||||
R_UNLESS(!region.Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||
{
|
||||
/* Get the lowest region with address >= the new region that's already in our tree. */
|
||||
auto lowest_after = m_io_region_tree.nfind_key(new_region->GetAddress());
|
||||
if (lowest_after != m_io_region_tree.end()) {
|
||||
R_UNLESS(!lowest_after->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||
}
|
||||
|
||||
/* There is no region with address >= the new region already in our tree, but we also need to check */
|
||||
/* for a region with address < the new region already in our tree. */
|
||||
if (lowest_after != m_io_region_tree.begin()) {
|
||||
auto highest_before = --lowest_after;
|
||||
R_UNLESS(!highest_before->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the region to our pool. */
|
||||
m_io_region_list.push_back(*new_region);
|
||||
m_io_region_tree.insert(*new_region);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
@ -122,8 +133,8 @@ namespace ams::kern {
|
|||
/* Lock ourselves. */
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
/* Remove the region from our list. */
|
||||
m_io_region_list.erase(m_io_region_list.iterator_to(*region));
|
||||
/* Remove the region from our tree. */
|
||||
m_io_region_tree.erase(m_io_region_tree.iterator_to(*region));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue