summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/kernel/process.cpp1
-rw-r--r--src/core/hle/kernel/scheduler.cpp2
-rw-r--r--src/core/hle/kernel/svc.cpp75
-rw-r--r--src/core/hle/kernel/synchronization.cpp8
-rw-r--r--src/core/hle/kernel/synchronization_object.cpp4
-rw-r--r--src/core/hle/kernel/synchronization_object.h2
-rw-r--r--src/core/hle/kernel/thread.cpp2
-rw-r--r--src/core/hle/kernel/time_manager.cpp18
-rw-r--r--src/core/hle/kernel/time_manager.h5
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