Merge pull request #2211 from lioncash/arbiter

kernel: Make the address arbiter instance per-process
This commit is contained in:
bunnei 2019-03-12 17:54:48 -04:00 committed by GitHub
commit 3bfd199497
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 81 additions and 65 deletions

View File

@ -116,7 +116,7 @@ struct System::Impl {
if (web_browser == nullptr) if (web_browser == nullptr)
web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
auto main_process = Kernel::Process::Create(kernel, "main"); auto main_process = Kernel::Process::Create(system, "main");
kernel.MakeCurrentProcess(main_process.get()); kernel.MakeCurrentProcess(main_process.get());
telemetry_session = std::make_unique<Core::TelemetrySession>(); telemetry_session = std::make_unique<Core::TelemetrySession>();

View File

@ -42,7 +42,21 @@ void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_
AddressArbiter::AddressArbiter(Core::System& system) : system{system} {} AddressArbiter::AddressArbiter(Core::System& system) : system{system} {}
AddressArbiter::~AddressArbiter() = default; AddressArbiter::~AddressArbiter() = default;
ResultCode AddressArbiter::SignalToAddress(VAddr address, s32 num_to_wake) { ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 value,
s32 num_to_wake) {
switch (type) {
case SignalType::Signal:
return SignalToAddressOnly(address, num_to_wake);
case SignalType::IncrementAndSignalIfEqual:
return IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
case SignalType::ModifyByWaitingCountAndSignalIfEqual:
return ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, num_to_wake);
default:
return ERR_INVALID_ENUM_VALUE;
}
}
ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
WakeThreads(waiting_threads, num_to_wake); WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -60,7 +74,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
} }
Memory::Write32(address, static_cast<u32>(value + 1)); Memory::Write32(address, static_cast<u32>(value + 1));
return SignalToAddress(address, num_to_wake); return SignalToAddressOnly(address, num_to_wake);
} }
ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
@ -92,6 +106,20 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s32 value,
s64 timeout_ns) {
switch (type) {
case ArbitrationType::WaitIfLessThan:
return WaitForAddressIfLessThan(address, value, timeout_ns, false);
case ArbitrationType::DecrementAndWaitIfLessThan:
return WaitForAddressIfLessThan(address, value, timeout_ns, true);
case ArbitrationType::WaitIfEqual:
return WaitForAddressIfEqual(address, value, timeout_ns);
default:
return ERR_INVALID_ENUM_VALUE;
}
}
ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
bool should_decrement) { bool should_decrement) {
// Ensure that we can read the address. // Ensure that we can read the address.
@ -113,7 +141,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
return RESULT_TIMEOUT; return RESULT_TIMEOUT;
} }
return WaitForAddress(address, timeout); return WaitForAddressImpl(address, timeout);
} }
ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
@ -130,10 +158,10 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
return RESULT_TIMEOUT; return RESULT_TIMEOUT;
} }
return WaitForAddress(address, timeout); return WaitForAddressImpl(address, timeout);
} }
ResultCode AddressArbiter::WaitForAddress(VAddr address, s64 timeout) { ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) {
SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread();
current_thread->SetArbiterWaitAddress(address); current_thread->SetArbiterWaitAddress(address);
current_thread->SetStatus(ThreadStatus::WaitArb); current_thread->SetStatus(ThreadStatus::WaitArb);

View File

@ -4,8 +4,10 @@
#pragma once #pragma once
#include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/object.h"
union ResultCode; union ResultCode;
@ -40,8 +42,15 @@ public:
AddressArbiter(AddressArbiter&&) = default; AddressArbiter(AddressArbiter&&) = default;
AddressArbiter& operator=(AddressArbiter&&) = delete; AddressArbiter& operator=(AddressArbiter&&) = delete;
/// Signals an address being waited on with a particular signaling type.
ResultCode SignalToAddress(VAddr address, SignalType type, s32 value, s32 num_to_wake);
/// Waits on an address with a particular arbitration type.
ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns);
private:
/// Signals an address being waited on. /// Signals an address being waited on.
ResultCode SignalToAddress(VAddr address, s32 num_to_wake); ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake);
/// Signals an address being waited on and increments its value if equal to the value argument. /// 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 IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
@ -59,9 +68,8 @@ public:
/// Waits on an address if the value passed is equal to the argument value. /// Waits on an address if the value passed is equal to the argument value.
ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
private:
// Waits on the given address with a timeout in nanoseconds // Waits on the given address with a timeout in nanoseconds
ResultCode WaitForAddress(VAddr address, s64 timeout); ResultCode WaitForAddressImpl(VAddr address, s64 timeout);
// Gets the threads waiting on an address. // Gets the threads waiting on an address.
std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;

View File

@ -87,7 +87,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
} }
struct KernelCore::Impl { struct KernelCore::Impl {
explicit Impl(Core::System& system) : address_arbiter{system}, system{system} {} explicit Impl(Core::System& system) : system{system} {}
void Initialize(KernelCore& kernel) { void Initialize(KernelCore& kernel) {
Shutdown(); Shutdown();
@ -138,8 +138,6 @@ struct KernelCore::Impl {
std::vector<SharedPtr<Process>> process_list; std::vector<SharedPtr<Process>> process_list;
Process* current_process = nullptr; Process* current_process = nullptr;
Kernel::AddressArbiter address_arbiter;
SharedPtr<ResourceLimit> system_resource_limit; SharedPtr<ResourceLimit> system_resource_limit;
Core::Timing::EventType* thread_wakeup_event_type = nullptr; Core::Timing::EventType* thread_wakeup_event_type = nullptr;
@ -192,14 +190,6 @@ const Process* KernelCore::CurrentProcess() const {
return impl->current_process; 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) { void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
impl->named_ports.emplace(std::move(name), std::move(port)); impl->named_ports.emplace(std::move(name), std::move(port));
} }

View File

@ -75,12 +75,6 @@ public:
/// Retrieves a const pointer to the current process. /// Retrieves a const pointer to the current process.
const Process* CurrentProcess() const; 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 /// Adds a port to the named port table
void AddNamedPort(std::string name, SharedPtr<ClientPort> port); void AddNamedPort(std::string name, SharedPtr<ClientPort> port);

View File

@ -53,9 +53,10 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_poi
CodeSet::CodeSet() = default; CodeSet::CodeSet() = default;
CodeSet::~CodeSet() = default; CodeSet::~CodeSet() = default;
SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) {
SharedPtr<Process> process(new Process(kernel)); auto& kernel = system.Kernel();
SharedPtr<Process> process(new Process(system));
process->name = std::move(name); process->name = std::move(name);
process->resource_limit = kernel.GetSystemResourceLimit(); process->resource_limit = kernel.GetSystemResourceLimit();
process->status = ProcessStatus::Created; process->status = ProcessStatus::Created;
@ -233,8 +234,8 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
} }
Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {} Process::Process(Core::System& system) : WaitObject{system.Kernel()}, address_arbiter{system} {}
Kernel::Process::~Process() {} Process::~Process() = default;
void Process::Acquire(Thread* thread) { void Process::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "Object unavailable!"); ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");

View File

@ -12,12 +12,17 @@
#include <vector> #include <vector>
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/vm_manager.h" #include "core/hle/kernel/vm_manager.h"
#include "core/hle/kernel/wait_object.h" #include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h" #include "core/hle/result.h"
namespace Core {
class System;
}
namespace FileSys { namespace FileSys {
class ProgramMetadata; class ProgramMetadata;
} }
@ -116,7 +121,7 @@ public:
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); static SharedPtr<Process> Create(Core::System& system, std::string&& name);
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "Process"; return "Process";
@ -150,6 +155,16 @@ public:
return handle_table; return handle_table;
} }
/// Gets a reference to the process' address arbiter.
AddressArbiter& GetAddressArbiter() {
return address_arbiter;
}
/// Gets a const reference to the process' address arbiter.
const AddressArbiter& GetAddressArbiter() const {
return address_arbiter;
}
/// Gets the current status of the process /// Gets the current status of the process
ProcessStatus GetStatus() const { ProcessStatus GetStatus() const {
return status; return status;
@ -251,7 +266,7 @@ public:
void FreeTLSSlot(VAddr tls_address); void FreeTLSSlot(VAddr tls_address);
private: private:
explicit Process(KernelCore& kernel); explicit Process(Core::System& kernel);
~Process() override; ~Process() override;
/// Checks if the specified thread should wait until this process is available. /// Checks if the specified thread should wait until this process is available.
@ -309,6 +324,9 @@ private:
/// Per-process handle table for storing created object handles in. /// Per-process handle table for storing created object handles in.
HandleTable handle_table; HandleTable handle_table;
/// Per-process address arbiter.
AddressArbiter address_arbiter;
/// Random values for svcGetInfo RandomEntropy /// Random values for svcGetInfo RandomEntropy
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;

View File

@ -1479,21 +1479,10 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
return ERR_INVALID_ADDRESS; return ERR_INVALID_ADDRESS;
} }
auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type);
switch (static_cast<AddressArbiter::ArbitrationType>(type)) { auto& address_arbiter =
case AddressArbiter::ArbitrationType::WaitIfLessThan: Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter();
return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false); return address_arbiter.WaitForAddress(address, arbitration_type, value, timeout);
case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan:
return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true);
case AddressArbiter::ArbitrationType::WaitIfEqual:
return address_arbiter.WaitForAddressIfEqual(address, value, timeout);
default:
LOG_ERROR(Kernel_SVC,
"Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan "
"or WaitIfEqual but got {}",
type);
return ERR_INVALID_ENUM_VALUE;
}
} }
// Signals to an address (via Address Arbiter) // Signals to an address (via Address Arbiter)
@ -1511,22 +1500,10 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
return ERR_INVALID_ADDRESS; return ERR_INVALID_ADDRESS;
} }
auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); const auto signal_type = static_cast<AddressArbiter::SignalType>(type);
switch (static_cast<AddressArbiter::SignalType>(type)) { auto& address_arbiter =
case AddressArbiter::SignalType::Signal: Core::System::GetInstance().Kernel().CurrentProcess()->GetAddressArbiter();
return address_arbiter.SignalToAddress(address, num_to_wake); return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake);
case AddressArbiter::SignalType::IncrementAndSignalIfEqual:
return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual:
return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
num_to_wake);
default:
LOG_ERROR(Kernel_SVC,
"Invalid signal type, expected Signal, IncrementAndSignalIfEqual "
"or ModifyByWaitingCountAndSignalIfEqual but got {}",
type);
return ERR_INVALID_ENUM_VALUE;
}
} }
/// This returns the total CPU ticks elapsed since the CPU was powered-on /// This returns the total CPU ticks elapsed since the CPU was powered-on

View File

@ -15,7 +15,7 @@ namespace ArmTests {
TestEnvironment::TestEnvironment(bool mutable_memory_) TestEnvironment::TestEnvironment(bool mutable_memory_)
: mutable_memory(mutable_memory_), : mutable_memory(mutable_memory_),
test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} { test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
auto process = Kernel::Process::Create(kernel, ""); auto process = Kernel::Process::Create(Core::System::GetInstance(), "");
kernel.MakeCurrentProcess(process.get()); kernel.MakeCurrentProcess(process.get());
page_table = &process->VMManager().page_table; page_table = &process->VMManager().page_table;