Merge pull request #2211 from lioncash/arbiter
kernel: Make the address arbiter instance per-process
This commit is contained in:
commit
3bfd199497
9 changed files with 81 additions and 65 deletions
|
@ -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>();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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!");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue