diff options
| -rw-r--r-- | src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp | 21 | ||||
| -rw-r--r-- | src/core/hle/kernel/init/init_slab_setup.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_address_arbiter.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_address_space_info.cpp | 79 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_condition_variable.cpp | 50 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_lock.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler_lock.h | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 271 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 175 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 93 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 67 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc_types.h | 1 |
13 files changed, 510 insertions, 288 deletions
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp index c10b7bf30..5b8a248c8 100644 --- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp +++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp | |||
| @@ -14,9 +14,12 @@ namespace Kernel::Board::Nintendo::Nx { | |||
| 14 | 14 | ||
| 15 | namespace impl { | 15 | namespace impl { |
| 16 | 16 | ||
| 17 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024; | 17 | using namespace Common::Literals; |
| 18 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024; | 18 | |
| 19 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024; | 19 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2280 * 4_KiB; |
| 20 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeViFatal = 0x200 * 4_KiB; | ||
| 21 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x704 * 4_KiB; | ||
| 22 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4_KiB; | ||
| 20 | 23 | ||
| 21 | } // namespace impl | 24 | } // namespace impl |
| 22 | 25 | ||
| @@ -24,6 +27,9 @@ constexpr const std::size_t RequiredNonSecureSystemMemorySize = | |||
| 24 | impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices + | 27 | impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices + |
| 25 | impl::RequiredNonSecureSystemMemorySizeMisc; | 28 | impl::RequiredNonSecureSystemMemorySizeMisc; |
| 26 | 29 | ||
| 30 | constexpr const std::size_t RequiredNonSecureSystemMemorySizeWithFatal = | ||
| 31 | RequiredNonSecureSystemMemorySize + impl::RequiredNonSecureSystemMemorySizeViFatal; | ||
| 32 | |||
| 27 | namespace { | 33 | namespace { |
| 28 | 34 | ||
| 29 | using namespace Common::Literals; | 35 | using namespace Common::Literals; |
| @@ -120,10 +126,13 @@ size_t KSystemControl::Init::GetAppletPoolSize() { | |||
| 120 | 126 | ||
| 121 | size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() { | 127 | size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() { |
| 122 | // Verify that our minimum is at least as large as Nintendo's. | 128 | // Verify that our minimum is at least as large as Nintendo's. |
| 123 | constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize; | 129 | constexpr size_t MinimumSizeWithFatal = RequiredNonSecureSystemMemorySizeWithFatal; |
| 124 | static_assert(MinimumSize >= 0x29C8000); | 130 | static_assert(MinimumSizeWithFatal >= 0x2C04000); |
| 131 | |||
| 132 | constexpr size_t MinimumSizeWithoutFatal = RequiredNonSecureSystemMemorySize; | ||
| 133 | static_assert(MinimumSizeWithoutFatal >= 0x2A00000); | ||
| 125 | 134 | ||
| 126 | return MinimumSize; | 135 | return MinimumSizeWithFatal; |
| 127 | } | 136 | } |
| 128 | 137 | ||
| 129 | namespace { | 138 | namespace { |
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index abdb5639f..5e4090e2b 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp | |||
| @@ -33,6 +33,9 @@ | |||
| 33 | 33 | ||
| 34 | namespace Kernel::Init { | 34 | namespace Kernel::Init { |
| 35 | 35 | ||
| 36 | // For macro convenience. | ||
| 37 | using KThreadLockInfo = KThread::LockWithPriorityInheritanceInfo; | ||
| 38 | |||
| 36 | #define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS | 39 | #define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS |
| 37 | 40 | ||
| 38 | #define FOREACH_SLAB_TYPE(HANDLER, ...) \ | 41 | #define FOREACH_SLAB_TYPE(HANDLER, ...) \ |
| @@ -54,7 +57,8 @@ namespace Kernel::Init { | |||
| 54 | HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \ | 57 | HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \ |
| 55 | HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ | 58 | HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ |
| 56 | HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ | 59 | HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ |
| 57 | HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) | 60 | HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \ |
| 61 | HANDLER(KThreadLockInfo, (SLAB_COUNT(KThread)), ##__VA_ARGS__) | ||
| 58 | 62 | ||
| 59 | namespace { | 63 | namespace { |
| 60 | 64 | ||
| @@ -131,7 +135,7 @@ VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAd | |||
| 131 | } | 135 | } |
| 132 | 136 | ||
| 133 | size_t CalculateSlabHeapGapSize() { | 137 | size_t CalculateSlabHeapGapSize() { |
| 134 | constexpr size_t KernelSlabHeapGapSize = 2_MiB - 320_KiB; | 138 | constexpr size_t KernelSlabHeapGapSize = 2_MiB - 356_KiB; |
| 135 | static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax); | 139 | static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax); |
| 136 | return KernelSlabHeapGapSize; | 140 | return KernelSlabHeapGapSize; |
| 137 | } | 141 | } |
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index a442a3b98..fb86451ea 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -29,7 +29,9 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu | |||
| 29 | auto& monitor = system.Monitor(); | 29 | auto& monitor = system.Monitor(); |
| 30 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); | 30 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); |
| 31 | 31 | ||
| 32 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. | 32 | // NOTE: If scheduler lock is not held here, interrupt disable is required. |
| 33 | // KScopedInterruptDisable di; | ||
| 34 | |||
| 33 | // TODO(bunnei): We should call CanAccessAtomic(..) here. | 35 | // TODO(bunnei): We should call CanAccessAtomic(..) here. |
| 34 | 36 | ||
| 35 | // Load the value from the address. | 37 | // Load the value from the address. |
| @@ -59,7 +61,9 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 | |||
| 59 | auto& monitor = system.Monitor(); | 61 | auto& monitor = system.Monitor(); |
| 60 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); | 62 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); |
| 61 | 63 | ||
| 62 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. | 64 | // NOTE: If scheduler lock is not held here, interrupt disable is required. |
| 65 | // KScopedInterruptDisable di; | ||
| 66 | |||
| 63 | // TODO(bunnei): We should call CanAccessAtomic(..) here. | 67 | // TODO(bunnei): We should call CanAccessAtomic(..) here. |
| 64 | 68 | ||
| 65 | // Load the value from the address. | 69 | // Load the value from the address. |
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp index 3e612a207..97972ebae 100644 --- a/src/core/hle/kernel/k_address_space_info.cpp +++ b/src/core/hle/kernel/k_address_space_info.cpp | |||
| @@ -23,86 +23,33 @@ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{ | |||
| 23 | { .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, }, | 23 | { .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, }, |
| 24 | { .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, }, | 24 | { .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, }, |
| 25 | { .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, }, | 25 | { .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, }, |
| 26 | { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, }, | 26 | { .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, }, |
| 27 | { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, }, | 27 | { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, }, |
| 28 | { .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, }, | 28 | { .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, }, |
| 29 | { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall }, | 29 | { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall }, |
| 30 | { .bit_width = 39, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, }, | 30 | { .bit_width = 39, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, }, |
| 31 | { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, }, | 31 | { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, }, |
| 32 | { .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, }, | 32 | { .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, }, |
| 33 | }}; | 33 | }}; |
| 34 | // clang-format on | 34 | // clang-format on |
| 35 | 35 | ||
| 36 | constexpr bool IsAllowedIndexForAddress(std::size_t index) { | 36 | const KAddressSpaceInfo& GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) { |
| 37 | return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Size_Invalid; | 37 | for (auto& info : AddressSpaceInfos) { |
| 38 | } | 38 | if (info.bit_width == width && info.type == type) { |
| 39 | 39 | return info; | |
| 40 | using IndexArray = | 40 | } |
| 41 | std::array<std::size_t, static_cast<std::size_t>(KAddressSpaceInfo::Type::Count)>; | 41 | } |
| 42 | 42 | UNREACHABLE_MSG("Could not find AddressSpaceInfo"); | |
| 43 | constexpr IndexArray AddressSpaceIndices32Bit{ | ||
| 44 | 0, 1, 0, 2, 0, 3, | ||
| 45 | }; | ||
| 46 | |||
| 47 | constexpr IndexArray AddressSpaceIndices36Bit{ | ||
| 48 | 4, 5, 4, 6, 4, 7, | ||
| 49 | }; | ||
| 50 | |||
| 51 | constexpr IndexArray AddressSpaceIndices39Bit{ | ||
| 52 | 9, 8, 8, 10, 12, 11, | ||
| 53 | }; | ||
| 54 | |||
| 55 | constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) { | ||
| 56 | return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit && | ||
| 57 | type != KAddressSpaceInfo::Type::Stack; | ||
| 58 | } | ||
| 59 | |||
| 60 | constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) { | ||
| 61 | return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit && | ||
| 62 | type != KAddressSpaceInfo::Type::Stack; | ||
| 63 | } | ||
| 64 | |||
| 65 | constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) { | ||
| 66 | return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::MapLarge; | ||
| 67 | } | 43 | } |
| 68 | 44 | ||
| 69 | } // namespace | 45 | } // namespace |
| 70 | 46 | ||
| 71 | u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { | 47 | uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) { |
| 72 | const std::size_t index{static_cast<std::size_t>(type)}; | 48 | return GetAddressSpaceInfo(width, type).address; |
| 73 | switch (width) { | ||
| 74 | case 32: | ||
| 75 | ASSERT(IsAllowed32BitType(type)); | ||
| 76 | ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index])); | ||
| 77 | return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address; | ||
| 78 | case 36: | ||
| 79 | ASSERT(IsAllowed36BitType(type)); | ||
| 80 | ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index])); | ||
| 81 | return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address; | ||
| 82 | case 39: | ||
| 83 | ASSERT(IsAllowed39BitType(type)); | ||
| 84 | ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); | ||
| 85 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; | ||
| 86 | } | ||
| 87 | ASSERT(false); | ||
| 88 | return 0; | ||
| 89 | } | 49 | } |
| 90 | 50 | ||
| 91 | std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { | 51 | size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) { |
| 92 | const std::size_t index{static_cast<std::size_t>(type)}; | 52 | return GetAddressSpaceInfo(width, type).size; |
| 93 | switch (width) { | ||
| 94 | case 32: | ||
| 95 | ASSERT(IsAllowed32BitType(type)); | ||
| 96 | return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size; | ||
| 97 | case 36: | ||
| 98 | ASSERT(IsAllowed36BitType(type)); | ||
| 99 | return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size; | ||
| 100 | case 39: | ||
| 101 | ASSERT(IsAllowed39BitType(type)); | ||
| 102 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; | ||
| 103 | } | ||
| 104 | ASSERT(false); | ||
| 105 | return 0; | ||
| 106 | } | 53 | } |
| 107 | 54 | ||
| 108 | } // namespace Kernel | 55 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 3f0be1c3f..f40cf92b1 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp | |||
| @@ -111,36 +111,36 @@ Result KConditionVariable::SignalToAddress(VAddr addr) { | |||
| 111 | KScopedSchedulerLock sl(kernel); | 111 | KScopedSchedulerLock sl(kernel); |
| 112 | 112 | ||
| 113 | // Remove waiter thread. | 113 | // Remove waiter thread. |
| 114 | s32 num_waiters{}; | 114 | bool has_waiters{}; |
| 115 | KThread* next_owner_thread = | 115 | KThread* const next_owner_thread = |
| 116 | owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); | 116 | owner_thread->RemoveUserWaiterByKey(std::addressof(has_waiters), addr); |
| 117 | 117 | ||
| 118 | // Determine the next tag. | 118 | // Determine the next tag. |
| 119 | u32 next_value{}; | 119 | u32 next_value{}; |
| 120 | if (next_owner_thread != nullptr) { | 120 | if (next_owner_thread != nullptr) { |
| 121 | next_value = next_owner_thread->GetAddressKeyValue(); | 121 | next_value = next_owner_thread->GetAddressKeyValue(); |
| 122 | if (num_waiters > 1) { | 122 | if (has_waiters) { |
| 123 | next_value |= Svc::HandleWaitMask; | 123 | next_value |= Svc::HandleWaitMask; |
| 124 | } | 124 | } |
| 125 | } | ||
| 125 | 126 | ||
| 126 | // Write the value to userspace. | 127 | // Synchronize memory before proceeding. |
| 127 | Result result{ResultSuccess}; | 128 | std::atomic_thread_fence(std::memory_order_seq_cst); |
| 128 | if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] { | ||
| 129 | result = ResultSuccess; | ||
| 130 | } else { | ||
| 131 | result = ResultInvalidCurrentMemory; | ||
| 132 | } | ||
| 133 | 129 | ||
| 134 | // Signal the next owner thread. | 130 | // Write the value to userspace. |
| 135 | next_owner_thread->EndWait(result); | 131 | Result result{ResultSuccess}; |
| 136 | return result; | 132 | if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] { |
| 133 | result = ResultSuccess; | ||
| 137 | } else { | 134 | } else { |
| 138 | // Just write the value to userspace. | 135 | result = ResultInvalidCurrentMemory; |
| 139 | R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)), | 136 | } |
| 140 | ResultInvalidCurrentMemory); | ||
| 141 | 137 | ||
| 142 | return ResultSuccess; | 138 | // If necessary, signal the next owner thread. |
| 139 | if (next_owner_thread != nullptr) { | ||
| 140 | next_owner_thread->EndWait(result); | ||
| 143 | } | 141 | } |
| 142 | |||
| 143 | R_RETURN(result); | ||
| 144 | } | 144 | } |
| 145 | } | 145 | } |
| 146 | 146 | ||
| @@ -198,7 +198,9 @@ void KConditionVariable::SignalImpl(KThread* thread) { | |||
| 198 | u32 prev_tag{}; | 198 | u32 prev_tag{}; |
| 199 | bool can_access{}; | 199 | bool can_access{}; |
| 200 | { | 200 | { |
| 201 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. | 201 | // NOTE: If scheduler lock is not held here, interrupt disable is required. |
| 202 | // KScopedInterruptDisable di; | ||
| 203 | |||
| 202 | // TODO(bunnei): We should call CanAccessAtomic(..) here. | 204 | // TODO(bunnei): We should call CanAccessAtomic(..) here. |
| 203 | can_access = true; | 205 | can_access = true; |
| 204 | if (can_access) [[likely]] { | 206 | if (can_access) [[likely]] { |
| @@ -245,9 +247,11 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { | |||
| 245 | (it->GetConditionVariableKey() == cv_key)) { | 247 | (it->GetConditionVariableKey() == cv_key)) { |
| 246 | KThread* target_thread = std::addressof(*it); | 248 | KThread* target_thread = std::addressof(*it); |
| 247 | 249 | ||
| 248 | this->SignalImpl(target_thread); | ||
| 249 | it = thread_tree.erase(it); | 250 | it = thread_tree.erase(it); |
| 250 | target_thread->ClearConditionVariable(); | 251 | target_thread->ClearConditionVariable(); |
| 252 | |||
| 253 | this->SignalImpl(target_thread); | ||
| 254 | |||
| 251 | ++num_waiters; | 255 | ++num_waiters; |
| 252 | } | 256 | } |
| 253 | 257 | ||
| @@ -277,16 +281,16 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { | |||
| 277 | // Update the value and process for the next owner. | 281 | // Update the value and process for the next owner. |
| 278 | { | 282 | { |
| 279 | // Remove waiter thread. | 283 | // Remove waiter thread. |
| 280 | s32 num_waiters{}; | 284 | bool has_waiters{}; |
| 281 | KThread* next_owner_thread = | 285 | KThread* next_owner_thread = |
| 282 | cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); | 286 | cur_thread->RemoveUserWaiterByKey(std::addressof(has_waiters), addr); |
| 283 | 287 | ||
| 284 | // Update for the next owner thread. | 288 | // Update for the next owner thread. |
| 285 | u32 next_value{}; | 289 | u32 next_value{}; |
| 286 | if (next_owner_thread != nullptr) { | 290 | if (next_owner_thread != nullptr) { |
| 287 | // Get the next tag value. | 291 | // Get the next tag value. |
| 288 | next_value = next_owner_thread->GetAddressKeyValue(); | 292 | next_value = next_owner_thread->GetAddressKeyValue(); |
| 289 | if (num_waiters > 1) { | 293 | if (has_waiters) { |
| 290 | next_value |= Svc::HandleWaitMask; | 294 | next_value |= Svc::HandleWaitMask; |
| 291 | } | 295 | } |
| 292 | 296 | ||
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index d791acbe3..14cb615da 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp | |||
| @@ -90,15 +90,15 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { | |||
| 90 | KScopedSchedulerLock sl(kernel); | 90 | KScopedSchedulerLock sl(kernel); |
| 91 | 91 | ||
| 92 | // Get the next owner. | 92 | // Get the next owner. |
| 93 | s32 num_waiters; | 93 | bool has_waiters; |
| 94 | KThread* next_owner = owner_thread->RemoveWaiterByKey( | 94 | KThread* next_owner = owner_thread->RemoveKernelWaiterByKey( |
| 95 | std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag))); | 95 | std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag))); |
| 96 | 96 | ||
| 97 | // Pass the lock to the next owner. | 97 | // Pass the lock to the next owner. |
| 98 | uintptr_t next_tag = 0; | 98 | uintptr_t next_tag = 0; |
| 99 | if (next_owner != nullptr) { | 99 | if (next_owner != nullptr) { |
| 100 | next_tag = | 100 | next_tag = |
| 101 | reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1); | 101 | reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(has_waiters); |
| 102 | 102 | ||
| 103 | next_owner->EndWait(ResultSuccess); | 103 | next_owner->EndWait(ResultSuccess); |
| 104 | 104 | ||
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index d9c1a0eb3..d44f6e921 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -156,9 +156,9 @@ bool KProcess::ReleaseUserException(KThread* thread) { | |||
| 156 | exception_thread = nullptr; | 156 | exception_thread = nullptr; |
| 157 | 157 | ||
| 158 | // Remove waiter thread. | 158 | // Remove waiter thread. |
| 159 | s32 num_waiters{}; | 159 | bool has_waiters{}; |
| 160 | if (KThread* next = thread->RemoveWaiterByKey( | 160 | if (KThread* next = thread->RemoveKernelWaiterByKey( |
| 161 | std::addressof(num_waiters), | 161 | std::addressof(has_waiters), |
| 162 | reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); | 162 | reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); |
| 163 | next != nullptr) { | 163 | next != nullptr) { |
| 164 | next->EndWait(ResultSuccess); | 164 | next->EndWait(ResultSuccess); |
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h index 129d60472..13463717f 100644 --- a/src/core/hle/kernel/k_scheduler_lock.h +++ b/src/core/hle/kernel/k_scheduler_lock.h | |||
| @@ -31,22 +31,23 @@ public: | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | if (IsLockedByCurrentThread()) { | 33 | if (IsLockedByCurrentThread()) { |
| 34 | // If we already own the lock, we can just increment the count. | 34 | // If we already own the lock, the lock count should be > 0. |
| 35 | // For debug, ensure this is true. | ||
| 35 | ASSERT(lock_count > 0); | 36 | ASSERT(lock_count > 0); |
| 36 | lock_count++; | ||
| 37 | } else { | 37 | } else { |
| 38 | // Otherwise, we want to disable scheduling and acquire the spinlock. | 38 | // Otherwise, we want to disable scheduling and acquire the spinlock. |
| 39 | SchedulerType::DisableScheduling(kernel); | 39 | SchedulerType::DisableScheduling(kernel); |
| 40 | spin_lock.Lock(); | 40 | spin_lock.Lock(); |
| 41 | 41 | ||
| 42 | // For debug, ensure that our state is valid. | ||
| 43 | ASSERT(lock_count == 0); | 42 | ASSERT(lock_count == 0); |
| 44 | ASSERT(owner_thread == nullptr); | 43 | ASSERT(owner_thread == nullptr); |
| 45 | 44 | ||
| 46 | // Increment count, take ownership. | 45 | // Take ownership of the lock. |
| 47 | lock_count = 1; | ||
| 48 | owner_thread = GetCurrentThreadPointer(kernel); | 46 | owner_thread = GetCurrentThreadPointer(kernel); |
| 49 | } | 47 | } |
| 48 | |||
| 49 | // Increment the lock count. | ||
| 50 | lock_count++; | ||
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | void Unlock() { | 53 | void Unlock() { |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 599d05947..8c403f5fd 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -191,7 +191,7 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack | |||
| 191 | light_ipc_data = nullptr; | 191 | light_ipc_data = nullptr; |
| 192 | 192 | ||
| 193 | // We're not waiting for a lock, and we haven't disabled migration. | 193 | // We're not waiting for a lock, and we haven't disabled migration. |
| 194 | lock_owner = nullptr; | 194 | waiting_lock_info = nullptr; |
| 195 | num_core_migration_disables = 0; | 195 | num_core_migration_disables = 0; |
| 196 | 196 | ||
| 197 | // We have no waiters, but we do have an entrypoint. | 197 | // We have no waiters, but we do have an entrypoint. |
| @@ -341,25 +341,39 @@ void KThread::Finalize() { | |||
| 341 | 341 | ||
| 342 | // Release any waiters. | 342 | // Release any waiters. |
| 343 | { | 343 | { |
| 344 | ASSERT(lock_owner == nullptr); | 344 | ASSERT(waiting_lock_info == nullptr); |
| 345 | KScopedSchedulerLock sl{kernel}; | 345 | KScopedSchedulerLock sl{kernel}; |
| 346 | 346 | ||
| 347 | auto it = waiter_list.begin(); | 347 | // Check that we have no kernel waiters. |
| 348 | while (it != waiter_list.end()) { | 348 | ASSERT(num_kernel_waiters == 0); |
| 349 | // Get the thread. | ||
| 350 | KThread* const waiter = std::addressof(*it); | ||
| 351 | 349 | ||
| 352 | // The thread shouldn't be a kernel waiter. | 350 | auto it = held_lock_info_list.begin(); |
| 353 | ASSERT(!waiter->GetAddressKeyIsKernel()); | 351 | while (it != held_lock_info_list.end()) { |
| 352 | // Get the lock info. | ||
| 353 | auto* const lock_info = std::addressof(*it); | ||
| 354 | 354 | ||
| 355 | // Clear the lock owner. | 355 | // The lock shouldn't have a kernel waiter. |
| 356 | waiter->SetLockOwner(nullptr); | 356 | ASSERT(!lock_info->GetIsKernelAddressKey()); |
| 357 | 357 | ||
| 358 | // Erase the waiter from our list. | 358 | // Remove all waiters. |
| 359 | it = waiter_list.erase(it); | 359 | while (lock_info->GetWaiterCount() != 0) { |
| 360 | // Get the front waiter. | ||
| 361 | KThread* const waiter = lock_info->GetHighestPriorityWaiter(); | ||
| 360 | 362 | ||
| 361 | // Cancel the thread's wait. | 363 | // Remove it from the lock. |
| 362 | waiter->CancelWait(ResultInvalidState, true); | 364 | if (lock_info->RemoveWaiter(waiter)) { |
| 365 | ASSERT(lock_info->GetWaiterCount() == 0); | ||
| 366 | } | ||
| 367 | |||
| 368 | // Cancel the thread's wait. | ||
| 369 | waiter->CancelWait(ResultInvalidState, true); | ||
| 370 | } | ||
| 371 | |||
| 372 | // Remove the held lock from our list. | ||
| 373 | it = held_lock_info_list.erase(it); | ||
| 374 | |||
| 375 | // Free the lock info. | ||
| 376 | LockWithPriorityInheritanceInfo::Free(kernel, lock_info); | ||
| 363 | } | 377 | } |
| 364 | } | 378 | } |
| 365 | 379 | ||
| @@ -708,6 +722,24 @@ void KThread::SetBasePriority(s32 value) { | |||
| 708 | RestorePriority(kernel, this); | 722 | RestorePriority(kernel, this); |
| 709 | } | 723 | } |
| 710 | 724 | ||
| 725 | KThread* KThread::GetLockOwner() const { | ||
| 726 | return waiting_lock_info != nullptr ? waiting_lock_info->GetOwner() : nullptr; | ||
| 727 | } | ||
| 728 | |||
| 729 | void KThread::IncreaseBasePriority(s32 priority_) { | ||
| 730 | ASSERT(Svc::HighestThreadPriority <= priority_ && priority_ <= Svc::LowestThreadPriority); | ||
| 731 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); | ||
| 732 | ASSERT(!this->GetStackParameters().is_pinned); | ||
| 733 | |||
| 734 | // Set our base priority. | ||
| 735 | if (base_priority > priority_) { | ||
| 736 | base_priority = priority_; | ||
| 737 | |||
| 738 | // Perform a priority restoration. | ||
| 739 | RestorePriority(kernel, this); | ||
| 740 | } | ||
| 741 | } | ||
| 742 | |||
| 711 | void KThread::RequestSuspend(SuspendType type) { | 743 | void KThread::RequestSuspend(SuspendType type) { |
| 712 | KScopedSchedulerLock sl{kernel}; | 744 | KScopedSchedulerLock sl{kernel}; |
| 713 | 745 | ||
| @@ -891,51 +923,89 @@ Result KThread::GetThreadContext3(std::vector<u8>& out) { | |||
| 891 | R_SUCCEED(); | 923 | R_SUCCEED(); |
| 892 | } | 924 | } |
| 893 | 925 | ||
| 894 | void KThread::AddWaiterImpl(KThread* thread) { | 926 | void KThread::AddHeldLock(LockWithPriorityInheritanceInfo* lock_info) { |
| 895 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 927 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); |
| 928 | |||
| 929 | // Set ourselves as the lock's owner. | ||
| 930 | lock_info->SetOwner(this); | ||
| 896 | 931 | ||
| 897 | // Find the right spot to insert the waiter. | 932 | // Add the lock to our held list. |
| 898 | auto it = waiter_list.begin(); | 933 | held_lock_info_list.push_front(*lock_info); |
| 899 | while (it != waiter_list.end()) { | 934 | } |
| 900 | if (it->GetPriority() > thread->GetPriority()) { | 935 | |
| 901 | break; | 936 | KThread::LockWithPriorityInheritanceInfo* KThread::FindHeldLock(VAddr address_key_, |
| 937 | bool is_kernel_address_key_) { | ||
| 938 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); | ||
| 939 | |||
| 940 | // Try to find an existing held lock. | ||
| 941 | for (auto& held_lock : held_lock_info_list) { | ||
| 942 | if (held_lock.GetAddressKey() == address_key_ && | ||
| 943 | held_lock.GetIsKernelAddressKey() == is_kernel_address_key_) { | ||
| 944 | return std::addressof(held_lock); | ||
| 902 | } | 945 | } |
| 903 | it++; | ||
| 904 | } | 946 | } |
| 905 | 947 | ||
| 948 | return nullptr; | ||
| 949 | } | ||
| 950 | |||
| 951 | void KThread::AddWaiterImpl(KThread* thread) { | ||
| 952 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); | ||
| 953 | ASSERT(thread->GetConditionVariableTree() == nullptr); | ||
| 954 | |||
| 955 | // Get the thread's address key. | ||
| 956 | const auto address_key_ = thread->GetAddressKey(); | ||
| 957 | const auto is_kernel_address_key_ = thread->GetIsKernelAddressKey(); | ||
| 958 | |||
| 906 | // Keep track of how many kernel waiters we have. | 959 | // Keep track of how many kernel waiters we have. |
| 907 | if (thread->GetAddressKeyIsKernel()) { | 960 | if (is_kernel_address_key_) { |
| 908 | ASSERT((num_kernel_waiters++) >= 0); | 961 | ASSERT((num_kernel_waiters++) >= 0); |
| 909 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 962 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 910 | } | 963 | } |
| 911 | 964 | ||
| 912 | // Insert the waiter. | 965 | // Get the relevant lock info. |
| 913 | waiter_list.insert(it, *thread); | 966 | auto* lock_info = this->FindHeldLock(address_key_, is_kernel_address_key_); |
| 914 | thread->SetLockOwner(this); | 967 | if (lock_info == nullptr) { |
| 968 | // Create a new lock for the address key. | ||
| 969 | lock_info = | ||
| 970 | LockWithPriorityInheritanceInfo::Create(kernel, address_key_, is_kernel_address_key_); | ||
| 971 | |||
| 972 | // Add the new lock to our list. | ||
| 973 | this->AddHeldLock(lock_info); | ||
| 974 | } | ||
| 975 | |||
| 976 | // Add the thread as waiter to the lock info. | ||
| 977 | lock_info->AddWaiter(thread); | ||
| 915 | } | 978 | } |
| 916 | 979 | ||
| 917 | void KThread::RemoveWaiterImpl(KThread* thread) { | 980 | void KThread::RemoveWaiterImpl(KThread* thread) { |
| 918 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 981 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); |
| 919 | 982 | ||
| 920 | // Keep track of how many kernel waiters we have. | 983 | // Keep track of how many kernel waiters we have. |
| 921 | if (thread->GetAddressKeyIsKernel()) { | 984 | if (thread->GetIsKernelAddressKey()) { |
| 922 | ASSERT((num_kernel_waiters--) > 0); | 985 | ASSERT((num_kernel_waiters--) > 0); |
| 923 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 986 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 924 | } | 987 | } |
| 925 | 988 | ||
| 989 | // Get the info for the lock the thread is waiting on. | ||
| 990 | auto* lock_info = thread->GetWaitingLockInfo(); | ||
| 991 | ASSERT(lock_info->GetOwner() == this); | ||
| 992 | |||
| 926 | // Remove the waiter. | 993 | // Remove the waiter. |
| 927 | waiter_list.erase(waiter_list.iterator_to(*thread)); | 994 | if (lock_info->RemoveWaiter(thread)) { |
| 928 | thread->SetLockOwner(nullptr); | 995 | held_lock_info_list.erase(held_lock_info_list.iterator_to(*lock_info)); |
| 996 | LockWithPriorityInheritanceInfo::Free(kernel, lock_info); | ||
| 997 | } | ||
| 929 | } | 998 | } |
| 930 | 999 | ||
| 931 | void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) { | 1000 | void KThread::RestorePriority(KernelCore& kernel, KThread* thread) { |
| 932 | ASSERT(kernel_ctx.GlobalSchedulerContext().IsLocked()); | 1001 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); |
| 933 | 1002 | ||
| 934 | while (true) { | 1003 | while (thread != nullptr) { |
| 935 | // We want to inherit priority where possible. | 1004 | // We want to inherit priority where possible. |
| 936 | s32 new_priority = thread->GetBasePriority(); | 1005 | s32 new_priority = thread->GetBasePriority(); |
| 937 | if (thread->HasWaiters()) { | 1006 | for (const auto& held_lock : thread->held_lock_info_list) { |
| 938 | new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority()); | 1007 | new_priority = |
| 1008 | std::min(new_priority, held_lock.GetHighestPriorityWaiter()->GetPriority()); | ||
| 939 | } | 1009 | } |
| 940 | 1010 | ||
| 941 | // If the priority we would inherit is not different from ours, don't do anything. | 1011 | // If the priority we would inherit is not different from ours, don't do anything. |
| @@ -943,9 +1013,18 @@ void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) { | |||
| 943 | return; | 1013 | return; |
| 944 | } | 1014 | } |
| 945 | 1015 | ||
| 1016 | // Get the owner of whatever lock this thread is waiting on. | ||
| 1017 | KThread* const lock_owner = thread->GetLockOwner(); | ||
| 1018 | |||
| 1019 | // If the thread is waiting on some lock, remove it as a waiter to prevent violating red | ||
| 1020 | // black tree invariants. | ||
| 1021 | if (lock_owner != nullptr) { | ||
| 1022 | lock_owner->RemoveWaiterImpl(thread); | ||
| 1023 | } | ||
| 1024 | |||
| 946 | // Ensure we don't violate condition variable red black tree invariants. | 1025 | // Ensure we don't violate condition variable red black tree invariants. |
| 947 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { | 1026 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { |
| 948 | BeforeUpdatePriority(kernel_ctx, cv_tree, thread); | 1027 | BeforeUpdatePriority(kernel, cv_tree, thread); |
| 949 | } | 1028 | } |
| 950 | 1029 | ||
| 951 | // Change the priority. | 1030 | // Change the priority. |
| @@ -954,73 +1033,99 @@ void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) { | |||
| 954 | 1033 | ||
| 955 | // Restore the condition variable, if relevant. | 1034 | // Restore the condition variable, if relevant. |
| 956 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { | 1035 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { |
| 957 | AfterUpdatePriority(kernel_ctx, cv_tree, thread); | 1036 | AfterUpdatePriority(kernel, cv_tree, thread); |
| 958 | } | 1037 | } |
| 959 | 1038 | ||
| 960 | // Update the scheduler. | 1039 | // If we removed the thread from some lock's waiting list, add it back. |
| 961 | KScheduler::OnThreadPriorityChanged(kernel_ctx, thread, old_priority); | 1040 | if (lock_owner != nullptr) { |
| 962 | 1041 | lock_owner->AddWaiterImpl(thread); | |
| 963 | // Keep the lock owner up to date. | ||
| 964 | KThread* lock_owner = thread->GetLockOwner(); | ||
| 965 | if (lock_owner == nullptr) { | ||
| 966 | return; | ||
| 967 | } | 1042 | } |
| 968 | 1043 | ||
| 969 | // Update the thread in the lock owner's sorted list, and continue inheriting. | 1044 | // Update the scheduler. |
| 970 | lock_owner->RemoveWaiterImpl(thread); | 1045 | KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); |
| 971 | lock_owner->AddWaiterImpl(thread); | 1046 | |
| 1047 | // Continue inheriting priority. | ||
| 972 | thread = lock_owner; | 1048 | thread = lock_owner; |
| 973 | } | 1049 | } |
| 974 | } | 1050 | } |
| 975 | 1051 | ||
| 976 | void KThread::AddWaiter(KThread* thread) { | 1052 | void KThread::AddWaiter(KThread* thread) { |
| 977 | AddWaiterImpl(thread); | 1053 | this->AddWaiterImpl(thread); |
| 978 | RestorePriority(kernel, this); | 1054 | |
| 1055 | // If the thread has a higher priority than us, we should inherit. | ||
| 1056 | if (thread->GetPriority() < this->GetPriority()) { | ||
| 1057 | RestorePriority(kernel, this); | ||
| 1058 | } | ||
| 979 | } | 1059 | } |
| 980 | 1060 | ||
| 981 | void KThread::RemoveWaiter(KThread* thread) { | 1061 | void KThread::RemoveWaiter(KThread* thread) { |
| 982 | RemoveWaiterImpl(thread); | 1062 | this->RemoveWaiterImpl(thread); |
| 983 | RestorePriority(kernel, this); | 1063 | |
| 1064 | // If our priority is the same as the thread's (and we've inherited), we may need to restore to | ||
| 1065 | // lower priority. | ||
| 1066 | if (this->GetPriority() == thread->GetPriority() && | ||
| 1067 | this->GetPriority() < this->GetBasePriority()) { | ||
| 1068 | RestorePriority(kernel, this); | ||
| 1069 | } | ||
| 984 | } | 1070 | } |
| 985 | 1071 | ||
| 986 | KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { | 1072 | KThread* KThread::RemoveWaiterByKey(bool* out_has_waiters, VAddr key, bool is_kernel_address_key_) { |
| 987 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 1073 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); |
| 988 | 1074 | ||
| 989 | s32 num_waiters{}; | 1075 | // Get the relevant lock info. |
| 990 | KThread* next_lock_owner{}; | 1076 | auto* lock_info = this->FindHeldLock(key, is_kernel_address_key_); |
| 991 | auto it = waiter_list.begin(); | 1077 | if (lock_info == nullptr) { |
| 992 | while (it != waiter_list.end()) { | 1078 | *out_has_waiters = false; |
| 993 | if (it->GetAddressKey() == key) { | 1079 | return nullptr; |
| 994 | KThread* thread = std::addressof(*it); | 1080 | } |
| 995 | |||
| 996 | // Keep track of how many kernel waiters we have. | ||
| 997 | if (thread->GetAddressKeyIsKernel()) { | ||
| 998 | ASSERT((num_kernel_waiters--) > 0); | ||
| 999 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 1000 | } | ||
| 1001 | it = waiter_list.erase(it); | ||
| 1002 | 1081 | ||
| 1003 | // Update the next lock owner. | 1082 | // Remove the lock info from our held list. |
| 1004 | if (next_lock_owner == nullptr) { | 1083 | held_lock_info_list.erase(held_lock_info_list.iterator_to(*lock_info)); |
| 1005 | next_lock_owner = thread; | 1084 | |
| 1006 | next_lock_owner->SetLockOwner(nullptr); | 1085 | // Keep track of how many kernel waiters we have. |
| 1007 | } else { | 1086 | if (lock_info->GetIsKernelAddressKey()) { |
| 1008 | next_lock_owner->AddWaiterImpl(thread); | 1087 | num_kernel_waiters -= lock_info->GetWaiterCount(); |
| 1009 | } | 1088 | ASSERT(num_kernel_waiters >= 0); |
| 1010 | num_waiters++; | 1089 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 1011 | } else { | 1090 | } |
| 1012 | it++; | 1091 | |
| 1092 | ASSERT(lock_info->GetWaiterCount() > 0); | ||
| 1093 | |||
| 1094 | // Remove the highest priority waiter from the lock to be the next owner. | ||
| 1095 | KThread* next_lock_owner = lock_info->GetHighestPriorityWaiter(); | ||
| 1096 | if (lock_info->RemoveWaiter(next_lock_owner)) { | ||
| 1097 | // The new owner was the only waiter. | ||
| 1098 | *out_has_waiters = false; | ||
| 1099 | |||
| 1100 | // Free the lock info, since it has no waiters. | ||
| 1101 | LockWithPriorityInheritanceInfo::Free(kernel, lock_info); | ||
| 1102 | } else { | ||
| 1103 | // There are additional waiters on the lock. | ||
| 1104 | *out_has_waiters = true; | ||
| 1105 | |||
| 1106 | // Add the lock to the new owner's held list. | ||
| 1107 | next_lock_owner->AddHeldLock(lock_info); | ||
| 1108 | |||
| 1109 | // Keep track of any kernel waiters for the new owner. | ||
| 1110 | if (lock_info->GetIsKernelAddressKey()) { | ||
| 1111 | next_lock_owner->num_kernel_waiters += lock_info->GetWaiterCount(); | ||
| 1112 | ASSERT(next_lock_owner->num_kernel_waiters > 0); | ||
| 1113 | |||
| 1114 | // NOTE: No need to set scheduler update needed, because we will have already done so | ||
| 1115 | // when removing earlier. | ||
| 1013 | } | 1116 | } |
| 1014 | } | 1117 | } |
| 1015 | 1118 | ||
| 1016 | // Do priority updates, if we have a next owner. | 1119 | // If our priority is the same as the next owner's (and we've inherited), we may need to restore |
| 1017 | if (next_lock_owner) { | 1120 | // to lower priority. |
| 1121 | if (this->GetPriority() == next_lock_owner->GetPriority() && | ||
| 1122 | this->GetPriority() < this->GetBasePriority()) { | ||
| 1018 | RestorePriority(kernel, this); | 1123 | RestorePriority(kernel, this); |
| 1019 | RestorePriority(kernel, next_lock_owner); | 1124 | // NOTE: No need to restore priority on the next lock owner, because it was already the |
| 1125 | // highest priority waiter on the lock. | ||
| 1020 | } | 1126 | } |
| 1021 | 1127 | ||
| 1022 | // Return output. | 1128 | // Return the next lock owner. |
| 1023 | *out_num_waiters = num_waiters; | ||
| 1024 | return next_lock_owner; | 1129 | return next_lock_owner; |
| 1025 | } | 1130 | } |
| 1026 | 1131 | ||
| @@ -1137,9 +1242,7 @@ ThreadState KThread::RequestTerminate() { | |||
| 1137 | } | 1242 | } |
| 1138 | 1243 | ||
| 1139 | // Change the thread's priority to be higher than any system thread's. | 1244 | // Change the thread's priority to be higher than any system thread's. |
| 1140 | if (this->GetBasePriority() >= Svc::SystemThreadPriorityHighest) { | 1245 | this->IncreaseBasePriority(TerminatingThreadPriority); |
| 1141 | this->SetBasePriority(TerminatingThreadPriority); | ||
| 1142 | } | ||
| 1143 | 1246 | ||
| 1144 | // If the thread is runnable, send a termination interrupt to other cores. | 1247 | // If the thread is runnable, send a termination interrupt to other cores. |
| 1145 | if (this->GetState() == ThreadState::Runnable) { | 1248 | if (this->GetState() == ThreadState::Runnable) { |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index a04de21bc..bd125f5f1 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -339,13 +339,7 @@ public: | |||
| 339 | void SetInterruptFlag(); | 339 | void SetInterruptFlag(); |
| 340 | void ClearInterruptFlag(); | 340 | void ClearInterruptFlag(); |
| 341 | 341 | ||
| 342 | [[nodiscard]] KThread* GetLockOwner() const { | 342 | KThread* GetLockOwner() const; |
| 343 | return lock_owner; | ||
| 344 | } | ||
| 345 | |||
| 346 | void SetLockOwner(KThread* owner) { | ||
| 347 | lock_owner = owner; | ||
| 348 | } | ||
| 349 | 343 | ||
| 350 | [[nodiscard]] const KAffinityMask& GetAffinityMask() const { | 344 | [[nodiscard]] const KAffinityMask& GetAffinityMask() const { |
| 351 | return physical_affinity_mask; | 345 | return physical_affinity_mask; |
| @@ -601,7 +595,13 @@ public: | |||
| 601 | 595 | ||
| 602 | [[nodiscard]] Result GetThreadContext3(std::vector<u8>& out); | 596 | [[nodiscard]] Result GetThreadContext3(std::vector<u8>& out); |
| 603 | 597 | ||
| 604 | [[nodiscard]] KThread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key); | 598 | [[nodiscard]] KThread* RemoveUserWaiterByKey(bool* out_has_waiters, VAddr key) { |
| 599 | return this->RemoveWaiterByKey(out_has_waiters, key, false); | ||
| 600 | } | ||
| 601 | |||
| 602 | [[nodiscard]] KThread* RemoveKernelWaiterByKey(bool* out_has_waiters, VAddr key) { | ||
| 603 | return this->RemoveWaiterByKey(out_has_waiters, key, true); | ||
| 604 | } | ||
| 605 | 605 | ||
| 606 | [[nodiscard]] VAddr GetAddressKey() const { | 606 | [[nodiscard]] VAddr GetAddressKey() const { |
| 607 | return address_key; | 607 | return address_key; |
| @@ -611,8 +611,8 @@ public: | |||
| 611 | return address_key_value; | 611 | return address_key_value; |
| 612 | } | 612 | } |
| 613 | 613 | ||
| 614 | [[nodiscard]] bool GetAddressKeyIsKernel() const { | 614 | [[nodiscard]] bool GetIsKernelAddressKey() const { |
| 615 | return address_key_is_kernel; | 615 | return is_kernel_address_key; |
| 616 | } | 616 | } |
| 617 | 617 | ||
| 618 | //! NB: intentional deviation from official kernel. | 618 | //! NB: intentional deviation from official kernel. |
| @@ -621,20 +621,17 @@ public: | |||
| 621 | // to cope with arbitrary host pointers making their way | 621 | // to cope with arbitrary host pointers making their way |
| 622 | // into things. | 622 | // into things. |
| 623 | 623 | ||
| 624 | void SetUserAddressKey(VAddr key) { | ||
| 625 | address_key = key; | ||
| 626 | address_key_is_kernel = false; | ||
| 627 | } | ||
| 628 | |||
| 629 | void SetUserAddressKey(VAddr key, u32 val) { | 624 | void SetUserAddressKey(VAddr key, u32 val) { |
| 625 | ASSERT(waiting_lock_info == nullptr); | ||
| 630 | address_key = key; | 626 | address_key = key; |
| 631 | address_key_value = val; | 627 | address_key_value = val; |
| 632 | address_key_is_kernel = false; | 628 | is_kernel_address_key = false; |
| 633 | } | 629 | } |
| 634 | 630 | ||
| 635 | void SetKernelAddressKey(VAddr key) { | 631 | void SetKernelAddressKey(VAddr key) { |
| 632 | ASSERT(waiting_lock_info == nullptr); | ||
| 636 | address_key = key; | 633 | address_key = key; |
| 637 | address_key_is_kernel = true; | 634 | is_kernel_address_key = true; |
| 638 | } | 635 | } |
| 639 | 636 | ||
| 640 | void ClearWaitQueue() { | 637 | void ClearWaitQueue() { |
| @@ -646,10 +643,6 @@ public: | |||
| 646 | void EndWait(Result wait_result_); | 643 | void EndWait(Result wait_result_); |
| 647 | void CancelWait(Result wait_result_, bool cancel_timer_task); | 644 | void CancelWait(Result wait_result_, bool cancel_timer_task); |
| 648 | 645 | ||
| 649 | [[nodiscard]] bool HasWaiters() const { | ||
| 650 | return !waiter_list.empty(); | ||
| 651 | } | ||
| 652 | |||
| 653 | [[nodiscard]] s32 GetNumKernelWaiters() const { | 646 | [[nodiscard]] s32 GetNumKernelWaiters() const { |
| 654 | return num_kernel_waiters; | 647 | return num_kernel_waiters; |
| 655 | } | 648 | } |
| @@ -679,6 +672,9 @@ public: | |||
| 679 | } | 672 | } |
| 680 | 673 | ||
| 681 | private: | 674 | private: |
| 675 | [[nodiscard]] KThread* RemoveWaiterByKey(bool* out_has_waiters, VAddr key, | ||
| 676 | bool is_kernel_address_key); | ||
| 677 | |||
| 682 | static constexpr size_t PriorityInheritanceCountMax = 10; | 678 | static constexpr size_t PriorityInheritanceCountMax = 10; |
| 683 | union SyncObjectBuffer { | 679 | union SyncObjectBuffer { |
| 684 | std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{}; | 680 | std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{}; |
| @@ -722,13 +718,14 @@ private: | |||
| 722 | }; | 718 | }; |
| 723 | 719 | ||
| 724 | void AddWaiterImpl(KThread* thread); | 720 | void AddWaiterImpl(KThread* thread); |
| 725 | |||
| 726 | void RemoveWaiterImpl(KThread* thread); | 721 | void RemoveWaiterImpl(KThread* thread); |
| 722 | static void RestorePriority(KernelCore& kernel, KThread* thread); | ||
| 727 | 723 | ||
| 728 | void StartTermination(); | 724 | void StartTermination(); |
| 729 | |||
| 730 | void FinishTermination(); | 725 | void FinishTermination(); |
| 731 | 726 | ||
| 727 | void IncreaseBasePriority(s32 priority); | ||
| 728 | |||
| 732 | [[nodiscard]] Result Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, | 729 | [[nodiscard]] Result Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, |
| 733 | s32 prio, s32 virt_core, KProcess* owner, ThreadType type); | 730 | s32 prio, s32 virt_core, KProcess* owner, ThreadType type); |
| 734 | 731 | ||
| @@ -737,8 +734,6 @@ private: | |||
| 737 | s32 core, KProcess* owner, ThreadType type, | 734 | s32 core, KProcess* owner, ThreadType type, |
| 738 | std::function<void()>&& init_func); | 735 | std::function<void()>&& init_func); |
| 739 | 736 | ||
| 740 | static void RestorePriority(KernelCore& kernel_ctx, KThread* thread); | ||
| 741 | |||
| 742 | // For core KThread implementation | 737 | // For core KThread implementation |
| 743 | ThreadContext32 thread_context_32{}; | 738 | ThreadContext32 thread_context_32{}; |
| 744 | ThreadContext64 thread_context_64{}; | 739 | ThreadContext64 thread_context_64{}; |
| @@ -749,6 +744,127 @@ private: | |||
| 749 | &KThread::condvar_arbiter_tree_node>; | 744 | &KThread::condvar_arbiter_tree_node>; |
| 750 | using ConditionVariableThreadTree = | 745 | using ConditionVariableThreadTree = |
| 751 | ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>; | 746 | ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>; |
| 747 | |||
| 748 | private: | ||
| 749 | struct LockWithPriorityInheritanceComparator { | ||
| 750 | struct RedBlackKeyType { | ||
| 751 | s32 m_priority; | ||
| 752 | |||
| 753 | constexpr s32 GetPriority() const { | ||
| 754 | return m_priority; | ||
| 755 | } | ||
| 756 | }; | ||
| 757 | |||
| 758 | template <typename T> | ||
| 759 | requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>) | ||
| 760 | static constexpr int Compare(const T& lhs, const KThread& rhs) { | ||
| 761 | if (lhs.GetPriority() < rhs.GetPriority()) { | ||
| 762 | // Sort by priority. | ||
| 763 | return -1; | ||
| 764 | } else { | ||
| 765 | return 1; | ||
| 766 | } | ||
| 767 | } | ||
| 768 | }; | ||
| 769 | static_assert(std::same_as<Common::RedBlackKeyType<LockWithPriorityInheritanceComparator, void>, | ||
| 770 | LockWithPriorityInheritanceComparator::RedBlackKeyType>); | ||
| 771 | |||
| 772 | using LockWithPriorityInheritanceThreadTreeTraits = | ||
| 773 | Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert< | ||
| 774 | &KThread::condvar_arbiter_tree_node>; | ||
| 775 | using LockWithPriorityInheritanceThreadTree = | ||
| 776 | ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>; | ||
| 777 | |||
| 778 | public: | ||
| 779 | class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>, | ||
| 780 | public boost::intrusive::list_base_hook<> { | ||
| 781 | public: | ||
| 782 | explicit LockWithPriorityInheritanceInfo(KernelCore&) {} | ||
| 783 | |||
| 784 | static LockWithPriorityInheritanceInfo* Create(KernelCore& kernel, VAddr address_key, | ||
| 785 | bool is_kernel_address_key) { | ||
| 786 | // Create a new lock info. | ||
| 787 | auto* new_lock = LockWithPriorityInheritanceInfo::Allocate(kernel); | ||
| 788 | ASSERT(new_lock != nullptr); | ||
| 789 | |||
| 790 | // Set the new lock's address key. | ||
| 791 | new_lock->m_address_key = address_key; | ||
| 792 | new_lock->m_is_kernel_address_key = is_kernel_address_key; | ||
| 793 | |||
| 794 | return new_lock; | ||
| 795 | } | ||
| 796 | |||
| 797 | void SetOwner(KThread* new_owner) { | ||
| 798 | // Set new owner. | ||
| 799 | m_owner = new_owner; | ||
| 800 | } | ||
| 801 | |||
| 802 | void AddWaiter(KThread* waiter) { | ||
| 803 | // Insert the waiter. | ||
| 804 | m_tree.insert(*waiter); | ||
| 805 | m_waiter_count++; | ||
| 806 | |||
| 807 | waiter->SetWaitingLockInfo(this); | ||
| 808 | } | ||
| 809 | |||
| 810 | [[nodiscard]] bool RemoveWaiter(KThread* waiter) { | ||
| 811 | m_tree.erase(m_tree.iterator_to(*waiter)); | ||
| 812 | |||
| 813 | waiter->SetWaitingLockInfo(nullptr); | ||
| 814 | |||
| 815 | return (--m_waiter_count) == 0; | ||
| 816 | } | ||
| 817 | |||
| 818 | KThread* GetHighestPriorityWaiter() { | ||
| 819 | return std::addressof(m_tree.front()); | ||
| 820 | } | ||
| 821 | const KThread* GetHighestPriorityWaiter() const { | ||
| 822 | return std::addressof(m_tree.front()); | ||
| 823 | } | ||
| 824 | |||
| 825 | LockWithPriorityInheritanceThreadTree& GetThreadTree() { | ||
| 826 | return m_tree; | ||
| 827 | } | ||
| 828 | const LockWithPriorityInheritanceThreadTree& GetThreadTree() const { | ||
| 829 | return m_tree; | ||
| 830 | } | ||
| 831 | |||
| 832 | VAddr GetAddressKey() const { | ||
| 833 | return m_address_key; | ||
| 834 | } | ||
| 835 | bool GetIsKernelAddressKey() const { | ||
| 836 | return m_is_kernel_address_key; | ||
| 837 | } | ||
| 838 | KThread* GetOwner() const { | ||
| 839 | return m_owner; | ||
| 840 | } | ||
| 841 | u32 GetWaiterCount() const { | ||
| 842 | return m_waiter_count; | ||
| 843 | } | ||
| 844 | |||
| 845 | private: | ||
| 846 | LockWithPriorityInheritanceThreadTree m_tree{}; | ||
| 847 | VAddr m_address_key{}; | ||
| 848 | KThread* m_owner{}; | ||
| 849 | u32 m_waiter_count{}; | ||
| 850 | bool m_is_kernel_address_key{}; | ||
| 851 | }; | ||
| 852 | |||
| 853 | void SetWaitingLockInfo(LockWithPriorityInheritanceInfo* lock) { | ||
| 854 | waiting_lock_info = lock; | ||
| 855 | } | ||
| 856 | |||
| 857 | LockWithPriorityInheritanceInfo* GetWaitingLockInfo() { | ||
| 858 | return waiting_lock_info; | ||
| 859 | } | ||
| 860 | |||
| 861 | void AddHeldLock(LockWithPriorityInheritanceInfo* lock_info); | ||
| 862 | LockWithPriorityInheritanceInfo* FindHeldLock(VAddr address_key, bool is_kernel_address_key); | ||
| 863 | |||
| 864 | private: | ||
| 865 | using LockWithPriorityInheritanceInfoList = | ||
| 866 | boost::intrusive::list<LockWithPriorityInheritanceInfo>; | ||
| 867 | |||
| 752 | ConditionVariableThreadTree* condvar_tree{}; | 868 | ConditionVariableThreadTree* condvar_tree{}; |
| 753 | u64 condvar_key{}; | 869 | u64 condvar_key{}; |
| 754 | u64 virtual_affinity_mask{}; | 870 | u64 virtual_affinity_mask{}; |
| @@ -765,9 +881,9 @@ private: | |||
| 765 | s64 last_scheduled_tick{}; | 881 | s64 last_scheduled_tick{}; |
| 766 | std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; | 882 | std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; |
| 767 | KThreadQueue* wait_queue{}; | 883 | KThreadQueue* wait_queue{}; |
| 768 | WaiterList waiter_list{}; | 884 | LockWithPriorityInheritanceInfoList held_lock_info_list{}; |
| 885 | LockWithPriorityInheritanceInfo* waiting_lock_info{}; | ||
| 769 | WaiterList pinned_waiter_list{}; | 886 | WaiterList pinned_waiter_list{}; |
| 770 | KThread* lock_owner{}; | ||
| 771 | u32 address_key_value{}; | 887 | u32 address_key_value{}; |
| 772 | u32 suspend_request_flags{}; | 888 | u32 suspend_request_flags{}; |
| 773 | u32 suspend_allowed_flags{}; | 889 | u32 suspend_allowed_flags{}; |
| @@ -791,7 +907,7 @@ private: | |||
| 791 | bool debug_attached{}; | 907 | bool debug_attached{}; |
| 792 | s8 priority_inheritance_count{}; | 908 | s8 priority_inheritance_count{}; |
| 793 | bool resource_limit_release_hint{}; | 909 | bool resource_limit_release_hint{}; |
| 794 | bool address_key_is_kernel{}; | 910 | bool is_kernel_address_key{}; |
| 795 | StackParameters stack_parameters{}; | 911 | StackParameters stack_parameters{}; |
| 796 | Common::SpinLock context_guard{}; | 912 | Common::SpinLock context_guard{}; |
| 797 | 913 | ||
| @@ -814,10 +930,12 @@ public: | |||
| 814 | 930 | ||
| 815 | void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key, | 931 | void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key, |
| 816 | u32 value) { | 932 | u32 value) { |
| 933 | ASSERT(waiting_lock_info == nullptr); | ||
| 817 | condvar_tree = tree; | 934 | condvar_tree = tree; |
| 818 | condvar_key = cv_key; | 935 | condvar_key = cv_key; |
| 819 | address_key = address; | 936 | address_key = address; |
| 820 | address_key_value = value; | 937 | address_key_value = value; |
| 938 | is_kernel_address_key = false; | ||
| 821 | } | 939 | } |
| 822 | 940 | ||
| 823 | void ClearConditionVariable() { | 941 | void ClearConditionVariable() { |
| @@ -829,6 +947,7 @@ public: | |||
| 829 | } | 947 | } |
| 830 | 948 | ||
| 831 | void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) { | 949 | void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) { |
| 950 | ASSERT(waiting_lock_info == nullptr); | ||
| 832 | condvar_tree = tree; | 951 | condvar_tree = tree; |
| 833 | condvar_key = address; | 952 | condvar_key = address; |
| 834 | } | 953 | } |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ce94d3605..ef7057ff7 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -1318,4 +1318,97 @@ const Core::System& KernelCore::System() const { | |||
| 1318 | return impl->system; | 1318 | return impl->system; |
| 1319 | } | 1319 | } |
| 1320 | 1320 | ||
| 1321 | struct KernelCore::SlabHeapContainer { | ||
| 1322 | KSlabHeap<KClientSession> client_session; | ||
| 1323 | KSlabHeap<KEvent> event; | ||
| 1324 | KSlabHeap<KLinkedListNode> linked_list_node; | ||
| 1325 | KSlabHeap<KPort> port; | ||
| 1326 | KSlabHeap<KProcess> process; | ||
| 1327 | KSlabHeap<KResourceLimit> resource_limit; | ||
| 1328 | KSlabHeap<KSession> session; | ||
| 1329 | KSlabHeap<KSharedMemory> shared_memory; | ||
| 1330 | KSlabHeap<KSharedMemoryInfo> shared_memory_info; | ||
| 1331 | KSlabHeap<KThread> thread; | ||
| 1332 | KSlabHeap<KTransferMemory> transfer_memory; | ||
| 1333 | KSlabHeap<KCodeMemory> code_memory; | ||
| 1334 | KSlabHeap<KDeviceAddressSpace> device_address_space; | ||
| 1335 | KSlabHeap<KPageBuffer> page_buffer; | ||
| 1336 | KSlabHeap<KThreadLocalPage> thread_local_page; | ||
| 1337 | KSlabHeap<KObjectName> object_name; | ||
| 1338 | KSlabHeap<KSessionRequest> session_request; | ||
| 1339 | KSlabHeap<KSecureSystemResource> secure_system_resource; | ||
| 1340 | KSlabHeap<KThread::LockWithPriorityInheritanceInfo> lock_info; | ||
| 1341 | KSlabHeap<KEventInfo> event_info; | ||
| 1342 | KSlabHeap<KDebug> debug; | ||
| 1343 | }; | ||
| 1344 | |||
| 1345 | template <typename T> | ||
| 1346 | KSlabHeap<T>& KernelCore::SlabHeap() { | ||
| 1347 | if constexpr (std::is_same_v<T, KClientSession>) { | ||
| 1348 | return slab_heap_container->client_session; | ||
| 1349 | } else if constexpr (std::is_same_v<T, KEvent>) { | ||
| 1350 | return slab_heap_container->event; | ||
| 1351 | } else if constexpr (std::is_same_v<T, KLinkedListNode>) { | ||
| 1352 | return slab_heap_container->linked_list_node; | ||
| 1353 | } else if constexpr (std::is_same_v<T, KPort>) { | ||
| 1354 | return slab_heap_container->port; | ||
| 1355 | } else if constexpr (std::is_same_v<T, KProcess>) { | ||
| 1356 | return slab_heap_container->process; | ||
| 1357 | } else if constexpr (std::is_same_v<T, KResourceLimit>) { | ||
| 1358 | return slab_heap_container->resource_limit; | ||
| 1359 | } else if constexpr (std::is_same_v<T, KSession>) { | ||
| 1360 | return slab_heap_container->session; | ||
| 1361 | } else if constexpr (std::is_same_v<T, KSharedMemory>) { | ||
| 1362 | return slab_heap_container->shared_memory; | ||
| 1363 | } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) { | ||
| 1364 | return slab_heap_container->shared_memory_info; | ||
| 1365 | } else if constexpr (std::is_same_v<T, KThread>) { | ||
| 1366 | return slab_heap_container->thread; | ||
| 1367 | } else if constexpr (std::is_same_v<T, KTransferMemory>) { | ||
| 1368 | return slab_heap_container->transfer_memory; | ||
| 1369 | } else if constexpr (std::is_same_v<T, KCodeMemory>) { | ||
| 1370 | return slab_heap_container->code_memory; | ||
| 1371 | } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) { | ||
| 1372 | return slab_heap_container->device_address_space; | ||
| 1373 | } else if constexpr (std::is_same_v<T, KPageBuffer>) { | ||
| 1374 | return slab_heap_container->page_buffer; | ||
| 1375 | } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { | ||
| 1376 | return slab_heap_container->thread_local_page; | ||
| 1377 | } else if constexpr (std::is_same_v<T, KObjectName>) { | ||
| 1378 | return slab_heap_container->object_name; | ||
| 1379 | } else if constexpr (std::is_same_v<T, KSessionRequest>) { | ||
| 1380 | return slab_heap_container->session_request; | ||
| 1381 | } else if constexpr (std::is_same_v<T, KSecureSystemResource>) { | ||
| 1382 | return slab_heap_container->secure_system_resource; | ||
| 1383 | } else if constexpr (std::is_same_v<T, KThread::LockWithPriorityInheritanceInfo>) { | ||
| 1384 | return slab_heap_container->lock_info; | ||
| 1385 | } else if constexpr (std::is_same_v<T, KEventInfo>) { | ||
| 1386 | return slab_heap_container->event_info; | ||
| 1387 | } else if constexpr (std::is_same_v<T, KDebug>) { | ||
| 1388 | return slab_heap_container->debug; | ||
| 1389 | } | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | template KSlabHeap<KClientSession>& KernelCore::SlabHeap(); | ||
| 1393 | template KSlabHeap<KEvent>& KernelCore::SlabHeap(); | ||
| 1394 | template KSlabHeap<KLinkedListNode>& KernelCore::SlabHeap(); | ||
| 1395 | template KSlabHeap<KPort>& KernelCore::SlabHeap(); | ||
| 1396 | template KSlabHeap<KProcess>& KernelCore::SlabHeap(); | ||
| 1397 | template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap(); | ||
| 1398 | template KSlabHeap<KSession>& KernelCore::SlabHeap(); | ||
| 1399 | template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap(); | ||
| 1400 | template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap(); | ||
| 1401 | template KSlabHeap<KThread>& KernelCore::SlabHeap(); | ||
| 1402 | template KSlabHeap<KTransferMemory>& KernelCore::SlabHeap(); | ||
| 1403 | template KSlabHeap<KCodeMemory>& KernelCore::SlabHeap(); | ||
| 1404 | template KSlabHeap<KDeviceAddressSpace>& KernelCore::SlabHeap(); | ||
| 1405 | template KSlabHeap<KPageBuffer>& KernelCore::SlabHeap(); | ||
| 1406 | template KSlabHeap<KThreadLocalPage>& KernelCore::SlabHeap(); | ||
| 1407 | template KSlabHeap<KObjectName>& KernelCore::SlabHeap(); | ||
| 1408 | template KSlabHeap<KSessionRequest>& KernelCore::SlabHeap(); | ||
| 1409 | template KSlabHeap<KSecureSystemResource>& KernelCore::SlabHeap(); | ||
| 1410 | template KSlabHeap<KThread::LockWithPriorityInheritanceInfo>& KernelCore::SlabHeap(); | ||
| 1411 | template KSlabHeap<KEventInfo>& KernelCore::SlabHeap(); | ||
| 1412 | template KSlabHeap<KDebug>& KernelCore::SlabHeap(); | ||
| 1413 | |||
| 1321 | } // namespace Kernel | 1414 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4449f6949..1b380a07b 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -305,49 +305,7 @@ public: | |||
| 305 | 305 | ||
| 306 | /// Gets the slab heap for the specified kernel object type. | 306 | /// Gets the slab heap for the specified kernel object type. |
| 307 | template <typename T> | 307 | template <typename T> |
| 308 | KSlabHeap<T>& SlabHeap() { | 308 | KSlabHeap<T>& SlabHeap(); |
| 309 | if constexpr (std::is_same_v<T, KClientSession>) { | ||
| 310 | return slab_heap_container->client_session; | ||
| 311 | } else if constexpr (std::is_same_v<T, KEvent>) { | ||
| 312 | return slab_heap_container->event; | ||
| 313 | } else if constexpr (std::is_same_v<T, KLinkedListNode>) { | ||
| 314 | return slab_heap_container->linked_list_node; | ||
| 315 | } else if constexpr (std::is_same_v<T, KPort>) { | ||
| 316 | return slab_heap_container->port; | ||
| 317 | } else if constexpr (std::is_same_v<T, KProcess>) { | ||
| 318 | return slab_heap_container->process; | ||
| 319 | } else if constexpr (std::is_same_v<T, KResourceLimit>) { | ||
| 320 | return slab_heap_container->resource_limit; | ||
| 321 | } else if constexpr (std::is_same_v<T, KSession>) { | ||
| 322 | return slab_heap_container->session; | ||
| 323 | } else if constexpr (std::is_same_v<T, KSharedMemory>) { | ||
| 324 | return slab_heap_container->shared_memory; | ||
| 325 | } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) { | ||
| 326 | return slab_heap_container->shared_memory_info; | ||
| 327 | } else if constexpr (std::is_same_v<T, KThread>) { | ||
| 328 | return slab_heap_container->thread; | ||
| 329 | } else if constexpr (std::is_same_v<T, KTransferMemory>) { | ||
| 330 | return slab_heap_container->transfer_memory; | ||
| 331 | } else if constexpr (std::is_same_v<T, KCodeMemory>) { | ||
| 332 | return slab_heap_container->code_memory; | ||
| 333 | } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) { | ||
| 334 | return slab_heap_container->device_address_space; | ||
| 335 | } else if constexpr (std::is_same_v<T, KPageBuffer>) { | ||
| 336 | return slab_heap_container->page_buffer; | ||
| 337 | } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { | ||
| 338 | return slab_heap_container->thread_local_page; | ||
| 339 | } else if constexpr (std::is_same_v<T, KObjectName>) { | ||
| 340 | return slab_heap_container->object_name; | ||
| 341 | } else if constexpr (std::is_same_v<T, KSessionRequest>) { | ||
| 342 | return slab_heap_container->session_request; | ||
| 343 | } else if constexpr (std::is_same_v<T, KSecureSystemResource>) { | ||
| 344 | return slab_heap_container->secure_system_resource; | ||
| 345 | } else if constexpr (std::is_same_v<T, KEventInfo>) { | ||
| 346 | return slab_heap_container->event_info; | ||
| 347 | } else if constexpr (std::is_same_v<T, KDebug>) { | ||
| 348 | return slab_heap_container->debug; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | 309 | ||
| 352 | /// Gets the current slab resource counts. | 310 | /// Gets the current slab resource counts. |
| 353 | Init::KSlabResourceCounts& SlabResourceCounts(); | 311 | Init::KSlabResourceCounts& SlabResourceCounts(); |
| @@ -393,28 +351,7 @@ private: | |||
| 393 | 351 | ||
| 394 | private: | 352 | private: |
| 395 | /// Helper to encapsulate all slab heaps in a single heap allocated container | 353 | /// Helper to encapsulate all slab heaps in a single heap allocated container |
| 396 | struct SlabHeapContainer { | 354 | struct SlabHeapContainer; |
| 397 | KSlabHeap<KClientSession> client_session; | ||
| 398 | KSlabHeap<KEvent> event; | ||
| 399 | KSlabHeap<KLinkedListNode> linked_list_node; | ||
| 400 | KSlabHeap<KPort> port; | ||
| 401 | KSlabHeap<KProcess> process; | ||
| 402 | KSlabHeap<KResourceLimit> resource_limit; | ||
| 403 | KSlabHeap<KSession> session; | ||
| 404 | KSlabHeap<KSharedMemory> shared_memory; | ||
| 405 | KSlabHeap<KSharedMemoryInfo> shared_memory_info; | ||
| 406 | KSlabHeap<KThread> thread; | ||
| 407 | KSlabHeap<KTransferMemory> transfer_memory; | ||
| 408 | KSlabHeap<KCodeMemory> code_memory; | ||
| 409 | KSlabHeap<KDeviceAddressSpace> device_address_space; | ||
| 410 | KSlabHeap<KPageBuffer> page_buffer; | ||
| 411 | KSlabHeap<KThreadLocalPage> thread_local_page; | ||
| 412 | KSlabHeap<KObjectName> object_name; | ||
| 413 | KSlabHeap<KSessionRequest> session_request; | ||
| 414 | KSlabHeap<KSecureSystemResource> secure_system_resource; | ||
| 415 | KSlabHeap<KEventInfo> event_info; | ||
| 416 | KSlabHeap<KDebug> debug; | ||
| 417 | }; | ||
| 418 | 355 | ||
| 419 | std::unique_ptr<SlabHeapContainer> slab_heap_container; | 356 | std::unique_ptr<SlabHeapContainer> slab_heap_container; |
| 420 | }; | 357 | }; |
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 542c13461..39355d9c4 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h | |||
| @@ -151,6 +151,7 @@ enum class InfoType : u32 { | |||
| 151 | FreeThreadCount = 24, | 151 | FreeThreadCount = 24, |
| 152 | ThreadTickCount = 25, | 152 | ThreadTickCount = 25, |
| 153 | IsSvcPermitted = 26, | 153 | IsSvcPermitted = 26, |
| 154 | IoRegionHint = 27, | ||
| 154 | 155 | ||
| 155 | MesosphereMeta = 65000, | 156 | MesosphereMeta = 65000, |
| 156 | MesosphereCurrentProcess = 65001, | 157 | MesosphereCurrentProcess = 65001, |