Kernel/Arbiters: Implement WaitForAddress
This commit is contained in:
parent
7e191dccc1
commit
9d71ce88ce
5 changed files with 71 additions and 6 deletions
|
@ -5,14 +5,31 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.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/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
#include "core/hle/lock.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
namespace AddressArbiter {
|
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->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.
|
// Signals an address being waited on.
|
||||||
ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) {
|
ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -33,14 +50,48 @@ namespace Kernel {
|
||||||
|
|
||||||
// Waits on an address if the value passed is less than the argument value, optionally decrementing.
|
// 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 WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) {
|
||||||
// TODO
|
// Ensure that we can read the address.
|
||||||
return RESULT_SUCCESS;
|
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<std::recursive_mutex> 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.
|
// Waits on an address if the value passed is equal to the argument value.
|
||||||
ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
|
ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
|
||||||
// TODO
|
// Ensure that we can read the address.
|
||||||
return RESULT_SUCCESS;
|
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 AddressArbiter
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
|
@ -29,6 +29,7 @@ enum {
|
||||||
SynchronizationCanceled = 118,
|
SynchronizationCanceled = 118,
|
||||||
TooLarge = 119,
|
TooLarge = 119,
|
||||||
InvalidEnumValue = 120,
|
InvalidEnumValue = 120,
|
||||||
|
InvalidState = 125,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ constexpr ResultCode ERR_OUT_OF_MEMORY(-1);
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
|
constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
|
||||||
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
||||||
|
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
|
||||||
constexpr ResultCode ERR_INVALID_POINTER(-1);
|
constexpr ResultCode ERR_INVALID_POINTER(-1);
|
||||||
constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
|
constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
|
||||||
constexpr ResultCode ERR_NOT_AUTHORIZED(-1);
|
constexpr ResultCode ERR_NOT_AUTHORIZED(-1);
|
||||||
|
|
|
@ -140,6 +140,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thread->arb_wait_address != 0) {
|
||||||
|
ASSERT(thread->status == THREADSTATUS_WAIT_ARB);
|
||||||
|
thread->arb_wait_address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (resume)
|
if (resume)
|
||||||
thread->ResumeFromWait();
|
thread->ResumeFromWait();
|
||||||
}
|
}
|
||||||
|
@ -179,6 +184,7 @@ void Thread::ResumeFromWait() {
|
||||||
case THREADSTATUS_WAIT_SLEEP:
|
case THREADSTATUS_WAIT_SLEEP:
|
||||||
case THREADSTATUS_WAIT_IPC:
|
case THREADSTATUS_WAIT_IPC:
|
||||||
case THREADSTATUS_WAIT_MUTEX:
|
case THREADSTATUS_WAIT_MUTEX:
|
||||||
|
case THREADSTATUS_WAIT_ARB:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case THREADSTATUS_READY:
|
case THREADSTATUS_READY:
|
||||||
|
|
|
@ -228,8 +228,10 @@ public:
|
||||||
|
|
||||||
// If waiting on a ConditionVariable, this is the ConditionVariable address
|
// If waiting on a ConditionVariable, this is the ConditionVariable address
|
||||||
VAddr condvar_wait_address;
|
VAddr condvar_wait_address;
|
||||||
VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex 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.
|
Handle wait_handle; ///< The handle used to wait for the mutex.
|
||||||
|
VAddr arb_wait_address; ///< If waiting for an AddressArbiter, this is the address
|
||||||
|
ResultCode arb_wait_result; ///< If waiting for an AddressArbiter, this is the result that will be returned.
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
|
|
@ -213,6 +213,9 @@ QString WaitTreeThread::GetText() const {
|
||||||
case THREADSTATUS_WAIT_MUTEX:
|
case THREADSTATUS_WAIT_MUTEX:
|
||||||
status = tr("waiting for mutex");
|
status = tr("waiting for mutex");
|
||||||
break;
|
break;
|
||||||
|
case THREADSTATUS_WAIT_MUTEX:
|
||||||
|
status = tr("waiting for address arbiter");
|
||||||
|
break;
|
||||||
case THREADSTATUS_DORMANT:
|
case THREADSTATUS_DORMANT:
|
||||||
status = tr("dormant");
|
status = tr("dormant");
|
||||||
break;
|
break;
|
||||||
|
@ -240,6 +243,7 @@ QColor WaitTreeThread::GetColor() const {
|
||||||
case THREADSTATUS_WAIT_SYNCH_ALL:
|
case THREADSTATUS_WAIT_SYNCH_ALL:
|
||||||
case THREADSTATUS_WAIT_SYNCH_ANY:
|
case THREADSTATUS_WAIT_SYNCH_ANY:
|
||||||
case THREADSTATUS_WAIT_MUTEX:
|
case THREADSTATUS_WAIT_MUTEX:
|
||||||
|
case THREADSTATUS_WAIT_ARB:
|
||||||
return QColor(Qt::GlobalColor::red);
|
return QColor(Qt::GlobalColor::red);
|
||||||
case THREADSTATUS_DORMANT:
|
case THREADSTATUS_DORMANT:
|
||||||
return QColor(Qt::GlobalColor::darkCyan);
|
return QColor(Qt::GlobalColor::darkCyan);
|
||||||
|
|
Loading…
Reference in a new issue