diff options
| author | 2018-06-21 04:07:03 -0600 | |
|---|---|---|
| committer | 2018-06-21 04:10:11 -0600 | |
| commit | 4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0 (patch) | |
| tree | 597b478c20184a6c40692b4d7c695c8b1cac362e /src | |
| parent | Kernel/Arbiters: Implement WaitForAddress (diff) | |
| download | yuzu-4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0.tar.gz yuzu-4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0.tar.xz yuzu-4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0.zip | |
Kernel/Arbiters: Mostly implement SignalToAddress
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 110 | ||||
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 6 | ||||
| -rw-r--r-- | src/yuzu/debugger/wait_tree.cpp | 2 |
5 files changed, 111 insertions, 11 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 367c4520d..4556199ab 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -27,24 +27,122 @@ namespace Kernel { | |||
| 27 | current_thread->WakeAfterDelay(timeout); | 27 | current_thread->WakeAfterDelay(timeout); |
| 28 | 28 | ||
| 29 | Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); | 29 | Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); |
| 30 | return RESULT_SUCCESS; | 30 | return current_thread->arb_wait_result; |
| 31 | } | ||
| 32 | |||
| 33 | // Gets the threads waiting on an address. | ||
| 34 | void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>> &waiting_threads, VAddr address) { | ||
| 35 | auto RetrieveWaitingThreads = | ||
| 36 | [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) { | ||
| 37 | const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); | ||
| 38 | auto& thread_list = scheduler->GetThreadList(); | ||
| 39 | |||
| 40 | for (auto& thread : thread_list) { | ||
| 41 | if (thread->arb_wait_address == arb_addr) | ||
| 42 | waiting_threads.push_back(thread); | ||
| 43 | } | ||
| 44 | }; | ||
| 45 | |||
| 46 | // Retrieve a list of all threads that are waiting for this address. | ||
| 47 | RetrieveWaitingThreads(0, waiting_threads, address); | ||
| 48 | RetrieveWaitingThreads(1, waiting_threads, address); | ||
| 49 | RetrieveWaitingThreads(2, waiting_threads, address); | ||
| 50 | RetrieveWaitingThreads(3, waiting_threads, address); | ||
| 51 | // Sort them by priority, such that the highest priority ones come first. | ||
| 52 | std::sort(waiting_threads.begin(), waiting_threads.end(), | ||
| 53 | [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { | ||
| 54 | return lhs->current_priority < rhs->current_priority; | ||
| 55 | }); | ||
| 56 | } | ||
| 57 | |||
| 58 | // Wake up num_to_wake (or all) threads in a vector. | ||
| 59 | void WakeThreads(std::vector<SharedPtr<Thread>> &waiting_threads, s32 num_to_wake) { | ||
| 60 | // Only process up to 'target' threads, unless 'target' is <= 0, in which case process | ||
| 61 | // them all. | ||
| 62 | size_t last = waiting_threads.size(); | ||
| 63 | if (num_to_wake > 0) | ||
| 64 | last = num_to_wake; | ||
| 65 | |||
| 66 | // Signal the waiting threads. | ||
| 67 | // TODO: Rescheduling should not occur while waking threads. How can it be prevented? | ||
| 68 | for (size_t i = 0; i < last; i++) { | ||
| 69 | ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB); | ||
| 70 | waiting_threads[i]->arb_wait_result = RESULT_SUCCESS; | ||
| 71 | waiting_threads[i]->ResumeFromWait(); | ||
| 72 | } | ||
| 73 | |||
| 31 | } | 74 | } |
| 32 | 75 | ||
| 33 | // Signals an address being waited on. | 76 | // Signals an address being waited on. |
| 34 | ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) { | 77 | ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { |
| 35 | // TODO | 78 | // Get threads waiting on the address. |
| 79 | std::vector<SharedPtr<Thread>> waiting_threads; | ||
| 80 | GetThreadsWaitingOnAddress(waiting_threads, address); | ||
| 81 | |||
| 82 | WakeThreads(waiting_threads, num_to_wake); | ||
| 36 | return RESULT_SUCCESS; | 83 | return RESULT_SUCCESS; |
| 37 | } | 84 | } |
| 38 | 85 | ||
| 39 | // Signals an address being waited on and increments its value if equal to the value argument. | 86 | // Signals an address being waited on and increments its value if equal to the value argument. |
| 40 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { | 87 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { |
| 41 | // TODO | 88 | // Ensure that we can write to the address. |
| 42 | return RESULT_SUCCESS; | 89 | if (!Memory::IsValidVirtualAddress(address)) { |
| 90 | return ERR_INVALID_ADDRESS_STATE; | ||
| 91 | } | ||
| 92 | |||
| 93 | s32 cur_value; | ||
| 94 | // Get value, incrementing if equal. | ||
| 95 | { | ||
| 96 | // Increment if Equal must be an atomic operation. | ||
| 97 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 98 | cur_value = (s32)Memory::Read32(address); | ||
| 99 | if (cur_value == value) { | ||
| 100 | Memory::Write32(address, (u32)(cur_value + 1)); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | if (cur_value != value) { | ||
| 104 | return ERR_INVALID_STATE; | ||
| 105 | } | ||
| 106 | |||
| 107 | return SignalToAddress(address, num_to_wake); | ||
| 43 | } | 108 | } |
| 44 | 109 | ||
| 45 | // Signals an address being waited on and modifies its value based on waiting thread count if equal to the value argument. | 110 | // Signals an address being waited on and modifies its value based on waiting thread count if equal to the value argument. |
| 46 | ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { | 111 | ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { |
| 47 | // TODO | 112 | // Ensure that we can write to the address. |
| 113 | if (!Memory::IsValidVirtualAddress(address)) { | ||
| 114 | return ERR_INVALID_ADDRESS_STATE; | ||
| 115 | } | ||
| 116 | |||
| 117 | // Get threads waiting on the address. | ||
| 118 | std::vector<SharedPtr<Thread>> waiting_threads; | ||
| 119 | GetThreadsWaitingOnAddress(waiting_threads, address); | ||
| 120 | |||
| 121 | // Determine the modified value depending on the waiting count. | ||
| 122 | s32 updated_value; | ||
| 123 | if (waiting_threads.size() == 0) { | ||
| 124 | updated_value = value - 1; | ||
| 125 | } else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) { | ||
| 126 | updated_value = value + 1; | ||
| 127 | } else { | ||
| 128 | updated_value = value; | ||
| 129 | } | ||
| 130 | s32 cur_value; | ||
| 131 | // Perform an atomic update if equal. | ||
| 132 | { | ||
| 133 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 134 | cur_value = (s32)Memory::Read32(address); | ||
| 135 | if (cur_value == value) { | ||
| 136 | Memory::Write32(address, (u32)(updated_value)); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | // Only continue if equal. | ||
| 141 | if (cur_value != value) { | ||
| 142 | return ERR_INVALID_STATE; | ||
| 143 | } | ||
| 144 | |||
| 145 | WakeThreads(waiting_threads, num_to_wake); | ||
| 48 | return RESULT_SUCCESS; | 146 | return RESULT_SUCCESS; |
| 49 | } | 147 | } |
| 50 | 148 | ||
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 3eba103dd..32d4a77a9 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h | |||
| @@ -21,7 +21,7 @@ namespace Kernel { | |||
| 21 | ModifyByWaitingCountAndSignalIfEqual = 2, | 21 | ModifyByWaitingCountAndSignalIfEqual = 2, |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake); | 24 | ResultCode SignalToAddress(VAddr address, s32 num_to_wake); |
| 25 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); | 25 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); |
| 26 | ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); | 26 | ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); |
| 27 | 27 | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4b4831c08..24dd50938 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -726,7 +726,7 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to | |||
| 726 | 726 | ||
| 727 | switch ((AddressArbiter::SignalType)type) { | 727 | switch ((AddressArbiter::SignalType)type) { |
| 728 | case AddressArbiter::SignalType::Signal: | 728 | case AddressArbiter::SignalType::Signal: |
| 729 | return AddressArbiter::SignalToAddress(address, value, num_to_wake); | 729 | return AddressArbiter::SignalToAddress(address, num_to_wake); |
| 730 | case AddressArbiter::SignalType::IncrementAndSignalIfEqual: | 730 | case AddressArbiter::SignalType::IncrementAndSignalIfEqual: |
| 731 | return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); | 731 | return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); |
| 732 | case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: | 732 | case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 79e5d6e5c..0a76bd222 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -230,8 +230,10 @@ public: | |||
| 230 | VAddr condvar_wait_address; | 230 | VAddr condvar_wait_address; |
| 231 | VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address | 231 | VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address |
| 232 | Handle wait_handle; ///< The handle used to wait for the mutex. | 232 | Handle wait_handle; ///< The handle used to wait for the mutex. |
| 233 | VAddr arb_wait_address; ///< If waiting for an AddressArbiter, this is the address | 233 | |
| 234 | ResultCode arb_wait_result; ///< If waiting for an AddressArbiter, this is the result that will be returned. | 234 | // If waiting for an AddressArbiter, this is the address being waited on. |
| 235 | VAddr arb_wait_address; | ||
| 236 | ResultCode arb_wait_result{RESULT_SUCCESS}; ///< Result returned when done waiting on AddressArbiter. | ||
| 235 | 237 | ||
| 236 | std::string name; | 238 | std::string name; |
| 237 | 239 | ||
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 800e431bd..7101b381e 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -213,7 +213,7 @@ QString WaitTreeThread::GetText() const { | |||
| 213 | case THREADSTATUS_WAIT_MUTEX: | 213 | case THREADSTATUS_WAIT_MUTEX: |
| 214 | status = tr("waiting for mutex"); | 214 | status = tr("waiting for mutex"); |
| 215 | break; | 215 | break; |
| 216 | case THREADSTATUS_WAIT_MUTEX: | 216 | case THREADSTATUS_WAIT_ARB: |
| 217 | status = tr("waiting for address arbiter"); | 217 | status = tr("waiting for address arbiter"); |
| 218 | break; | 218 | break; |
| 219 | case THREADSTATUS_DORMANT: | 219 | case THREADSTATUS_DORMANT: |