@ -9,6 +9,7 @@
# include "common/common_types.h"
# include "core/core.h"
# include "core/core_cpu.h"
# include "core/hle/kernel/address_arbiter.h"
# include "core/hle/kernel/errors.h"
# include "core/hle/kernel/object.h"
# include "core/hle/kernel/process.h"
@ -17,53 +18,10 @@
# include "core/hle/result.h"
# include "core/memory.h"
namespace Kernel : : AddressArbiter {
// Performs actual address waiting logic.
static ResultCode WaitForAddress ( VAddr address , s64 timeout ) {
SharedPtr < Thread > current_thread = GetCurrentThread ( ) ;
current_thread - > SetArbiterWaitAddress ( address ) ;
current_thread - > SetStatus ( ThreadStatus : : WaitArb ) ;
current_thread - > InvalidateWakeupCallback ( ) ;
current_thread - > WakeAfterDelay ( timeout ) ;
Core : : System : : GetInstance ( ) . CpuCore ( current_thread - > GetProcessorID ( ) ) . PrepareReschedule ( ) ;
return RESULT_TIMEOUT ;
}
// Gets the threads waiting on an address.
static std : : vector < SharedPtr < Thread > > GetThreadsWaitingOnAddress ( VAddr address ) {
const auto RetrieveWaitingThreads = [ ] ( std : : size_t core_index ,
std : : vector < SharedPtr < Thread > > & waiting_threads ,
VAddr arb_addr ) {
const auto & scheduler = Core : : System : : GetInstance ( ) . Scheduler ( core_index ) ;
const auto & thread_list = scheduler . GetThreadList ( ) ;
for ( const auto & thread : thread_list ) {
if ( thread - > GetArbiterWaitAddress ( ) = = arb_addr )
waiting_threads . push_back ( thread ) ;
}
} ;
// Retrieve all threads that are waiting for this address.
std : : vector < SharedPtr < Thread > > threads ;
RetrieveWaitingThreads ( 0 , threads , address ) ;
RetrieveWaitingThreads ( 1 , threads , address ) ;
RetrieveWaitingThreads ( 2 , threads , address ) ;
RetrieveWaitingThreads ( 3 , threads , address ) ;
// Sort them by priority, such that the highest priority ones come first.
std : : sort ( threads . begin ( ) , threads . end ( ) ,
[ ] ( const SharedPtr < Thread > & lhs , const SharedPtr < Thread > & rhs ) {
return lhs - > GetPriority ( ) < rhs - > GetPriority ( ) ;
} ) ;
return threads ;
}
namespace Kernel {
namespace {
// Wake up num_to_wake (or all) threads in a vector.
static void WakeThreads ( std : : vector < SharedPtr < Thread > > & waiting_threads , s32 num_to_wake ) {
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.
std : : size_t last = waiting_threads . size ( ) ;
@ -78,17 +36,20 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num
waiting_threads [ i ] - > ResumeFromWait ( ) ;
}
}
} // Anonymous namespace
// Signals an address being waited on.
ResultCode SignalToAddress ( VAddr address , s32 num_to_wake ) {
AddressArbiter : : AddressArbiter ( ) = default ;
AddressArbiter : : ~ AddressArbiter ( ) = default ;
ResultCode AddressArbiter : : SignalToAddress ( VAddr address , s32 num_to_wake ) {
std : : vector < SharedPtr < Thread > > waiting_threads = GetThreadsWaitingOnAddress ( 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 ) {
ResultCode AddressArbiter : : 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 ;
@ -103,10 +64,8 @@ ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_
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 ) {
ResultCode AddressArbiter : : 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 ;
@ -135,8 +94,8 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
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 ) {
ResultCode AddressArbiter : : 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 ;
@ -158,8 +117,7 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool
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 ) {
ResultCode AddressArbiter : : WaitForAddressIfEqual ( VAddr address , s32 value , s64 timeout ) {
// Ensure that we can read the address.
if ( ! Memory : : IsValidVirtualAddress ( address ) ) {
return ERR_INVALID_ADDRESS_STATE ;
@ -175,4 +133,45 @@ ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
return WaitForAddress ( address , timeout ) ;
}
} // namespace Kernel::AddressArbiter
ResultCode AddressArbiter : : WaitForAddress ( VAddr address , s64 timeout ) {
SharedPtr < Thread > current_thread = GetCurrentThread ( ) ;
current_thread - > SetArbiterWaitAddress ( address ) ;
current_thread - > SetStatus ( ThreadStatus : : WaitArb ) ;
current_thread - > InvalidateWakeupCallback ( ) ;
current_thread - > WakeAfterDelay ( timeout ) ;
Core : : System : : GetInstance ( ) . CpuCore ( current_thread - > GetProcessorID ( ) ) . PrepareReschedule ( ) ;
return RESULT_TIMEOUT ;
}
std : : vector < SharedPtr < Thread > > AddressArbiter : : GetThreadsWaitingOnAddress ( VAddr address ) const {
const auto RetrieveWaitingThreads = [ ] ( std : : size_t core_index ,
std : : vector < SharedPtr < Thread > > & waiting_threads ,
VAddr arb_addr ) {
const auto & scheduler = Core : : System : : GetInstance ( ) . Scheduler ( core_index ) ;
const auto & thread_list = scheduler . GetThreadList ( ) ;
for ( const auto & thread : thread_list ) {
if ( thread - > GetArbiterWaitAddress ( ) = = arb_addr )
waiting_threads . push_back ( thread ) ;
}
} ;
// Retrieve all threads that are waiting for this address.
std : : vector < SharedPtr < Thread > > threads ;
RetrieveWaitingThreads ( 0 , threads , address ) ;
RetrieveWaitingThreads ( 1 , threads , address ) ;
RetrieveWaitingThreads ( 2 , threads , address ) ;
RetrieveWaitingThreads ( 3 , threads , address ) ;
// Sort them by priority, such that the highest priority ones come first.
std : : sort ( threads . begin ( ) , threads . end ( ) ,
[ ] ( const SharedPtr < Thread > & lhs , const SharedPtr < Thread > & rhs ) {
return lhs - > GetPriority ( ) < rhs - > GetPriority ( ) ;
} ) ;
return threads ;
}
} // namespace Kernel