summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-26 22:26:53 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:35:17 -0400
commitd4ebb510a05d29befde6556e632413e5b35b9ab5 (patch)
tree309755a4ef21b48f12cca6c40798dccd191cf860 /src
parentSVC: Cleanup old methods. (diff)
downloadyuzu-d4ebb510a05d29befde6556e632413e5b35b9ab5.tar.gz
yuzu-d4ebb510a05d29befde6556e632413e5b35b9ab5.tar.xz
yuzu-d4ebb510a05d29befde6556e632413e5b35b9ab5.zip
SVC: Correct WaitSynchronization, WaitProcessWideKey, SignalProcessWideKey.
Diffstat (limited to 'src')
-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) {
187 } 187 }
188 ++it; 188 ++it;
189 } 189 }
190 UNREACHABLE();
191} 190}
192 191
193std::vector<std::shared_ptr<Thread>> Process::GetConditionVariableThreads( 192std::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() {
632 cpu_core.SaveContext(previous_thread->GetContext64()); 632 cpu_core.SaveContext(previous_thread->GetContext64());
633 // Save the TPIDR_EL0 system register in case it was modified. 633 // Save the TPIDR_EL0 system register in case it was modified.
634 previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); 634 previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
635 635 cpu_core.ClearExclusiveState();
636 } 636 }
637 if (previous_thread->GetStatus() == ThreadStatus::Running) { 637 if (previous_thread->GetStatus() == ThreadStatus::Running) {
638 previous_thread->SetStatus(ThreadStatus::Ready); 638 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
1541 return ERR_INVALID_ADDRESS; 1541 return ERR_INVALID_ADDRESS;
1542 } 1542 }
1543 1543
1544 UNIMPLEMENTED();
1545
1546 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); 1544 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
1547 1545 auto& kernel = system.Kernel();
1546 Handle event_handle;
1547 Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
1548 auto* const current_process = system.Kernel().CurrentProcess(); 1548 auto* const current_process = system.Kernel().CurrentProcess();
1549 const auto& handle_table = current_process->GetHandleTable(); 1549 {
1550 std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1550 SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds);
1551 ASSERT(thread); 1551 const auto& handle_table = current_process->GetHandleTable();
1552 std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1553 ASSERT(thread);
1554
1555 current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
1556
1557 const auto release_result = current_process->GetMutex().Release(mutex_addr);
1558 if (release_result.IsError()) {
1559 lock.CancelSleep();
1560 return release_result;
1561 }
1552 1562
1553 const auto release_result = current_process->GetMutex().Release(mutex_addr); 1563 if (nano_seconds == 0) {
1554 if (release_result.IsError()) { 1564 lock.CancelSleep();
1555 return release_result; 1565 return RESULT_TIMEOUT;
1566 }
1567
1568 current_thread->SetCondVarWaitAddress(condition_variable_addr);
1569 current_thread->SetMutexWaitAddress(mutex_addr);
1570 current_thread->SetWaitHandle(thread_handle);
1571 current_thread->SetStatus(ThreadStatus::WaitCondVar);
1572 current_process->InsertConditionVariableThread(SharedFrom(current_thread));
1556 } 1573 }
1557 1574
1558 Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); 1575 if (event_handle != InvalidHandle) {
1559 current_thread->SetCondVarWaitAddress(condition_variable_addr); 1576 auto& time_manager = kernel.TimeManager();
1560 current_thread->SetMutexWaitAddress(mutex_addr); 1577 time_manager.UnscheduleTimeEvent(event_handle);
1561 current_thread->SetWaitHandle(thread_handle); 1578 }
1562 current_thread->SetStatus(ThreadStatus::WaitCondVar);
1563 current_thread->InvalidateWakeupCallback();
1564 current_process->InsertConditionVariableThread(SharedFrom(current_thread));
1565 1579
1566 current_thread->WakeAfterDelay(nano_seconds); 1580 {
1581 SchedulerLock lock(kernel);
1567 1582
1583 current_process->RemoveConditionVariableThread(SharedFrom(current_thread));
1584 }
1568 // Note: Deliberately don't attempt to inherit the lock owner's priority. 1585 // Note: Deliberately don't attempt to inherit the lock owner's priority.
1569 1586
1570 return RESULT_SUCCESS; 1587 return current_thread->GetSignalingResult();
1571} 1588}
1572 1589
1573/// Signal process wide key 1590/// Signal process wide key
@@ -1577,10 +1594,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
1577 1594
1578 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); 1595 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
1579 1596
1580 UNIMPLEMENTED();
1581
1582 // Retrieve a list of all threads that are waiting for this condition variable. 1597 // Retrieve a list of all threads that are waiting for this condition variable.
1583 auto* const current_process = system.Kernel().CurrentProcess(); 1598 auto& kernel = system.Kernel();
1599 SchedulerLock lock(kernel);
1600 auto* const current_process = kernel.CurrentProcess();
1584 std::vector<std::shared_ptr<Thread>> waiting_threads = 1601 std::vector<std::shared_ptr<Thread>> waiting_threads =
1585 current_process->GetConditionVariableThreads(condition_variable_addr); 1602 current_process->GetConditionVariableThreads(condition_variable_addr);
1586 1603
@@ -1589,10 +1606,18 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
1589 std::size_t last = waiting_threads.size(); 1606 std::size_t last = waiting_threads.size();
1590 if (target > 0) 1607 if (target > 0)
1591 last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); 1608 last = std::min(waiting_threads.size(), static_cast<std::size_t>(target));
1592 1609 auto& time_manager = kernel.TimeManager();
1593 for (std::size_t index = 0; index < last; ++index) { 1610 for (std::size_t index = 0; index < last; ++index) {
1594 auto& thread = waiting_threads[index]; 1611 auto& thread = waiting_threads[index];
1595 1612
1613 if (thread->GetStatus() != ThreadStatus::WaitCondVar) {
1614 last++;
1615 last = std::min(waiting_threads.size(), last);
1616 continue;
1617 }
1618
1619 time_manager.CancelTimeEvent(thread.get());
1620
1596 ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); 1621 ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
1597 1622
1598 // liberate Cond Var Thread. 1623 // liberate Cond Var Thread.
@@ -1630,17 +1655,13 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
1630 } 1655 }
1631 1656
1632 thread->SetLockOwner(nullptr); 1657 thread->SetLockOwner(nullptr);
1633 thread->SetMutexWaitAddress(0); 1658 thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
1634 thread->SetWaitHandle(0);
1635 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
1636 } else { 1659 } else {
1637 // The mutex is already owned by some other thread, make this thread wait on it. 1660 // The mutex is already owned by some other thread, make this thread wait on it.
1638 const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); 1661 const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
1639 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1662 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1640 auto owner = handle_table.Get<Thread>(owner_handle); 1663 auto owner = handle_table.Get<Thread>(owner_handle);
1641 ASSERT(owner); 1664 ASSERT(owner);
1642 ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
1643 thread->InvalidateWakeupCallback();
1644 thread->SetStatus(ThreadStatus::WaitMutex); 1665 thread->SetStatus(ThreadStatus::WaitMutex);
1645 1666
1646 owner->AddMutexWaiter(thread); 1667 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 {
17Synchronization::Synchronization(Core::System& system) : system{system} {} 17Synchronization::Synchronization(Core::System& system) : system{system} {}
18 18
19void Synchronization::SignalObject(SynchronizationObject& obj) const { 19void Synchronization::SignalObject(SynchronizationObject& obj) const {
20 SchedulerLock lock(system.Kernel()); 20 auto& kernel = system.Kernel();
21 SchedulerLock lock(kernel);
22 auto& time_manager = kernel.TimeManager();
21 if (obj.IsSignaled()) { 23 if (obj.IsSignaled()) {
22 for (auto thread : obj.GetWaitingThreads()) { 24 for (auto thread : obj.GetWaitingThreads()) {
23 if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { 25 if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
24 thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); 26 thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
25 thread->ResumeFromWait(); 27 thread->ResumeFromWait();
28 time_manager.CancelTimeEvent(thread.get());
26 } 29 }
27 } 30 }
28 } 31 }
@@ -79,6 +82,9 @@ std::pair<ResultCode, Handle> Synchronization::WaitFor(
79 SchedulerLock lock(kernel); 82 SchedulerLock lock(kernel);
80 ResultCode signaling_result = thread->GetSignalingResult(); 83 ResultCode signaling_result = thread->GetSignalingResult();
81 SynchronizationObject* signaling_object = thread->GetSignalingObject(); 84 SynchronizationObject* signaling_object = thread->GetSignalingObject();
85 for (auto& obj : sync_objects) {
86 obj->RemoveWaitingThread(SharedFrom(thread));
87 }
82 if (signaling_result == RESULT_SUCCESS) { 88 if (signaling_result == RESULT_SUCCESS) {
83 const auto itr = std::find_if( 89 const auto itr = std::find_if(
84 sync_objects.begin(), sync_objects.end(), 90 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() {
102 } 102 }
103} 103}
104 104
105void SynchronizationObject::ClearWaitingThreads() {
106 waiting_threads.clear();
107}
108
105const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const { 109const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
106 return waiting_threads; 110 return waiting_threads;
107} 111}
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:
68 /// Get a const reference to the waiting threads list for debug use 68 /// Get a const reference to the waiting threads list for debug use
69 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; 69 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
70 70
71 void ClearWaitingThreads();
72
71protected: 73protected:
72 bool is_signaled{}; // Tells if this sync object is signalled; 74 bool is_signaled{}; // Tells if this sync object is signalled;
73 75
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;
49void Thread::Stop() { 49void Thread::Stop() {
50 SchedulerLock lock(kernel); 50 SchedulerLock lock(kernel);
51 // Cancel any outstanding wakeup events for this thread 51 // Cancel any outstanding wakeup events for this thread
52 Signal();
52 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), 53 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
53 global_handle); 54 global_handle);
54 kernel.GlobalHandleTable().Close(global_handle); 55 kernel.GlobalHandleTable().Close(global_handle);
55 global_handle = 0; 56 global_handle = 0;
56 SetStatus(ThreadStatus::Dead); 57 SetStatus(ThreadStatus::Dead);
57 Signal();
58 58
59 owner_process->UnregisterThread(this); 59 owner_process->UnregisterThread(this);
60 60
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 @@
8#include "core/core_timing_util.h" 8#include "core/core_timing_util.h"
9#include "core/hle/kernel/handle_table.h" 9#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/scheduler.h"
11#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
12#include "core/hle/kernel/time_manager.h" 13#include "core/hle/kernel/time_manager.h"
13 14
14namespace Kernel { 15namespace Kernel {
15 16
16TimeManager::TimeManager(Core::System& system) : system{system} { 17TimeManager::TimeManager(Core::System& system_) : system{system_} {
17 time_manager_event_type = Core::Timing::CreateEvent( 18 time_manager_event_type = Core::Timing::CreateEvent(
18 "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { 19 "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) {
20 SchedulerLock lock(system.Kernel());
19 Handle proper_handle = static_cast<Handle>(thread_handle); 21 Handle proper_handle = static_cast<Handle>(thread_handle);
22 if (cancelled_events[proper_handle]) {
23 return;
24 }
25 event_fired[proper_handle] = true;
20 std::shared_ptr<Thread> thread = 26 std::shared_ptr<Thread> thread =
21 this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); 27 this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
22 thread->OnWakeUp(); 28 thread->OnWakeUp();
@@ -24,14 +30,16 @@ TimeManager::TimeManager(Core::System& system) : system{system} {
24} 30}
25 31
26void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { 32void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) {
33 event_handle = timetask->GetGlobalHandle();
27 if (nanoseconds > 0) { 34 if (nanoseconds > 0) {
28 ASSERT(timetask); 35 ASSERT(timetask);
29 event_handle = timetask->GetGlobalHandle();
30 const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); 36 const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
31 system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle); 37 system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle);
32 } else { 38 } else {
33 event_handle = InvalidHandle; 39 event_handle = InvalidHandle;
34 } 40 }
41 cancelled_events[event_handle] = false;
42 event_fired[event_handle] = false;
35} 43}
36 44
37void TimeManager::UnscheduleTimeEvent(Handle event_handle) { 45void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
@@ -39,6 +47,12 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
39 return; 47 return;
40 } 48 }
41 system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); 49 system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
50 cancelled_events[event_handle] = true;
51}
52
53void TimeManager::CancelTimeEvent(Thread* time_task) {
54 Handle event_handle = time_task->GetGlobalHandle();
55 UnscheduleTimeEvent(event_handle);
42} 56}
43 57
44} // namespace Kernel 58} // 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 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <unordered_map>
8 9
9#include "core/hle/kernel/object.h" 10#include "core/hle/kernel/object.h"
10 11
@@ -35,9 +36,13 @@ public:
35 /// Unschedule an existing time event 36 /// Unschedule an existing time event
36 void UnscheduleTimeEvent(Handle event_handle); 37 void UnscheduleTimeEvent(Handle event_handle);
37 38
39 void CancelTimeEvent(Thread* time_task);
40
38private: 41private:
39 Core::System& system; 42 Core::System& system;
40 std::shared_ptr<Core::Timing::EventType> time_manager_event_type; 43 std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
44 std::unordered_map<Handle, bool> cancelled_events;
45 std::unordered_map<Handle, bool> event_fired;
41}; 46};
42 47
43} // namespace Kernel 48} // namespace Kernel