summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Scire <SciresM@gmail.com>2018-06-22 05:05:34 +0200
committerMichael Scire <SciresM@gmail.com>2018-06-22 05:05:34 +0200
commit08d454e30ddf5031190790c977bfda9422a24118 (patch)
tree0de42225f3cf8cc32a98c812b076d2e6dadee876
parentKernel/Arbiters: HLE is atomic, adjust code to reflect that. (diff)
downloadyuzu-08d454e30ddf5031190790c977bfda9422a24118.tar
yuzu-08d454e30ddf5031190790c977bfda9422a24118.tar.gz
yuzu-08d454e30ddf5031190790c977bfda9422a24118.tar.bz2
yuzu-08d454e30ddf5031190790c977bfda9422a24118.tar.lz
yuzu-08d454e30ddf5031190790c977bfda9422a24118.tar.xz
yuzu-08d454e30ddf5031190790c977bfda9422a24118.tar.zst
yuzu-08d454e30ddf5031190790c977bfda9422a24118.zip
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp313
-rw-r--r--src/core/hle/kernel/address_arbiter.h44
-rw-r--r--src/core/hle/kernel/thread.h4
3 files changed, 181 insertions, 180 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 01c5bf61b..972911e42 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -14,160 +14,161 @@
#include "core/memory.h"
namespace Kernel {
- namespace AddressArbiter {
-
- // Performs actual address waiting logic.
- ResultCode WaitForAddress(VAddr address, s64 timeout) {
- SharedPtr<Thread> current_thread = GetCurrentThread();
- current_thread->arb_wait_address = address;
- current_thread->status = THREADSTATUS_WAIT_ARB;
- current_thread->wakeup_callback = nullptr;
-
- current_thread->WakeAfterDelay(timeout);
-
- Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
- // This should never actually execute.
- return RESULT_SUCCESS;
- }
-
- // Gets the threads waiting on an address.
- void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>> &waiting_threads, VAddr address) {
- auto RetrieveWaitingThreads =
- [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) {
- const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
- auto& thread_list = scheduler->GetThreadList();
-
- for (auto& thread : thread_list) {
- if (thread->arb_wait_address == arb_addr)
- waiting_threads.push_back(thread);
- }
- };
-
- // Retrieve a list of all threads that are waiting for this address.
- RetrieveWaitingThreads(0, waiting_threads, address);
- RetrieveWaitingThreads(1, waiting_threads, address);
- RetrieveWaitingThreads(2, waiting_threads, address);
- RetrieveWaitingThreads(3, waiting_threads, address);
- // Sort them by priority, such that the highest priority ones come first.
- std::sort(waiting_threads.begin(), waiting_threads.end(),
- [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
- return lhs->current_priority < rhs->current_priority;
- });
- }
-
- // Wake up num_to_wake (or all) threads in a vector.
- 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.
- size_t last = waiting_threads.size();
- if (num_to_wake > 0)
- last = num_to_wake;
-
- // Signal the waiting threads.
- // TODO: Rescheduling should not occur while waking threads. How can it be prevented?
- for (size_t i = 0; i < last; i++) {
- ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB);
- waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
- waiting_threads[i]->arb_wait_address = 0;
- waiting_threads[i]->ResumeFromWait();
+namespace AddressArbiter {
+
+// Performs actual address waiting logic.
+ResultCode WaitForAddress(VAddr address, s64 timeout) {
+ SharedPtr<Thread> current_thread = GetCurrentThread();
+ current_thread->arb_wait_address = address;
+ current_thread->status = THREADSTATUS_WAIT_ARB;
+ current_thread->wakeup_callback = nullptr;
+
+ current_thread->WakeAfterDelay(timeout);
+
+ Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
+ // This should never actually execute.
+ return RESULT_SUCCESS;
+}
+
+// Gets the threads waiting on an address.
+void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_threads, VAddr address) {
+ auto RetrieveWaitingThreads =
+ [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) {
+ const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
+ auto& thread_list = scheduler->GetThreadList();
+
+ for (auto& thread : thread_list) {
+ if (thread->arb_wait_address == arb_addr)
+ waiting_threads.push_back(thread);
}
-
- }
-
- // Signals an address being waited on.
- ResultCode SignalToAddress(VAddr address, s32 num_to_wake) {
- // Get threads waiting on the address.
- std::vector<SharedPtr<Thread>> waiting_threads;
- GetThreadsWaitingOnAddress(waiting_threads, 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) {
- // Ensure that we can write to the address.
- if (!Memory::IsValidVirtualAddress(address)) {
- return ERR_INVALID_ADDRESS_STATE;
- }
-
- if ((s32)Memory::Read32(address) == value) {
- Memory::Write32(address, (u32)(value + 1));
- } else {
- return ERR_INVALID_STATE;
- }
-
- 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) {
- // Ensure that we can write to the address.
- if (!Memory::IsValidVirtualAddress(address)) {
- return ERR_INVALID_ADDRESS_STATE;
- }
-
- // Get threads waiting on the address.
- std::vector<SharedPtr<Thread>> waiting_threads;
- GetThreadsWaitingOnAddress(waiting_threads, address);
-
- // Determine the modified value depending on the waiting count.
- s32 updated_value;
- if (waiting_threads.size() == 0) {
- updated_value = value - 1;
- } else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) {
- updated_value = value + 1;
- } else {
- updated_value = value;
- }
-
- if ((s32)Memory::Read32(address) == value) {
- Memory::Write32(address, (u32)(updated_value));
- } else {
- return ERR_INVALID_STATE;
- }
-
- WakeThreads(waiting_threads, num_to_wake);
- 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) {
- // Ensure that we can read the address.
- if (!Memory::IsValidVirtualAddress(address)) {
- return ERR_INVALID_ADDRESS_STATE;
- }
-
- s32 cur_value = (s32)Memory::Read32(address);
- if (cur_value < value) {
- Memory::Write32(address, (u32)(cur_value - 1));
- } else {
- return ERR_INVALID_STATE;
- }
- // Short-circuit without rescheduling, if timeout is zero.
- if (timeout == 0) {
- return RESULT_TIMEOUT;
- }
-
- 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) {
- // Ensure that we can read the address.
- if (!Memory::IsValidVirtualAddress(address)) {
- return ERR_INVALID_ADDRESS_STATE;
- }
- // Only wait for the address if equal.
- if ((s32)Memory::Read32(address) != value) {
- return ERR_INVALID_STATE;
- }
- // Short-circuit without rescheduling, if timeout is zero.
- if (timeout == 0) {
- return RESULT_TIMEOUT;
- }
-
- return WaitForAddress(address, timeout);
- }
- } // namespace AddressArbiter
-} // namespace Kernel \ No newline at end of file
+ };
+
+ // Retrieve a list of all threads that are waiting for this address.
+ RetrieveWaitingThreads(0, waiting_threads, address);
+ RetrieveWaitingThreads(1, waiting_threads, address);
+ RetrieveWaitingThreads(2, waiting_threads, address);
+ RetrieveWaitingThreads(3, waiting_threads, address);
+ // Sort them by priority, such that the highest priority ones come first.
+ std::sort(waiting_threads.begin(), waiting_threads.end(),
+ [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
+ return lhs->current_priority < rhs->current_priority;
+ });
+}
+
+// Wake up num_to_wake (or all) threads in a vector.
+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.
+ size_t last = waiting_threads.size();
+ if (num_to_wake > 0)
+ last = num_to_wake;
+
+ // Signal the waiting threads.
+ // TODO: Rescheduling should not occur while waking threads. How can it be prevented?
+ for (size_t i = 0; i < last; i++) {
+ ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB);
+ waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
+ waiting_threads[i]->arb_wait_address = 0;
+ waiting_threads[i]->ResumeFromWait();
+ }
+}
+
+// Signals an address being waited on.
+ResultCode SignalToAddress(VAddr address, s32 num_to_wake) {
+ // Get threads waiting on the address.
+ std::vector<SharedPtr<Thread>> waiting_threads;
+ GetThreadsWaitingOnAddress(waiting_threads, 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) {
+ // Ensure that we can write to the address.
+ if (!Memory::IsValidVirtualAddress(address)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
+ if ((s32)Memory::Read32(address) == value) {
+ Memory::Write32(address, (u32)(value + 1));
+ } else {
+ return ERR_INVALID_STATE;
+ }
+
+ 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) {
+ // Ensure that we can write to the address.
+ if (!Memory::IsValidVirtualAddress(address)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
+ // Get threads waiting on the address.
+ std::vector<SharedPtr<Thread>> waiting_threads;
+ GetThreadsWaitingOnAddress(waiting_threads, address);
+
+ // Determine the modified value depending on the waiting count.
+ s32 updated_value;
+ if (waiting_threads.size() == 0) {
+ updated_value = value - 1;
+ } else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) {
+ updated_value = value + 1;
+ } else {
+ updated_value = value;
+ }
+
+ if ((s32)Memory::Read32(address) == value) {
+ Memory::Write32(address, (u32)(updated_value));
+ } else {
+ return ERR_INVALID_STATE;
+ }
+
+ WakeThreads(waiting_threads, num_to_wake);
+ 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) {
+ // Ensure that we can read the address.
+ if (!Memory::IsValidVirtualAddress(address)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
+ s32 cur_value = (s32)Memory::Read32(address);
+ if (cur_value < value) {
+ Memory::Write32(address, (u32)(cur_value - 1));
+ } else {
+ return ERR_INVALID_STATE;
+ }
+ // Short-circuit without rescheduling, if timeout is zero.
+ if (timeout == 0) {
+ return RESULT_TIMEOUT;
+ }
+
+ 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) {
+ // Ensure that we can read the address.
+ if (!Memory::IsValidVirtualAddress(address)) {
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+ // Only wait for the address if equal.
+ if ((s32)Memory::Read32(address) != value) {
+ return ERR_INVALID_STATE;
+ }
+ // Short-circuit without rescheduling, if timeout is zero.
+ if (timeout == 0) {
+ return RESULT_TIMEOUT;
+ }
+
+ return WaitForAddress(address, timeout);
+}
+} // namespace AddressArbiter
+} // namespace Kernel
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 32d4a77a9..f20f3dbc0 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -8,25 +8,25 @@
namespace Kernel {
- namespace AddressArbiter {
- enum class ArbitrationType {
- WaitIfLessThan = 0,
- DecrementAndWaitIfLessThan = 1,
- WaitIfEqual = 2,
- };
-
- enum class SignalType {
- Signal = 0,
- IncrementAndSignalIfEqual = 1,
- ModifyByWaitingCountAndSignalIfEqual = 2,
- };
-
- 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);
-
- ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement);
- ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
- } // namespace AddressArbiter
-
-} // namespace Kernel \ No newline at end of file
+namespace AddressArbiter {
+enum class ArbitrationType {
+ WaitIfLessThan = 0,
+ DecrementAndWaitIfLessThan = 1,
+ WaitIfEqual = 2,
+};
+
+enum class SignalType {
+ Signal = 0,
+ IncrementAndSignalIfEqual = 1,
+ ModifyByWaitingCountAndSignalIfEqual = 2,
+};
+
+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);
+
+ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement);
+ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
+} // namespace AddressArbiter
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 3851d1085..f1e759802 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -228,8 +228,8 @@ public:
// If waiting on a ConditionVariable, this is the ConditionVariable address
VAddr condvar_wait_address;
- VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address
- Handle wait_handle; ///< The handle used to wait for the mutex.
+ VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address
+ Handle wait_handle; ///< The handle used to wait for the mutex.
// If waiting for an AddressArbiter, this is the address being waited on.
VAddr arb_wait_address{0};