From 7e191dccc184ae85ce5ade2bca913ab331002481 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Jun 2018 00:49:43 -0600 Subject: Kernel/Arbiters: Add stubs for 4.x SignalToAddress/WaitForAddres SVCs. --- src/core/hle/kernel/address_arbiter.cpp | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/core/hle/kernel/address_arbiter.cpp (limited to 'src/core/hle/kernel/address_arbiter.cpp') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp new file mode 100644 index 000000000..cfd2c1590 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -0,0 +1,46 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h" +#include "core/memory.h" + +namespace Kernel { + namespace AddressArbiter { + + // Signals an address being waited on. + ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) { + // TODO + 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) { + // TODO + return RESULT_SUCCESS; + } + + // 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) { + // TODO + 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) { + // TODO + return RESULT_SUCCESS; + } + + // Waits on an address if the value passed is equal to the argument value. + ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { + // TODO + return RESULT_SUCCESS; + } + } // namespace AddressArbiter +} // namespace Kernel \ No newline at end of file -- cgit v1.2.3 From 9d71ce88cee58d2e171ec5ed82daf075112fb422 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Jun 2018 01:40:29 -0600 Subject: Kernel/Arbiters: Implement WaitForAddress --- src/core/hle/kernel/address_arbiter.cpp | 59 ++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/address_arbiter.cpp') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index cfd2c1590..367c4520d 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -5,14 +5,31 @@ #include "common/assert.h" #include "common/common_funcs.h" #include "common/common_types.h" +#include "core/core.h" +#include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" +#include "core/hle/lock.h" #include "core/memory.h" namespace Kernel { namespace AddressArbiter { + // Performs actual address waiting logic. + ResultCode WaitForAddress(VAddr address, s64 timeout) { + SharedPtr current_thread = GetCurrentThread(); + current_thread->arb_wait_address = address; + current_thread->arb_wait_result = RESULT_TIMEOUT; + current_thread->status = THREADSTATUS_WAIT_ARB; + current_thread->wakeup_callback = nullptr; + + current_thread->WakeAfterDelay(timeout); + + Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); + return RESULT_SUCCESS; + } + // Signals an address being waited on. ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) { // TODO @@ -33,14 +50,48 @@ namespace Kernel { // 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) { - // TODO - return RESULT_SUCCESS; + // Ensure that we can read the address. + if (!Memory::IsValidVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + + s32 cur_value; + // Get value, decrementing if less than + { + // Decrement if less than must be an atomic operation. + std::lock_guard lock(HLE::g_hle_lock); + cur_value = (s32)Memory::Read32(address); + if (cur_value < value) { + Memory::Write32(address, (u32)(cur_value - 1)); + } + } + if (cur_value >= value) { + 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) { - // TODO - return RESULT_SUCCESS; + // 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 -- cgit v1.2.3 From 4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Jun 2018 04:07:03 -0600 Subject: Kernel/Arbiters: Mostly implement SignalToAddress --- src/core/hle/kernel/address_arbiter.cpp | 110 ++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel/address_arbiter.cpp') 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 { current_thread->WakeAfterDelay(timeout); Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); - return RESULT_SUCCESS; + return current_thread->arb_wait_result; + } + + // Gets the threads waiting on an address. + void GetThreadsWaitingOnAddress(std::vector> &waiting_threads, VAddr address) { + auto RetrieveWaitingThreads = + [](size_t core_index, std::vector>& 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& lhs, const SharedPtr& rhs) { + return lhs->current_priority < rhs->current_priority; + }); + } + + // Wake up num_to_wake (or all) threads in a vector. + void WakeThreads(std::vector> &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]->arb_wait_result = RESULT_SUCCESS; + waiting_threads[i]->ResumeFromWait(); + } + } // Signals an address being waited on. - ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) { - // TODO + ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { + // Get threads waiting on the address. + std::vector> 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) { - // TODO - return RESULT_SUCCESS; + // Ensure that we can write to the address. + if (!Memory::IsValidVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + + s32 cur_value; + // Get value, incrementing if equal. + { + // Increment if Equal must be an atomic operation. + std::lock_guard lock(HLE::g_hle_lock); + cur_value = (s32)Memory::Read32(address); + if (cur_value == value) { + Memory::Write32(address, (u32)(cur_value + 1)); + } + } + if (cur_value != value) { + 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) { - // TODO + // 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> 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; + } + s32 cur_value; + // Perform an atomic update if equal. + { + std::lock_guard lock(HLE::g_hle_lock); + cur_value = (s32)Memory::Read32(address); + if (cur_value == value) { + Memory::Write32(address, (u32)(updated_value)); + } + } + + // Only continue if equal. + if (cur_value != value) { + return ERR_INVALID_STATE; + } + + WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } -- cgit v1.2.3 From 62bd1299ea8c855b4951a15f9f3b645c2953ee0c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Jun 2018 04:20:39 -0600 Subject: Kernel/Arbiters: Clear WaitAddress in SignalToAddress --- src/core/hle/kernel/address_arbiter.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle/kernel/address_arbiter.cpp') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 4556199ab..63cdcb559 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -68,6 +68,7 @@ namespace Kernel { for (size_t i = 0; i < last; i++) { ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB); waiting_threads[i]->arb_wait_result = RESULT_SUCCESS; + waiting_threads[i]->arb_wait_address = 0; waiting_threads[i]->ResumeFromWait(); } -- cgit v1.2.3 From dc70a87af1576e29dd6fda1d0313aca260982498 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Jun 2018 20:25:57 -0600 Subject: Kernel/Arbiters: HLE is atomic, adjust code to reflect that. --- src/core/hle/kernel/address_arbiter.cpp | 49 +++++++++------------------------ 1 file changed, 13 insertions(+), 36 deletions(-) (limited to 'src/core/hle/kernel/address_arbiter.cpp') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 63cdcb559..01c5bf61b 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -20,14 +20,14 @@ namespace Kernel { ResultCode WaitForAddress(VAddr address, s64 timeout) { SharedPtr current_thread = GetCurrentThread(); current_thread->arb_wait_address = address; - current_thread->arb_wait_result = RESULT_TIMEOUT; current_thread->status = THREADSTATUS_WAIT_ARB; current_thread->wakeup_callback = nullptr; current_thread->WakeAfterDelay(timeout); Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); - return current_thread->arb_wait_result; + // This should never actually execute. + return RESULT_SUCCESS; } // Gets the threads waiting on an address. @@ -67,7 +67,7 @@ namespace Kernel { // 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]->arb_wait_result = RESULT_SUCCESS; + waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); waiting_threads[i]->arb_wait_address = 0; waiting_threads[i]->ResumeFromWait(); } @@ -91,17 +91,9 @@ namespace Kernel { return ERR_INVALID_ADDRESS_STATE; } - s32 cur_value; - // Get value, incrementing if equal. - { - // Increment if Equal must be an atomic operation. - std::lock_guard lock(HLE::g_hle_lock); - cur_value = (s32)Memory::Read32(address); - if (cur_value == value) { - Memory::Write32(address, (u32)(cur_value + 1)); - } - } - if (cur_value != value) { + if ((s32)Memory::Read32(address) == value) { + Memory::Write32(address, (u32)(value + 1)); + } else { return ERR_INVALID_STATE; } @@ -128,18 +120,10 @@ namespace Kernel { } else { updated_value = value; } - s32 cur_value; - // Perform an atomic update if equal. - { - std::lock_guard lock(HLE::g_hle_lock); - cur_value = (s32)Memory::Read32(address); - if (cur_value == value) { - Memory::Write32(address, (u32)(updated_value)); - } - } - // Only continue if equal. - if (cur_value != value) { + if ((s32)Memory::Read32(address) == value) { + Memory::Write32(address, (u32)(updated_value)); + } else { return ERR_INVALID_STATE; } @@ -154,17 +138,10 @@ namespace Kernel { return ERR_INVALID_ADDRESS_STATE; } - s32 cur_value; - // Get value, decrementing if less than - { - // Decrement if less than must be an atomic operation. - std::lock_guard lock(HLE::g_hle_lock); - cur_value = (s32)Memory::Read32(address); - if (cur_value < value) { - Memory::Write32(address, (u32)(cur_value - 1)); - } - } - if (cur_value >= value) { + 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. -- cgit v1.2.3 From 08d454e30ddf5031190790c977bfda9422a24118 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Jun 2018 21:05:34 -0600 Subject: Run clang-format on PR. --- src/core/hle/kernel/address_arbiter.cpp | 313 ++++++++++++++++---------------- 1 file changed, 157 insertions(+), 156 deletions(-) (limited to 'src/core/hle/kernel/address_arbiter.cpp') 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 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> &waiting_threads, VAddr address) { - auto RetrieveWaitingThreads = - [](size_t core_index, std::vector>& 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& lhs, const SharedPtr& rhs) { - return lhs->current_priority < rhs->current_priority; - }); - } - - // Wake up num_to_wake (or all) threads in a vector. - void WakeThreads(std::vector> &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 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>& waiting_threads, VAddr address) { + auto RetrieveWaitingThreads = + [](size_t core_index, std::vector>& 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> 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> 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& lhs, const SharedPtr& rhs) { + return lhs->current_priority < rhs->current_priority; + }); +} + +// Wake up num_to_wake (or all) threads in a vector. +void WakeThreads(std::vector>& 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> 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> 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 -- cgit v1.2.3 From 067ac434ba90084359babef1638970e849a5f2ce Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 22 Jun 2018 00:47:59 -0600 Subject: Kernel/Arbiters: Fix casts, cleanup comments/magic numbers --- src/core/hle/kernel/address_arbiter.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'src/core/hle/kernel/address_arbiter.cpp') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 972911e42..e9c8369d7 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -17,7 +17,7 @@ namespace Kernel { namespace AddressArbiter { // Performs actual address waiting logic. -ResultCode WaitForAddress(VAddr address, s64 timeout) { +static ResultCode WaitForAddress(VAddr address, s64 timeout) { SharedPtr current_thread = GetCurrentThread(); current_thread->arb_wait_address = address; current_thread->status = THREADSTATUS_WAIT_ARB; @@ -26,12 +26,12 @@ ResultCode WaitForAddress(VAddr address, s64 timeout) { current_thread->WakeAfterDelay(timeout); Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); - // This should never actually execute. - return RESULT_SUCCESS; + return RESULT_TIMEOUT; } // Gets the threads waiting on an address. -void GetThreadsWaitingOnAddress(std::vector>& waiting_threads, VAddr address) { +static void GetThreadsWaitingOnAddress(std::vector>& waiting_threads, + VAddr address) { auto RetrieveWaitingThreads = [](size_t core_index, std::vector>& waiting_threads, VAddr arb_addr) { const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); @@ -56,7 +56,7 @@ void GetThreadsWaitingOnAddress(std::vector>& waiting_threads, } // Wake up num_to_wake (or all) threads in a vector. -void WakeThreads(std::vector>& waiting_threads, s32 num_to_wake) { +static void WakeThreads(std::vector>& 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(); @@ -64,7 +64,6 @@ void WakeThreads(std::vector>& waiting_threads, s32 num_to_wak 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); @@ -90,8 +89,8 @@ ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_ return ERR_INVALID_ADDRESS_STATE; } - if ((s32)Memory::Read32(address) == value) { - Memory::Write32(address, (u32)(value + 1)); + if (static_cast(Memory::Read32(address)) == value) { + Memory::Write32(address, static_cast(value + 1)); } else { return ERR_INVALID_STATE; } @@ -122,8 +121,8 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu updated_value = value; } - if ((s32)Memory::Read32(address) == value) { - Memory::Write32(address, (u32)(updated_value)); + if (static_cast(Memory::Read32(address)) == value) { + Memory::Write32(address, static_cast(updated_value)); } else { return ERR_INVALID_STATE; } @@ -139,9 +138,9 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool return ERR_INVALID_ADDRESS_STATE; } - s32 cur_value = (s32)Memory::Read32(address); + s32 cur_value = static_cast(Memory::Read32(address)); if (cur_value < value) { - Memory::Write32(address, (u32)(cur_value - 1)); + Memory::Write32(address, static_cast(cur_value - 1)); } else { return ERR_INVALID_STATE; } @@ -160,7 +159,7 @@ ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { return ERR_INVALID_ADDRESS_STATE; } // Only wait for the address if equal. - if ((s32)Memory::Read32(address) != value) { + if (static_cast(Memory::Read32(address)) != value) { return ERR_INVALID_STATE; } // Short-circuit without rescheduling, if timeout is zero. -- cgit v1.2.3