mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-07-04 23:31:19 +01:00
Kernel: Fixes, corrections and asserts to scheduler and different svcs.
This commit is contained in:
parent
4217e58a10
commit
6515c6e8c6
8 changed files with 38 additions and 38 deletions
|
@ -34,19 +34,9 @@ void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& wai
|
||||||
|
|
||||||
// Signal the waiting threads.
|
// Signal the waiting threads.
|
||||||
for (std::size_t i = 0; i < last; i++) {
|
for (std::size_t i = 0; i < last; i++) {
|
||||||
if (waiting_threads[i]->GetStatus() != ThreadStatus::WaitArb) {
|
|
||||||
last++;
|
|
||||||
last = std::min(waiting_threads.size(), last);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_manager.CancelTimeEvent(waiting_threads[i].get());
|
|
||||||
|
|
||||||
ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb);
|
|
||||||
waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
||||||
RemoveThread(waiting_threads[i]);
|
RemoveThread(waiting_threads[i]);
|
||||||
waiting_threads[i]->WaitForArbitration(false);
|
waiting_threads[i]->WaitForArbitration(false);
|
||||||
waiting_threads[i]->SetArbiterWaitAddress(0);
|
|
||||||
waiting_threads[i]->ResumeFromWait();
|
waiting_threads[i]->ResumeFromWait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,20 +162,25 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
|
||||||
{
|
{
|
||||||
SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
||||||
|
|
||||||
|
if (current_thread->IsPendingTermination()) {
|
||||||
|
lock.CancelSleep();
|
||||||
|
return ERR_THREAD_TERMINATING;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that we can read the address.
|
// Ensure that we can read the address.
|
||||||
if (!memory.IsValidVirtualAddress(address)) {
|
if (!memory.IsValidVirtualAddress(address)) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
return ERR_INVALID_ADDRESS_STATE;
|
return ERR_INVALID_ADDRESS_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO(Blinkhawk): Check termination pending.
|
|
||||||
|
|
||||||
s32 current_value = static_cast<s32>(memory.Read32(address));
|
s32 current_value = static_cast<s32>(memory.Read32(address));
|
||||||
if (current_value >= value) {
|
if (current_value >= value) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
return ERR_INVALID_STATE;
|
return ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
||||||
|
|
||||||
s32 decrement_value;
|
s32 decrement_value;
|
||||||
|
|
||||||
const std::size_t current_core = system.CurrentCoreIndex();
|
const std::size_t current_core = system.CurrentCoreIndex();
|
||||||
|
@ -207,7 +202,6 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
|
||||||
return RESULT_TIMEOUT;
|
return RESULT_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
|
||||||
current_thread->SetArbiterWaitAddress(address);
|
current_thread->SetArbiterWaitAddress(address);
|
||||||
InsertThread(SharedFrom(current_thread));
|
InsertThread(SharedFrom(current_thread));
|
||||||
current_thread->SetStatus(ThreadStatus::WaitArb);
|
current_thread->SetStatus(ThreadStatus::WaitArb);
|
||||||
|
@ -239,14 +233,17 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
|
||||||
{
|
{
|
||||||
SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
||||||
|
|
||||||
|
if (current_thread->IsPendingTermination()) {
|
||||||
|
lock.CancelSleep();
|
||||||
|
return ERR_THREAD_TERMINATING;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that we can read the address.
|
// Ensure that we can read the address.
|
||||||
if (!memory.IsValidVirtualAddress(address)) {
|
if (!memory.IsValidVirtualAddress(address)) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
return ERR_INVALID_ADDRESS_STATE;
|
return ERR_INVALID_ADDRESS_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO(Blinkhawk): Check termination pending.
|
|
||||||
|
|
||||||
s32 current_value = static_cast<s32>(memory.Read32(address));
|
s32 current_value = static_cast<s32>(memory.Read32(address));
|
||||||
if (current_value != value) {
|
if (current_value != value) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
|
|
|
@ -49,6 +49,7 @@ namespace Kernel {
|
||||||
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
|
* @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
|
||||||
*/
|
*/
|
||||||
static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) {
|
static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) {
|
||||||
|
UNREACHABLE();
|
||||||
const auto proper_handle = static_cast<Handle>(thread_handle);
|
const auto proper_handle = static_cast<Handle>(thread_handle);
|
||||||
const auto& system = Core::System::GetInstance();
|
const auto& system = Core::System::GetInstance();
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,7 @@ u32 GlobalScheduler::SelectThreads() {
|
||||||
u32 cores_needing_context_switch{};
|
u32 cores_needing_context_switch{};
|
||||||
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
Scheduler& sched = kernel.Scheduler(core);
|
Scheduler& sched = kernel.Scheduler(core);
|
||||||
|
ASSERT(top_threads[core] == nullptr || top_threads[core]->GetProcessorID() == core);
|
||||||
if (update_thread(top_threads[core], sched)) {
|
if (update_thread(top_threads[core], sched)) {
|
||||||
cores_needing_context_switch |= (1ul << core);
|
cores_needing_context_switch |= (1ul << core);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +245,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread
|
||||||
winner = yielding_thread;
|
winner = yielding_thread;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
winner = scheduled_queue[i].front();
|
winner = scheduled_queue[core_id].front();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernel.GetCurrentHostThreadID() != core_id) {
|
if (kernel.GetCurrentHostThreadID() != core_id) {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
class Fiber;
|
class Fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -133,7 +133,8 @@ private:
|
||||||
/// and reschedules current core if needed.
|
/// and reschedules current core if needed.
|
||||||
void Unlock();
|
void Unlock();
|
||||||
|
|
||||||
void EnableInterruptAndSchedule(u32 cores_pending_reschedule, Core::EmuThreadHandle global_thread);
|
void EnableInterruptAndSchedule(u32 cores_pending_reschedule,
|
||||||
|
Core::EmuThreadHandle global_thread);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a thread to the suggested queue of a cpu core. Suggested threads may be
|
* Add a thread to the suggested queue of a cpu core. Suggested threads may be
|
||||||
|
|
|
@ -1562,6 +1562,11 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
|
||||||
|
|
||||||
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
||||||
|
|
||||||
|
if (thread->IsPendingTermination()) {
|
||||||
|
lock.CancelSleep();
|
||||||
|
return ERR_THREAD_TERMINATING;
|
||||||
|
}
|
||||||
|
|
||||||
const auto release_result = current_process->GetMutex().Release(mutex_addr);
|
const auto release_result = current_process->GetMutex().Release(mutex_addr);
|
||||||
if (release_result.IsError()) {
|
if (release_result.IsError()) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
|
@ -1588,6 +1593,11 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
|
||||||
{
|
{
|
||||||
SchedulerLock lock(kernel);
|
SchedulerLock lock(kernel);
|
||||||
|
|
||||||
|
auto* owner = current_thread->GetLockOwner();
|
||||||
|
if (owner != nullptr) {
|
||||||
|
owner->RemoveMutexWaiter(SharedFrom(current_thread));
|
||||||
|
}
|
||||||
|
|
||||||
current_process->RemoveConditionVariableThread(SharedFrom(current_thread));
|
current_process->RemoveConditionVariableThread(SharedFrom(current_thread));
|
||||||
}
|
}
|
||||||
// Note: Deliberately don't attempt to inherit the lock owner's priority.
|
// Note: Deliberately don't attempt to inherit the lock owner's priority.
|
||||||
|
@ -1618,19 +1628,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
||||||
for (std::size_t index = 0; index < last; ++index) {
|
for (std::size_t index = 0; index < last; ++index) {
|
||||||
auto& thread = waiting_threads[index];
|
auto& thread = waiting_threads[index];
|
||||||
|
|
||||||
if (thread->GetStatus() != ThreadStatus::WaitCondVar) {
|
|
||||||
last++;
|
|
||||||
last = std::min(waiting_threads.size(), last);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_manager.CancelTimeEvent(thread.get());
|
|
||||||
|
|
||||||
ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
|
ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
|
||||||
|
|
||||||
// liberate Cond Var Thread.
|
// liberate Cond Var Thread.
|
||||||
current_process->RemoveConditionVariableThread(thread);
|
current_process->RemoveConditionVariableThread(thread);
|
||||||
thread->SetCondVarWaitAddress(0);
|
|
||||||
|
|
||||||
const std::size_t current_core = system.CurrentCoreIndex();
|
const std::size_t current_core = system.CurrentCoreIndex();
|
||||||
auto& monitor = system.Monitor();
|
auto& monitor = system.Monitor();
|
||||||
|
@ -1655,9 +1656,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
||||||
monitor.ClearExclusive();
|
monitor.ClearExclusive();
|
||||||
if (mutex_val == 0) {
|
if (mutex_val == 0) {
|
||||||
// We were able to acquire the mutex, resume this thread.
|
// We were able to acquire the mutex, resume this thread.
|
||||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
|
|
||||||
thread->ResumeFromWait();
|
|
||||||
|
|
||||||
auto* const lock_owner = thread->GetLockOwner();
|
auto* const lock_owner = thread->GetLockOwner();
|
||||||
if (lock_owner != nullptr) {
|
if (lock_owner != nullptr) {
|
||||||
lock_owner->RemoveMutexWaiter(thread);
|
lock_owner->RemoveMutexWaiter(thread);
|
||||||
|
@ -1665,13 +1663,16 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
||||||
|
|
||||||
thread->SetLockOwner(nullptr);
|
thread->SetLockOwner(nullptr);
|
||||||
thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
||||||
|
thread->ResumeFromWait();
|
||||||
} else {
|
} else {
|
||||||
// The mutex is already owned by some other thread, make this thread wait on it.
|
// The mutex is already owned by some other thread, make this thread wait on it.
|
||||||
const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||||
auto owner = handle_table.Get<Thread>(owner_handle);
|
auto owner = handle_table.Get<Thread>(owner_handle);
|
||||||
ASSERT(owner);
|
ASSERT(owner);
|
||||||
thread->SetStatus(ThreadStatus::WaitMutex);
|
if (thread->GetStatus() == ThreadStatus::WaitCondVar) {
|
||||||
|
thread->SetStatus(ThreadStatus::WaitMutex);
|
||||||
|
}
|
||||||
|
|
||||||
owner->AddMutexWaiter(thread);
|
owner->AddMutexWaiter(thread);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,10 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const {
|
||||||
if (obj.IsSignaled()) {
|
if (obj.IsSignaled()) {
|
||||||
for (auto thread : obj.GetWaitingThreads()) {
|
for (auto thread : obj.GetWaitingThreads()) {
|
||||||
if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
|
if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
|
||||||
|
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
|
||||||
|
ASSERT(thread->IsWaitingSync());
|
||||||
thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
|
thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
|
||||||
thread->ResumeFromWait();
|
thread->ResumeFromWait();
|
||||||
time_manager.CancelTimeEvent(thread.get());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obj.ClearWaitingThreads();
|
obj.ClearWaitingThreads();
|
||||||
|
@ -91,10 +92,11 @@ std::pair<ResultCode, Handle> Synchronization::WaitFor(
|
||||||
ResultCode signaling_result = thread->GetSignalingResult();
|
ResultCode signaling_result = thread->GetSignalingResult();
|
||||||
SynchronizationObject* signaling_object = thread->GetSignalingObject();
|
SynchronizationObject* signaling_object = thread->GetSignalingObject();
|
||||||
thread->SetSynchronizationObjects(nullptr);
|
thread->SetSynchronizationObjects(nullptr);
|
||||||
|
auto shared_thread = SharedFrom(thread);
|
||||||
for (auto& obj : sync_objects) {
|
for (auto& obj : sync_objects) {
|
||||||
obj->RemoveWaitingThread(SharedFrom(thread));
|
obj->RemoveWaitingThread(shared_thread);
|
||||||
}
|
}
|
||||||
if (signaling_result == RESULT_SUCCESS) {
|
if (signaling_object != nullptr) {
|
||||||
const auto itr = std::find_if(
|
const auto itr = std::find_if(
|
||||||
sync_objects.begin(), sync_objects.end(),
|
sync_objects.begin(), sync_objects.end(),
|
||||||
[signaling_object](const std::shared_ptr<SynchronizationObject>& object) {
|
[signaling_object](const std::shared_ptr<SynchronizationObject>& object) {
|
||||||
|
@ -103,7 +105,7 @@ std::pair<ResultCode, Handle> Synchronization::WaitFor(
|
||||||
ASSERT(itr != sync_objects.end());
|
ASSERT(itr != sync_objects.end());
|
||||||
signaling_object->Acquire(thread);
|
signaling_object->Acquire(thread);
|
||||||
const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
|
const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
|
||||||
return {RESULT_SUCCESS, index};
|
return {signaling_result, index};
|
||||||
}
|
}
|
||||||
return {signaling_result, -1};
|
return {signaling_result, -1};
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
|
||||||
if (cancelled_events[proper_handle]) {
|
if (cancelled_events[proper_handle]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
event_fired[proper_handle] = true;
|
|
||||||
std::shared_ptr<Thread> thread =
|
std::shared_ptr<Thread> thread =
|
||||||
this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
|
this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
|
||||||
thread->OnWakeUp();
|
thread->OnWakeUp();
|
||||||
|
@ -39,7 +38,6 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64
|
||||||
event_handle = InvalidHandle;
|
event_handle = InvalidHandle;
|
||||||
}
|
}
|
||||||
cancelled_events[event_handle] = false;
|
cancelled_events[event_handle] = false;
|
||||||
event_fired[event_handle] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
|
void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
|
||||||
|
|
|
@ -42,7 +42,6 @@ private:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
|
std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
|
||||||
std::unordered_map<Handle, bool> cancelled_events;
|
std::unordered_map<Handle, bool> cancelled_events;
|
||||||
std::unordered_map<Handle, bool> event_fired;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
Loading…
Reference in a new issue