diff options
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 75 | ||||
| -rw-r--r-- | src/core/hle/kernel/synchronization.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/synchronization_object.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/synchronization_object.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.cpp | 18 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.h | 5 | 
9 files changed, 84 insertions, 33 deletions
| diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index cd4b0aa60..ea5fe5b29 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -187,7 +187,6 @@ void Process::RemoveConditionVariableThread(std::shared_ptr<Thread> thread) {          }          ++it;      } -    UNREACHABLE();  }  std::vector<std::shared_ptr<Thread>> Process::GetConditionVariableThreads( diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 0e85ee69e..758fa8188 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -632,7 +632,7 @@ void Scheduler::SwitchContext() {              cpu_core.SaveContext(previous_thread->GetContext64());              // Save the TPIDR_EL0 system register in case it was modified.              previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
 - +            cpu_core.ClearExclusiveState();          }          if (previous_thread->GetStatus() == ThreadStatus::Running) {              previous_thread->SetStatus(ThreadStatus::Ready); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8634d3feb..a5193063b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1541,33 +1541,50 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add          return ERR_INVALID_ADDRESS;      } -    UNIMPLEMENTED(); -      ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); - +    auto& kernel = system.Kernel(); +    Handle event_handle; +    Thread* current_thread = system.CurrentScheduler().GetCurrentThread();      auto* const current_process = system.Kernel().CurrentProcess(); -    const auto& handle_table = current_process->GetHandleTable(); -    std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); -    ASSERT(thread); +    { +        SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds); +        const auto& handle_table = current_process->GetHandleTable(); +        std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); +        ASSERT(thread); + +        current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + +        const auto release_result = current_process->GetMutex().Release(mutex_addr); +        if (release_result.IsError()) { +            lock.CancelSleep(); +            return release_result; +        } -    const auto release_result = current_process->GetMutex().Release(mutex_addr); -    if (release_result.IsError()) { -        return release_result; +        if (nano_seconds == 0) { +            lock.CancelSleep(); +            return RESULT_TIMEOUT; +        } + +        current_thread->SetCondVarWaitAddress(condition_variable_addr); +        current_thread->SetMutexWaitAddress(mutex_addr); +        current_thread->SetWaitHandle(thread_handle); +        current_thread->SetStatus(ThreadStatus::WaitCondVar); +        current_process->InsertConditionVariableThread(SharedFrom(current_thread));      } -    Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); -    current_thread->SetCondVarWaitAddress(condition_variable_addr); -    current_thread->SetMutexWaitAddress(mutex_addr); -    current_thread->SetWaitHandle(thread_handle); -    current_thread->SetStatus(ThreadStatus::WaitCondVar); -    current_thread->InvalidateWakeupCallback(); -    current_process->InsertConditionVariableThread(SharedFrom(current_thread)); +    if (event_handle != InvalidHandle) { +        auto& time_manager = kernel.TimeManager(); +        time_manager.UnscheduleTimeEvent(event_handle); +    } -    current_thread->WakeAfterDelay(nano_seconds); +    { +        SchedulerLock lock(kernel); +        current_process->RemoveConditionVariableThread(SharedFrom(current_thread)); +    }      // Note: Deliberately don't attempt to inherit the lock owner's priority. -    return RESULT_SUCCESS; +    return current_thread->GetSignalingResult();  }  /// Signal process wide key @@ -1577,10 +1594,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_      ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); -    UNIMPLEMENTED(); -      // Retrieve a list of all threads that are waiting for this condition variable. -    auto* const current_process = system.Kernel().CurrentProcess(); +    auto& kernel = system.Kernel(); +    SchedulerLock lock(kernel); +    auto* const current_process = kernel.CurrentProcess();      std::vector<std::shared_ptr<Thread>> waiting_threads =          current_process->GetConditionVariableThreads(condition_variable_addr); @@ -1589,10 +1606,18 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_      std::size_t last = waiting_threads.size();      if (target > 0)          last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); - +    auto& time_manager = kernel.TimeManager();      for (std::size_t index = 0; index < last; ++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);          // liberate Cond Var Thread. @@ -1630,17 +1655,13 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_              }              thread->SetLockOwner(nullptr); -            thread->SetMutexWaitAddress(0); -            thread->SetWaitHandle(0); -            thread->SetWaitSynchronizationResult(RESULT_SUCCESS); +            thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);          } else {              // 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 auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();              auto owner = handle_table.Get<Thread>(owner_handle);              ASSERT(owner); -            ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); -            thread->InvalidateWakeupCallback();              thread->SetStatus(ThreadStatus::WaitMutex);              owner->AddMutexWaiter(thread); diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index b36e550a0..c60c5bb42 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -17,12 +17,15 @@ namespace Kernel {  Synchronization::Synchronization(Core::System& system) : system{system} {}  void Synchronization::SignalObject(SynchronizationObject& obj) const { -    SchedulerLock lock(system.Kernel()); +    auto& kernel = system.Kernel(); +    SchedulerLock lock(kernel); +    auto& time_manager = kernel.TimeManager();      if (obj.IsSignaled()) {          for (auto thread : obj.GetWaitingThreads()) {              if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {                  thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);                  thread->ResumeFromWait(); +                time_manager.CancelTimeEvent(thread.get());              }          }      } @@ -79,6 +82,9 @@ std::pair<ResultCode, Handle> Synchronization::WaitFor(          SchedulerLock lock(kernel);          ResultCode signaling_result = thread->GetSignalingResult();          SynchronizationObject* signaling_object = thread->GetSignalingObject(); +        for (auto& obj : sync_objects) { +            obj->RemoveWaitingThread(SharedFrom(thread)); +        }          if (signaling_result == RESULT_SUCCESS) {              const auto itr = std::find_if(                  sync_objects.begin(), sync_objects.end(), diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index 43f3eef18..be9e09106 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -102,6 +102,10 @@ void SynchronizationObject::WakeupAllWaitingThreads() {      }  } +void SynchronizationObject::ClearWaitingThreads() { +    waiting_threads.clear(); +} +  const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {      return waiting_threads;  } diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index 0a0d069e0..a35544ac1 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -68,6 +68,8 @@ public:      /// Get a const reference to the waiting threads list for debug use      const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; +    void ClearWaitingThreads(); +  protected:      bool is_signaled{}; // Tells if this sync object is signalled; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fb97535a3..a645ee3a2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -49,12 +49,12 @@ Thread::~Thread() = default;  void Thread::Stop() {      SchedulerLock lock(kernel);      // Cancel any outstanding wakeup events for this thread +    Signal();      Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),                                                               global_handle);      kernel.GlobalHandleTable().Close(global_handle);      global_handle = 0;      SetStatus(ThreadStatus::Dead); -    Signal();      owner_process->UnregisterThread(this); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 0b8f0d993..dab5fc4c6 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -8,15 +8,21 @@  #include "core/core_timing_util.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h"  #include "core/hle/kernel/thread.h"  #include "core/hle/kernel/time_manager.h"  namespace Kernel { -TimeManager::TimeManager(Core::System& system) : system{system} { +TimeManager::TimeManager(Core::System& system_) : system{system_} {      time_manager_event_type = Core::Timing::CreateEvent(          "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { +            SchedulerLock lock(system.Kernel());              Handle proper_handle = static_cast<Handle>(thread_handle); +            if (cancelled_events[proper_handle]) { +                return; +            } +            event_fired[proper_handle] = true;              std::shared_ptr<Thread> thread =                  this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);              thread->OnWakeUp(); @@ -24,14 +30,16 @@ TimeManager::TimeManager(Core::System& system) : system{system} {  }  void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { +    event_handle = timetask->GetGlobalHandle();      if (nanoseconds > 0) {          ASSERT(timetask); -        event_handle = timetask->GetGlobalHandle();          const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});          system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle);      } else {          event_handle = InvalidHandle;      } +    cancelled_events[event_handle] = false; +    event_fired[event_handle] = false;  }  void TimeManager::UnscheduleTimeEvent(Handle event_handle) { @@ -39,6 +47,12 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) {          return;      }      system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); +    cancelled_events[event_handle] = true; +} + +void TimeManager::CancelTimeEvent(Thread* time_task) { +    Handle event_handle = time_task->GetGlobalHandle(); +    UnscheduleTimeEvent(event_handle);  }  } // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index eaec486d1..3080ac838 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -5,6 +5,7 @@  #pragma once  #include <memory> +#include <unordered_map>  #include "core/hle/kernel/object.h" @@ -35,9 +36,13 @@ public:      /// Unschedule an existing time event      void UnscheduleTimeEvent(Handle event_handle); +    void CancelTimeEvent(Thread* time_task); +  private:      Core::System& system;      std::shared_ptr<Core::Timing::EventType> time_manager_event_type; +    std::unordered_map<Handle, bool> cancelled_events; +    std::unordered_map<Handle, bool> event_fired;  };  } // namespace Kernel | 
