summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorGravatar Lioncash2019-03-05 11:54:06 -0500
committerGravatar Lioncash2019-03-05 12:58:26 -0500
commitec6664f6d61f46569a2686b864ba3e9a0f85fc60 (patch)
tree67a78607f085efd3e4258fd90afd2aa2036d0448 /src/core/hle/kernel
parentMerge pull request #2185 from FearlessTobi/port-4630 (diff)
downloadyuzu-ec6664f6d61f46569a2686b864ba3e9a0f85fc60.tar.gz
yuzu-ec6664f6d61f46569a2686b864ba3e9a0f85fc60.tar.xz
yuzu-ec6664f6d61f46569a2686b864ba3e9a0f85fc60.zip
kernel/address_arbiter: Convert the address arbiter into a class
Places all of the functions for address arbiter operation into a class. This will be necessary for future deglobalizing efforts related to both the memory and system itself.
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp117
-rw-r--r--src/core/hle/kernel/address_arbiter.h68
-rw-r--r--src/core/hle/kernel/kernel.cpp11
-rw-r--r--src/core/hle/kernel/kernel.h7
-rw-r--r--src/core/hle/kernel/svc.cpp14
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 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/core_cpu.h" 11#include "core/core_cpu.h"
12#include "core/hle/kernel/address_arbiter.h"
12#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
13#include "core/hle/kernel/object.h" 14#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
@@ -17,53 +18,10 @@
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18#include "core/memory.h" 19#include "core/memory.h"
19 20
20namespace Kernel::AddressArbiter { 21namespace Kernel {
21 22namespace {
22// Performs actual address waiting logic.
23static ResultCode WaitForAddress(VAddr address, s64 timeout) {
24 SharedPtr<Thread> current_thread = GetCurrentThread();
25 current_thread->SetArbiterWaitAddress(address);
26 current_thread->SetStatus(ThreadStatus::WaitArb);
27 current_thread->InvalidateWakeupCallback();
28
29 current_thread->WakeAfterDelay(timeout);
30
31 Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
32 return RESULT_TIMEOUT;
33}
34
35// Gets the threads waiting on an address.
36static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) {
37 const auto RetrieveWaitingThreads = [](std::size_t core_index,
38 std::vector<SharedPtr<Thread>>& waiting_threads,
39 VAddr arb_addr) {
40 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
41 const auto& thread_list = scheduler.GetThreadList();
42
43 for (const auto& thread : thread_list) {
44 if (thread->GetArbiterWaitAddress() == arb_addr)
45 waiting_threads.push_back(thread);
46 }
47 };
48
49 // Retrieve all threads that are waiting for this address.
50 std::vector<SharedPtr<Thread>> threads;
51 RetrieveWaitingThreads(0, threads, address);
52 RetrieveWaitingThreads(1, threads, address);
53 RetrieveWaitingThreads(2, threads, address);
54 RetrieveWaitingThreads(3, threads, address);
55
56 // Sort them by priority, such that the highest priority ones come first.
57 std::sort(threads.begin(), threads.end(),
58 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
59 return lhs->GetPriority() < rhs->GetPriority();
60 });
61
62 return threads;
63}
64
65// Wake up num_to_wake (or all) threads in a vector. 23// Wake up num_to_wake (or all) threads in a vector.
66static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { 24void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {
67 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process 25 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
68 // them all. 26 // them all.
69 std::size_t last = waiting_threads.size(); 27 std::size_t last = waiting_threads.size();
@@ -78,17 +36,20 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num
78 waiting_threads[i]->ResumeFromWait(); 36 waiting_threads[i]->ResumeFromWait();
79 } 37 }
80} 38}
39} // Anonymous namespace
81 40
82// Signals an address being waited on. 41AddressArbiter::AddressArbiter() = default;
83ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { 42AddressArbiter::~AddressArbiter() = default;
43
44ResultCode AddressArbiter::SignalToAddress(VAddr address, s32 num_to_wake) {
84 std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); 45 std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
85 46
86 WakeThreads(waiting_threads, num_to_wake); 47 WakeThreads(waiting_threads, num_to_wake);
87 return RESULT_SUCCESS; 48 return RESULT_SUCCESS;
88} 49}
89 50
90// Signals an address being waited on and increments its value if equal to the value argument. 51ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value,
91ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { 52 s32 num_to_wake) {
92 // Ensure that we can write to the address. 53 // Ensure that we can write to the address.
93 if (!Memory::IsValidVirtualAddress(address)) { 54 if (!Memory::IsValidVirtualAddress(address)) {
94 return ERR_INVALID_ADDRESS_STATE; 55 return ERR_INVALID_ADDRESS_STATE;
@@ -103,10 +64,8 @@ ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_
103 return SignalToAddress(address, num_to_wake); 64 return SignalToAddress(address, num_to_wake);
104} 65}
105 66
106// Signals an address being waited on and modifies its value based on waiting thread count if equal 67ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
107// to the value argument. 68 s32 num_to_wake) {
108ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
109 s32 num_to_wake) {
110 // Ensure that we can write to the address. 69 // Ensure that we can write to the address.
111 if (!Memory::IsValidVirtualAddress(address)) { 70 if (!Memory::IsValidVirtualAddress(address)) {
112 return ERR_INVALID_ADDRESS_STATE; 71 return ERR_INVALID_ADDRESS_STATE;
@@ -135,8 +94,8 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
135 return RESULT_SUCCESS; 94 return RESULT_SUCCESS;
136} 95}
137 96
138// Waits on an address if the value passed is less than the argument value, optionally decrementing. 97ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
139ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { 98 bool should_decrement) {
140 // Ensure that we can read the address. 99 // Ensure that we can read the address.
141 if (!Memory::IsValidVirtualAddress(address)) { 100 if (!Memory::IsValidVirtualAddress(address)) {
142 return ERR_INVALID_ADDRESS_STATE; 101 return ERR_INVALID_ADDRESS_STATE;
@@ -158,8 +117,7 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool
158 return WaitForAddress(address, timeout); 117 return WaitForAddress(address, timeout);
159} 118}
160 119
161// Waits on an address if the value passed is equal to the argument value. 120ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
162ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
163 // Ensure that we can read the address. 121 // Ensure that we can read the address.
164 if (!Memory::IsValidVirtualAddress(address)) { 122 if (!Memory::IsValidVirtualAddress(address)) {
165 return ERR_INVALID_ADDRESS_STATE; 123 return ERR_INVALID_ADDRESS_STATE;
@@ -175,4 +133,45 @@ ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
175 133
176 return WaitForAddress(address, timeout); 134 return WaitForAddress(address, timeout);
177} 135}
178} // namespace Kernel::AddressArbiter 136
137ResultCode AddressArbiter::WaitForAddress(VAddr address, s64 timeout) {
138 SharedPtr<Thread> current_thread = GetCurrentThread();
139 current_thread->SetArbiterWaitAddress(address);
140 current_thread->SetStatus(ThreadStatus::WaitArb);
141 current_thread->InvalidateWakeupCallback();
142
143 current_thread->WakeAfterDelay(timeout);
144
145 Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
146 return RESULT_TIMEOUT;
147}
148
149std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) const {
150 const auto RetrieveWaitingThreads = [](std::size_t core_index,
151 std::vector<SharedPtr<Thread>>& waiting_threads,
152 VAddr arb_addr) {
153 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
154 const auto& thread_list = scheduler.GetThreadList();
155
156 for (const auto& thread : thread_list) {
157 if (thread->GetArbiterWaitAddress() == arb_addr)
158 waiting_threads.push_back(thread);
159 }
160 };
161
162 // Retrieve all threads that are waiting for this address.
163 std::vector<SharedPtr<Thread>> threads;
164 RetrieveWaitingThreads(0, threads, address);
165 RetrieveWaitingThreads(1, threads, address);
166 RetrieveWaitingThreads(2, threads, address);
167 RetrieveWaitingThreads(3, threads, address);
168
169 // Sort them by priority, such that the highest priority ones come first.
170 std::sort(threads.begin(), threads.end(),
171 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
172 return lhs->GetPriority() < rhs->GetPriority();
173 });
174
175 return threads;
176}
177} // 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 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/address_arbiter.h"
8 9
9union ResultCode; 10union ResultCode;
10 11
11namespace Kernel::AddressArbiter { 12namespace Kernel {
12 13
13enum class ArbitrationType { 14class Thread;
14 WaitIfLessThan = 0,
15 DecrementAndWaitIfLessThan = 1,
16 WaitIfEqual = 2,
17};
18 15
19enum class SignalType { 16class AddressArbiter {
20 Signal = 0, 17public:
21 IncrementAndSignalIfEqual = 1, 18 enum class ArbitrationType {
22 ModifyByWaitingCountAndSignalIfEqual = 2, 19 WaitIfLessThan = 0,
23}; 20 DecrementAndWaitIfLessThan = 1,
21 WaitIfEqual = 2,
22 };
23
24 enum class SignalType {
25 Signal = 0,
26 IncrementAndSignalIfEqual = 1,
27 ModifyByWaitingCountAndSignalIfEqual = 2,
28 };
29
30 AddressArbiter();
31 ~AddressArbiter();
32
33 AddressArbiter(const AddressArbiter&) = delete;
34 AddressArbiter& operator=(const AddressArbiter&) = delete;
35
36 AddressArbiter(AddressArbiter&&) = default;
37 AddressArbiter& operator=(AddressArbiter&&) = delete;
24 38
25ResultCode SignalToAddress(VAddr address, s32 num_to_wake); 39 /// Signals an address being waited on.
26ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); 40 ResultCode SignalToAddress(VAddr address, s32 num_to_wake);
27ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
28 41
29ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement); 42 /// Signals an address being waited on and increments its value if equal to the value argument.
30ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); 43 ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
44
45 /// Signals an address being waited on and modifies its value based on waiting thread count if
46 /// equal to the value argument.
47 ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
48 s32 num_to_wake);
49
50 /// Waits on an address if the value passed is less than the argument value,
51 /// optionally decrementing.
52 ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
53 bool should_decrement);
54
55 /// Waits on an address if the value passed is equal to the argument value.
56 ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
57
58private:
59 // Waits on the given address with a timeout in nanoseconds
60 ResultCode WaitForAddress(VAddr address, s64 timeout);
61
62 // Gets the threads waiting on an address.
63 std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;
64};
31 65
32} // namespace Kernel::AddressArbiter 66} // 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 @@
12 12
13#include "core/core.h" 13#include "core/core.h"
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/hle/kernel/address_arbiter.h"
15#include "core/hle/kernel/client_port.h" 16#include "core/hle/kernel/client_port.h"
16#include "core/hle/kernel/handle_table.h" 17#include "core/hle/kernel/handle_table.h"
17#include "core/hle/kernel/kernel.h" 18#include "core/hle/kernel/kernel.h"
@@ -135,6 +136,8 @@ struct KernelCore::Impl {
135 std::vector<SharedPtr<Process>> process_list; 136 std::vector<SharedPtr<Process>> process_list;
136 Process* current_process = nullptr; 137 Process* current_process = nullptr;
137 138
139 Kernel::AddressArbiter address_arbiter;
140
138 SharedPtr<ResourceLimit> system_resource_limit; 141 SharedPtr<ResourceLimit> system_resource_limit;
139 142
140 Core::Timing::EventType* thread_wakeup_event_type = nullptr; 143 Core::Timing::EventType* thread_wakeup_event_type = nullptr;
@@ -184,6 +187,14 @@ const Process* KernelCore::CurrentProcess() const {
184 return impl->current_process; 187 return impl->current_process;
185} 188}
186 189
190AddressArbiter& KernelCore::AddressArbiter() {
191 return impl->address_arbiter;
192}
193
194const AddressArbiter& KernelCore::AddressArbiter() const {
195 return impl->address_arbiter;
196}
197
187void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { 198void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
188 impl->named_ports.emplace(std::move(name), std::move(port)); 199 impl->named_ports.emplace(std::move(name), std::move(port));
189} 200}
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;
18 18
19namespace Kernel { 19namespace Kernel {
20 20
21class AddressArbiter;
21class ClientPort; 22class ClientPort;
22class HandleTable; 23class HandleTable;
23class Process; 24class Process;
@@ -67,6 +68,12 @@ public:
67 /// Retrieves a const pointer to the current process. 68 /// Retrieves a const pointer to the current process.
68 const Process* CurrentProcess() const; 69 const Process* CurrentProcess() const;
69 70
71 /// Provides a reference to the kernel's address arbiter.
72 Kernel::AddressArbiter& AddressArbiter();
73
74 /// Provides a const reference to the kernel's address arbiter.
75 const Kernel::AddressArbiter& AddressArbiter() const;
76
70 /// Adds a port to the named port table 77 /// Adds a port to the named port table
71 void AddNamedPort(std::string name, SharedPtr<ClientPort> port); 78 void AddNamedPort(std::string name, SharedPtr<ClientPort> port);
72 79
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
1495 return ERR_INVALID_ADDRESS; 1495 return ERR_INVALID_ADDRESS;
1496 } 1496 }
1497 1497
1498 auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();
1498 switch (static_cast<AddressArbiter::ArbitrationType>(type)) { 1499 switch (static_cast<AddressArbiter::ArbitrationType>(type)) {
1499 case AddressArbiter::ArbitrationType::WaitIfLessThan: 1500 case AddressArbiter::ArbitrationType::WaitIfLessThan:
1500 return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false); 1501 return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false);
1501 case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: 1502 case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan:
1502 return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true); 1503 return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true);
1503 case AddressArbiter::ArbitrationType::WaitIfEqual: 1504 case AddressArbiter::ArbitrationType::WaitIfEqual:
1504 return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); 1505 return address_arbiter.WaitForAddressIfEqual(address, value, timeout);
1505 default: 1506 default:
1506 LOG_ERROR(Kernel_SVC, 1507 LOG_ERROR(Kernel_SVC,
1507 "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " 1508 "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan "
@@ -1526,13 +1527,14 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1526 return ERR_INVALID_ADDRESS; 1527 return ERR_INVALID_ADDRESS;
1527 } 1528 }
1528 1529
1530 auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();
1529 switch (static_cast<AddressArbiter::SignalType>(type)) { 1531 switch (static_cast<AddressArbiter::SignalType>(type)) {
1530 case AddressArbiter::SignalType::Signal: 1532 case AddressArbiter::SignalType::Signal:
1531 return AddressArbiter::SignalToAddress(address, num_to_wake); 1533 return address_arbiter.SignalToAddress(address, num_to_wake);
1532 case AddressArbiter::SignalType::IncrementAndSignalIfEqual: 1534 case AddressArbiter::SignalType::IncrementAndSignalIfEqual:
1533 return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); 1535 return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
1534 case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: 1536 case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual:
1535 return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, 1537 return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
1536 num_to_wake); 1538 num_to_wake);
1537 default: 1539 default:
1538 LOG_ERROR(Kernel_SVC, 1540 LOG_ERROR(Kernel_SVC,