diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 117 | ||||
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.h | 68 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 14 | 
5 files changed, 135 insertions, 82 deletions
| diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index a250d088d..f14283cca 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -9,6 +9,7 @@  #include "common/common_types.h"  #include "core/core.h"  #include "core/core_cpu.h" +#include "core/hle/kernel/address_arbiter.h"  #include "core/hle/kernel/errors.h"  #include "core/hle/kernel/object.h"  #include "core/hle/kernel/process.h" @@ -17,53 +18,10 @@  #include "core/hle/result.h"  #include "core/memory.h" -namespace Kernel::AddressArbiter { - -// Performs actual address waiting logic. -static ResultCode WaitForAddress(VAddr address, s64 timeout) { -    SharedPtr<Thread> current_thread = GetCurrentThread(); -    current_thread->SetArbiterWaitAddress(address); -    current_thread->SetStatus(ThreadStatus::WaitArb); -    current_thread->InvalidateWakeupCallback(); - -    current_thread->WakeAfterDelay(timeout); - -    Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); -    return RESULT_TIMEOUT; -} - -// Gets the threads waiting on an address. -static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) { -    const auto RetrieveWaitingThreads = [](std::size_t core_index, -                                           std::vector<SharedPtr<Thread>>& waiting_threads, -                                           VAddr arb_addr) { -        const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); -        const auto& thread_list = scheduler.GetThreadList(); - -        for (const auto& thread : thread_list) { -            if (thread->GetArbiterWaitAddress() == arb_addr) -                waiting_threads.push_back(thread); -        } -    }; - -    // Retrieve all threads that are waiting for this address. -    std::vector<SharedPtr<Thread>> threads; -    RetrieveWaitingThreads(0, threads, address); -    RetrieveWaitingThreads(1, threads, address); -    RetrieveWaitingThreads(2, threads, address); -    RetrieveWaitingThreads(3, threads, address); - -    // Sort them by priority, such that the highest priority ones come first. -    std::sort(threads.begin(), threads.end(), -              [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { -                  return lhs->GetPriority() < rhs->GetPriority(); -              }); - -    return threads; -} - +namespace Kernel { +namespace {  // Wake up num_to_wake (or all) threads in a vector. -static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { +void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {      // Only process up to 'target' threads, unless 'target' is <= 0, in which case process      // them all.      std::size_t last = waiting_threads.size(); @@ -78,17 +36,20 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num          waiting_threads[i]->ResumeFromWait();      }  } +} // Anonymous namespace -// Signals an address being waited on. -ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { +AddressArbiter::AddressArbiter() = default; +AddressArbiter::~AddressArbiter() = default; + +ResultCode AddressArbiter::SignalToAddress(VAddr address, s32 num_to_wake) {      std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);      WakeThreads(waiting_threads, num_to_wake);      return RESULT_SUCCESS;  } -// Signals an address being waited on and increments its value if equal to the value argument. -ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { +ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, +                                                              s32 num_to_wake) {      // Ensure that we can write to the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE; @@ -103,10 +64,8 @@ ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_      return SignalToAddress(address, num_to_wake);  } -// Signals an address being waited on and modifies its value based on waiting thread count if equal -// to the value argument. -ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, -                                                         s32 num_to_wake) { +ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, +                                                                         s32 num_to_wake) {      // Ensure that we can write to the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE; @@ -135,8 +94,8 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu      return RESULT_SUCCESS;  } -// Waits on an address if the value passed is less than the argument value, optionally decrementing. -ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { +ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, +                                                    bool should_decrement) {      // Ensure that we can read the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE; @@ -158,8 +117,7 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool      return WaitForAddress(address, timeout);  } -// Waits on an address if the value passed is equal to the argument value. -ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { +ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {      // Ensure that we can read the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE; @@ -175,4 +133,45 @@ ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {      return WaitForAddress(address, timeout);  } -} // namespace Kernel::AddressArbiter + +ResultCode AddressArbiter::WaitForAddress(VAddr address, s64 timeout) { +    SharedPtr<Thread> current_thread = GetCurrentThread(); +    current_thread->SetArbiterWaitAddress(address); +    current_thread->SetStatus(ThreadStatus::WaitArb); +    current_thread->InvalidateWakeupCallback(); + +    current_thread->WakeAfterDelay(timeout); + +    Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); +    return RESULT_TIMEOUT; +} + +std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) const { +    const auto RetrieveWaitingThreads = [](std::size_t core_index, +                                           std::vector<SharedPtr<Thread>>& waiting_threads, +                                           VAddr arb_addr) { +        const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); +        const auto& thread_list = scheduler.GetThreadList(); + +        for (const auto& thread : thread_list) { +            if (thread->GetArbiterWaitAddress() == arb_addr) +                waiting_threads.push_back(thread); +        } +    }; + +    // Retrieve all threads that are waiting for this address. +    std::vector<SharedPtr<Thread>> threads; +    RetrieveWaitingThreads(0, threads, address); +    RetrieveWaitingThreads(1, threads, address); +    RetrieveWaitingThreads(2, threads, address); +    RetrieveWaitingThreads(3, threads, address); + +    // Sort them by priority, such that the highest priority ones come first. +    std::sort(threads.begin(), threads.end(), +              [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { +                  return lhs->GetPriority() < rhs->GetPriority(); +              }); + +    return threads; +} +} // namespace Kernel diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index b58f21bec..6f46190f6 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -5,28 +5,62 @@  #pragma once  #include "common/common_types.h" +#include "core/hle/kernel/address_arbiter.h"  union ResultCode; -namespace Kernel::AddressArbiter { +namespace Kernel { -enum class ArbitrationType { -    WaitIfLessThan = 0, -    DecrementAndWaitIfLessThan = 1, -    WaitIfEqual = 2, -}; +class Thread; -enum class SignalType { -    Signal = 0, -    IncrementAndSignalIfEqual = 1, -    ModifyByWaitingCountAndSignalIfEqual = 2, -}; +class AddressArbiter { +public: +    enum class ArbitrationType { +        WaitIfLessThan = 0, +        DecrementAndWaitIfLessThan = 1, +        WaitIfEqual = 2, +    }; + +    enum class SignalType { +        Signal = 0, +        IncrementAndSignalIfEqual = 1, +        ModifyByWaitingCountAndSignalIfEqual = 2, +    }; + +    AddressArbiter(); +    ~AddressArbiter(); + +    AddressArbiter(const AddressArbiter&) = delete; +    AddressArbiter& operator=(const AddressArbiter&) = delete; + +    AddressArbiter(AddressArbiter&&) = default; +    AddressArbiter& operator=(AddressArbiter&&) = delete; -ResultCode SignalToAddress(VAddr address, s32 num_to_wake); -ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); -ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); +    /// Signals an address being waited on. +    ResultCode SignalToAddress(VAddr address, s32 num_to_wake); -ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement); -ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); +    /// Signals an address being waited on and increments its value if equal to the value argument. +    ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); + +    /// Signals an address being waited on and modifies its value based on waiting thread count if +    /// equal to the value argument. +    ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, +                                                             s32 num_to_wake); + +    /// Waits on an address if the value passed is less than the argument value, +    /// optionally decrementing. +    ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, +                                        bool should_decrement); + +    /// Waits on an address if the value passed is equal to the argument value. +    ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); + +private: +    // Waits on the given address with a timeout in nanoseconds +    ResultCode WaitForAddress(VAddr address, s64 timeout); + +    // Gets the threads waiting on an address. +    std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; +}; -} // namespace Kernel::AddressArbiter +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index dd749eed4..b771a33a6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -12,6 +12,7 @@  #include "core/core.h"  #include "core/core_timing.h" +#include "core/hle/kernel/address_arbiter.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/kernel.h" @@ -135,6 +136,8 @@ struct KernelCore::Impl {      std::vector<SharedPtr<Process>> process_list;      Process* current_process = nullptr; +    Kernel::AddressArbiter address_arbiter; +      SharedPtr<ResourceLimit> system_resource_limit;      Core::Timing::EventType* thread_wakeup_event_type = nullptr; @@ -184,6 +187,14 @@ const Process* KernelCore::CurrentProcess() const {      return impl->current_process;  } +AddressArbiter& KernelCore::AddressArbiter() { +    return impl->address_arbiter; +} + +const AddressArbiter& KernelCore::AddressArbiter() const { +    return impl->address_arbiter; +} +  void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {      impl->named_ports.emplace(std::move(name), std::move(port));  } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 154bced42..32b8ede0e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -18,6 +18,7 @@ struct EventType;  namespace Kernel { +class AddressArbiter;  class ClientPort;  class HandleTable;  class Process; @@ -67,6 +68,12 @@ public:      /// Retrieves a const pointer to the current process.      const Process* CurrentProcess() const; +    /// Provides a reference to the kernel's address arbiter. +    Kernel::AddressArbiter& AddressArbiter(); + +    /// Provides a const reference to the kernel's address arbiter. +    const Kernel::AddressArbiter& AddressArbiter() const; +      /// Adds a port to the named port table      void AddNamedPort(std::string name, SharedPtr<ClientPort> port); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c5d399bab..b7546087e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1495,13 +1495,14 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout          return ERR_INVALID_ADDRESS;      } +    auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();      switch (static_cast<AddressArbiter::ArbitrationType>(type)) {      case AddressArbiter::ArbitrationType::WaitIfLessThan: -        return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false); +        return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false);      case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: -        return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true); +        return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true);      case AddressArbiter::ArbitrationType::WaitIfEqual: -        return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); +        return address_arbiter.WaitForAddressIfEqual(address, value, timeout);      default:          LOG_ERROR(Kernel_SVC,                    "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " @@ -1526,13 +1527,14 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to          return ERR_INVALID_ADDRESS;      } +    auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();      switch (static_cast<AddressArbiter::SignalType>(type)) {      case AddressArbiter::SignalType::Signal: -        return AddressArbiter::SignalToAddress(address, num_to_wake); +        return address_arbiter.SignalToAddress(address, num_to_wake);      case AddressArbiter::SignalType::IncrementAndSignalIfEqual: -        return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); +        return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);      case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: -        return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, +        return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,                                                                               num_to_wake);      default:          LOG_ERROR(Kernel_SVC, | 
