mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 01:26:34 +00:00
kern: use tree for IoPool regions instead of list
This commit is contained in:
parent
b7846247aa
commit
8eef019e3d
3 changed files with 42 additions and 13 deletions
|
@ -24,10 +24,10 @@ namespace ams::kern {
|
||||||
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
||||||
private:
|
private:
|
||||||
using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_pool_list_node>::ListType;
|
using IoRegionTree = util::IntrusiveRedBlackTreeBaseTraits<KIoRegion>::TreeType<KIoRegion>;
|
||||||
private:
|
private:
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
IoRegionList m_io_region_list;
|
IoRegionTree m_io_region_tree;
|
||||||
ams::svc::IoPoolType m_pool_type;
|
ams::svc::IoPoolType m_pool_type;
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -23,11 +23,30 @@ namespace ams::kern {
|
||||||
class KProcess;
|
class KProcess;
|
||||||
class KIoPool;
|
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);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
|
||||||
private:
|
private:
|
||||||
friend class KProcess;
|
friend class KProcess;
|
||||||
friend class KIoPool;
|
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:
|
private:
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
KIoPool *m_pool;
|
KIoPool *m_pool;
|
||||||
|
@ -38,7 +57,6 @@ namespace ams::kern {
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
bool m_is_mapped;
|
bool m_is_mapped;
|
||||||
util::IntrusiveListNode m_process_list_node;
|
util::IntrusiveListNode m_process_list_node;
|
||||||
util::IntrusiveListNode m_pool_list_node;
|
|
||||||
public:
|
public:
|
||||||
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
|
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 Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
|
||||||
Result Unmap(KProcessAddress address, size_t size);
|
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);
|
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
||||||
ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
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. */
|
/* Check if the address/size falls within any allowable extents. */
|
||||||
for (const auto &extents : g_io_region_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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,12 +106,23 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
/* Check that the desired range isn't already in our pool. */
|
/* 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. */
|
/* Add the region to our pool. */
|
||||||
m_io_region_list.push_back(*new_region);
|
m_io_region_tree.insert(*new_region);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
@ -122,8 +133,8 @@ namespace ams::kern {
|
||||||
/* Lock ourselves. */
|
/* Lock ourselves. */
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
/* Remove the region from our list. */
|
/* Remove the region from our tree. */
|
||||||
m_io_region_list.erase(m_io_region_list.iterator_to(*region));
|
m_io_region_tree.erase(m_io_region_tree.iterator_to(*region));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue