summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-04-01 17:28:49 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:36:05 -0400
commit48fa3b7a0f2054a836b0a8061e6b082c246b5ae0 (patch)
tree37a09cfb55f13ebf2df2b9a71622c599733100b0
parentKernel/svcBreak: Implement CacheInvalidation for Singlecore and correct svcBr... (diff)
downloadyuzu-48fa3b7a0f2054a836b0a8061e6b082c246b5ae0.tar.gz
yuzu-48fa3b7a0f2054a836b0a8061e6b082c246b5ae0.tar.xz
yuzu-48fa3b7a0f2054a836b0a8061e6b082c246b5ae0.zip
General: Cleanup legacy code.
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp1
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp1
-rw-r--r--src/core/core_manager.cpp51
-rw-r--r--src/core/core_manager.h63
-rw-r--r--src/core/gdbstub/gdbstub.cpp1
-rw-r--r--src/core/hle/kernel/client_port.cpp2
-rw-r--r--src/core/hle/kernel/kernel.cpp81
-rw-r--r--src/core/hle/kernel/kernel.h3
-rw-r--r--src/core/hle/kernel/svc.cpp3
-rw-r--r--src/core/hle/kernel/synchronization_object.cpp64
-rw-r--r--src/core/hle/kernel/synchronization_object.h15
-rw-r--r--src/core/hle/kernel/thread.cpp34
-rw-r--r--src/core/hle/kernel/thread.h56
-rw-r--r--src/core/hle/service/sm/sm.cpp2
-rw-r--r--src/core/host_timing.cpp206
-rw-r--r--src/core/host_timing.h160
-rw-r--r--src/tests/core/core_timing.cpp1
-rw-r--r--src/yuzu/debugger/wait_tree.cpp2
19 files changed, 8 insertions, 740 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 552094ddb..653b7620b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -17,8 +17,6 @@ add_library(core STATIC
17 constants.h 17 constants.h
18 core.cpp 18 core.cpp
19 core.h 19 core.h
20 core_manager.cpp
21 core_manager.h
22 core_timing.cpp 20 core_timing.cpp
23 core_timing.h 21 core_timing.h
24 core_timing_util.cpp 22 core_timing_util.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index c4aeedef9..c8adf2866 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -12,7 +12,6 @@
12#include "core/arm/dynarmic/arm_dynarmic_64.h" 12#include "core/arm/dynarmic/arm_dynarmic_64.h"
13#include "core/arm/dynarmic/arm_dynarmic_cp15.h" 13#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_manager.h"
16#include "core/core_timing.h" 15#include "core/core_timing.h"
17#include "core/hle/kernel/svc.h" 16#include "core/hle/kernel/svc.h"
18#include "core/memory.h" 17#include "core/memory.h"
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index a518733b6..14b394368 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -11,7 +11,6 @@
11#include "core/arm/cpu_interrupt_handler.h" 11#include "core/arm/cpu_interrupt_handler.h"
12#include "core/arm/dynarmic/arm_dynarmic_64.h" 12#include "core/arm/dynarmic/arm_dynarmic_64.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/core_manager.h"
15#include "core/core_timing.h" 14#include "core/core_timing.h"
16#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
17#include "core/gdbstub/gdbstub.h" 16#include "core/gdbstub/gdbstub.h"
diff --git a/src/core/core_manager.cpp b/src/core/core_manager.cpp
deleted file mode 100644
index 82d7acb40..000000000
--- a/src/core/core_manager.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <condition_variable>
6#include <mutex>
7
8#include "common/logging/log.h"
9#include "core/arm/exclusive_monitor.h"
10#include "core/arm/unicorn/arm_unicorn.h"
11#include "core/core.h"
12#include "core/core_manager.h"
13#include "core/core_timing.h"
14#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/physical_core.h"
16#include "core/hle/kernel/scheduler.h"
17#include "core/hle/kernel/thread.h"
18#include "core/hle/lock.h"
19#include "core/settings.h"
20
21namespace Core {
22
23CoreManager::CoreManager(System& system, std::size_t core_index)
24 : global_scheduler{system.GlobalScheduler()}, physical_core{system.Kernel().PhysicalCore(
25 core_index)},
26 core_timing{system.CoreTiming()}, core_index{core_index} {}
27
28CoreManager::~CoreManager() = default;
29
30void CoreManager::RunLoop(bool tight_loop) {
31 /// Deprecated
32}
33
34void CoreManager::SingleStep() {
35 return RunLoop(false);
36}
37
38void CoreManager::PrepareReschedule() {
39 //physical_core.Stop();
40}
41
42void CoreManager::Reschedule() {
43 // Lock the global kernel mutex when we manipulate the HLE state
44 std::lock_guard lock(HLE::g_hle_lock);
45
46 // global_scheduler.SelectThread(core_index);
47
48 physical_core.Scheduler().TryDoContextSwitch();
49}
50
51} // namespace Core
diff --git a/src/core/core_manager.h b/src/core/core_manager.h
deleted file mode 100644
index d525de00a..000000000
--- a/src/core/core_manager.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <cstddef>
9#include <memory>
10#include "common/common_types.h"
11
12namespace Kernel {
13class GlobalScheduler;
14class PhysicalCore;
15} // namespace Kernel
16
17namespace Core {
18class System;
19}
20
21namespace Core::Timing {
22class CoreTiming;
23}
24
25namespace Core::Memory {
26class Memory;
27}
28
29namespace Core {
30
31constexpr unsigned NUM_CPU_CORES{4};
32
33class CoreManager {
34public:
35 CoreManager(System& system, std::size_t core_index);
36 ~CoreManager();
37
38 void RunLoop(bool tight_loop = true);
39
40 void SingleStep();
41
42 void PrepareReschedule();
43
44 bool IsMainCore() const {
45 return core_index == 0;
46 }
47
48 std::size_t CoreIndex() const {
49 return core_index;
50 }
51
52private:
53 void Reschedule();
54
55 Kernel::GlobalScheduler& global_scheduler;
56 Kernel::PhysicalCore& physical_core;
57 Timing::CoreTiming& core_timing;
58
59 std::atomic<bool> reschedule_pending = false;
60 std::size_t core_index;
61};
62
63} // namespace Core
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 70c0f8b80..79f22a403 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -35,7 +35,6 @@
35#include "common/swap.h" 35#include "common/swap.h"
36#include "core/arm/arm_interface.h" 36#include "core/arm/arm_interface.h"
37#include "core/core.h" 37#include "core/core.h"
38#include "core/core_manager.h"
39#include "core/gdbstub/gdbstub.h" 38#include "core/gdbstub/gdbstub.h"
40#include "core/hle/kernel/memory/page_table.h" 39#include "core/hle/kernel/memory/page_table.h"
41#include "core/hle/kernel/process.h" 40#include "core/hle/kernel/process.h"
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index 5498fd313..8aff2227a 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -34,7 +34,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
34 } 34 }
35 35
36 // Wake the threads waiting on the ServerPort 36 // Wake the threads waiting on the ServerPort
37 server_port->WakeupAllWaitingThreads(); 37 server_port->Signal();
38 38
39 return MakeResult(std::move(client)); 39 return MakeResult(std::move(client));
40} 40}
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1f230fc4a..dbb75416d 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -48,72 +48,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
48 48
49namespace Kernel { 49namespace Kernel {
50 50
51/**
52 * Callback that will wake up the thread it was scheduled for
53 * @param thread_handle The handle of the thread that's been awoken
54 * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
55 */
56static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) {
57 UNREACHABLE();
58 const auto proper_handle = static_cast<Handle>(thread_handle);
59 const auto& system = Core::System::GetInstance();
60
61 // Lock the global kernel mutex when we enter the kernel HLE.
62 std::lock_guard lock{HLE::g_hle_lock};
63
64 std::shared_ptr<Thread> thread =
65 system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
66 if (thread == nullptr) {
67 LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
68 return;
69 }
70
71 bool resume = true;
72
73 if (thread->GetStatus() == ThreadStatus::WaitSynch ||
74 thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
75 // Remove the thread from each of its waiting objects' waitlists
76 for (const auto& object : thread->GetSynchronizationObjects()) {
77 object->RemoveWaitingThread(thread);
78 }
79 thread->ClearSynchronizationObjects();
80
81 // Invoke the wakeup callback before clearing the wait objects
82 if (thread->HasWakeupCallback()) {
83 resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
84 }
85 } else if (thread->GetStatus() == ThreadStatus::WaitMutex ||
86 thread->GetStatus() == ThreadStatus::WaitCondVar) {
87 thread->SetMutexWaitAddress(0);
88 thread->SetWaitHandle(0);
89 if (thread->GetStatus() == ThreadStatus::WaitCondVar) {
90 thread->GetOwnerProcess()->RemoveConditionVariableThread(thread);
91 thread->SetCondVarWaitAddress(0);
92 }
93
94 auto* const lock_owner = thread->GetLockOwner();
95 // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
96 // and don't have a lock owner unless SignalProcessWideKey was called first and the thread
97 // wasn't awakened due to the mutex already being acquired.
98 if (lock_owner != nullptr) {
99 lock_owner->RemoveMutexWaiter(thread);
100 }
101 }
102
103 if (thread->GetStatus() == ThreadStatus::WaitArb) {
104 auto& address_arbiter = thread->GetOwnerProcess()->GetAddressArbiter();
105 address_arbiter.HandleWakeupThread(thread);
106 }
107
108 if (resume) {
109 if (thread->GetStatus() == ThreadStatus::WaitCondVar ||
110 thread->GetStatus() == ThreadStatus::WaitArb) {
111 thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
112 }
113 thread->ResumeFromWait();
114 }
115}
116
117struct KernelCore::Impl { 51struct KernelCore::Impl {
118 explicit Impl(Core::System& system, KernelCore& kernel) 52 explicit Impl(Core::System& system, KernelCore& kernel)
119 : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} 53 : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {}
@@ -129,7 +63,6 @@ struct KernelCore::Impl {
129 InitializePhysicalCores(); 63 InitializePhysicalCores();
130 InitializeSystemResourceLimit(kernel); 64 InitializeSystemResourceLimit(kernel);
131 InitializeMemoryLayout(); 65 InitializeMemoryLayout();
132 InitializeThreads();
133 InitializePreemption(kernel); 66 InitializePreemption(kernel);
134 InitializeSchedulers(); 67 InitializeSchedulers();
135 InitializeSuspendThreads(); 68 InitializeSuspendThreads();
@@ -161,7 +94,6 @@ struct KernelCore::Impl {
161 system_resource_limit = nullptr; 94 system_resource_limit = nullptr;
162 95
163 global_handle_table.Clear(); 96 global_handle_table.Clear();
164 thread_wakeup_event_type = nullptr;
165 preemption_event = nullptr; 97 preemption_event = nullptr;
166 98
167 global_scheduler.Shutdown(); 99 global_scheduler.Shutdown();
@@ -210,11 +142,6 @@ struct KernelCore::Impl {
210 } 142 }
211 } 143 }
212 144
213 void InitializeThreads() {
214 thread_wakeup_event_type =
215 Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback);
216 }
217
218 void InitializePreemption(KernelCore& kernel) { 145 void InitializePreemption(KernelCore& kernel) {
219 preemption_event = Core::Timing::CreateEvent( 146 preemption_event = Core::Timing::CreateEvent(
220 "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { 147 "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) {
@@ -376,7 +303,6 @@ struct KernelCore::Impl {
376 303
377 std::shared_ptr<ResourceLimit> system_resource_limit; 304 std::shared_ptr<ResourceLimit> system_resource_limit;
378 305
379 std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type;
380 std::shared_ptr<Core::Timing::EventType> preemption_event; 306 std::shared_ptr<Core::Timing::EventType> preemption_event;
381 307
382 // This is the kernel's handle table or supervisor handle table which 308 // This is the kernel's handle table or supervisor handle table which
@@ -516,7 +442,8 @@ std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore
516 return impl->interrupts; 442 return impl->interrupts;
517} 443}
518 444
519const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() const { 445const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts()
446 const {
520 return impl->interrupts; 447 return impl->interrupts;
521} 448}
522 449
@@ -595,10 +522,6 @@ u64 KernelCore::CreateNewUserProcessID() {
595 return impl->next_user_process_id++; 522 return impl->next_user_process_id++;
596} 523}
597 524
598const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallbackEventType() const {
599 return impl->thread_wakeup_event_type;
600}
601
602Kernel::HandleTable& KernelCore::GlobalHandleTable() { 525Kernel::HandleTable& KernelCore::GlobalHandleTable() {
603 return impl->global_handle_table; 526 return impl->global_handle_table;
604} 527}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 846056b85..49bd47e89 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -241,9 +241,6 @@ private:
241 /// Creates a new thread ID, incrementing the internal thread ID counter. 241 /// Creates a new thread ID, incrementing the internal thread ID counter.
242 u64 CreateNewThreadID(); 242 u64 CreateNewThreadID();
243 243
244 /// Retrieves the event type used for thread wakeup callbacks.
245 const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const;
246
247 /// Provides a reference to the global handle table. 244 /// Provides a reference to the global handle table.
248 Kernel::HandleTable& GlobalHandleTable(); 245 Kernel::HandleTable& GlobalHandleTable();
249 246
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index dbd35580e..781032cd1 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -16,7 +16,6 @@
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/arm/exclusive_monitor.h" 17#include "core/arm/exclusive_monitor.h"
18#include "core/core.h" 18#include "core/core.h"
19#include "core/core_manager.h"
20#include "core/core_timing.h" 19#include "core/core_timing.h"
21#include "core/core_timing_util.h" 20#include "core/core_timing_util.h"
22#include "core/cpu_manager.h" 21#include "core/cpu_manager.h"
@@ -1909,7 +1908,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
1909 return ERR_INVALID_COMBINATION; 1908 return ERR_INVALID_COMBINATION;
1910 } 1909 }
1911 1910
1912 if (core < Core::NUM_CPU_CORES) { 1911 if (core < Core::Hardware::NUM_CPU_CORES) {
1913 if ((affinity_mask & (1ULL << core)) == 0) { 1912 if ((affinity_mask & (1ULL << core)) == 0) {
1914 LOG_ERROR(Kernel_SVC, 1913 LOG_ERROR(Kernel_SVC,
1915 "Core is not enabled for the current mask, core={}, mask={:016X}", core, 1914 "Core is not enabled for the current mask, core={}, mask={:016X}", core,
diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp
index be9e09106..ba4d39157 100644
--- a/src/core/hle/kernel/synchronization_object.cpp
+++ b/src/core/hle/kernel/synchronization_object.cpp
@@ -38,70 +38,6 @@ void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread)
38 waiting_threads.erase(itr); 38 waiting_threads.erase(itr);
39} 39}
40 40
41std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const {
42 Thread* candidate = nullptr;
43 u32 candidate_priority = THREADPRIO_LOWEST + 1;
44
45 for (const auto& thread : waiting_threads) {
46 const ThreadStatus thread_status = thread->GetStatus();
47
48 // The list of waiting threads must not contain threads that are not waiting to be awakened.
49 ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
50 thread_status == ThreadStatus::WaitHLEEvent,
51 "Inconsistent thread statuses in waiting_threads");
52
53 if (thread->GetPriority() >= candidate_priority)
54 continue;
55
56 if (ShouldWait(thread.get()))
57 continue;
58
59 candidate = thread.get();
60 candidate_priority = thread->GetPriority();
61 }
62
63 return SharedFrom(candidate);
64}
65
66void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
67 ASSERT(!ShouldWait(thread.get()));
68
69 if (!thread) {
70 return;
71 }
72
73 if (thread->IsSleepingOnWait()) {
74 for (const auto& object : thread->GetSynchronizationObjects()) {
75 ASSERT(!object->ShouldWait(thread.get()));
76 object->Acquire(thread.get());
77 }
78 } else {
79 Acquire(thread.get());
80 }
81
82 const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this));
83
84 thread->ClearSynchronizationObjects();
85
86 thread->CancelWakeupTimer();
87
88 bool resume = true;
89 if (thread->HasWakeupCallback()) {
90 resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this),
91 index);
92 }
93 if (resume) {
94 thread->ResumeFromWait();
95 kernel.PrepareReschedule(thread->GetProcessorID());
96 }
97}
98
99void SynchronizationObject::WakeupAllWaitingThreads() {
100 while (auto thread = GetHighestPriorityReadyThread()) {
101 WakeupWaitingThread(thread);
102 }
103}
104
105void SynchronizationObject::ClearWaitingThreads() { 41void SynchronizationObject::ClearWaitingThreads() {
106 waiting_threads.clear(); 42 waiting_threads.clear();
107} 43}
diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h
index a35544ac1..f89b24204 100644
--- a/src/core/hle/kernel/synchronization_object.h
+++ b/src/core/hle/kernel/synchronization_object.h
@@ -50,21 +50,6 @@ public:
50 */ 50 */
51 void RemoveWaitingThread(std::shared_ptr<Thread> thread); 51 void RemoveWaitingThread(std::shared_ptr<Thread> thread);
52 52
53 /**
54 * Wake up all threads waiting on this object that can be awoken, in priority order,
55 * and set the synchronization result and output of the thread.
56 */
57 void /* deprecated */ WakeupAllWaitingThreads();
58
59 /**
60 * Wakes up a single thread waiting on this object.
61 * @param thread Thread that is waiting on this object to wakeup.
62 */
63 void WakeupWaitingThread(std::shared_ptr<Thread> thread);
64
65 /// Obtains the highest priority thread that is ready to run from this object's waiting list.
66 std::shared_ptr<Thread> /* deprecated */ GetHighestPriorityReadyThread() const;
67
68 /// Get a const reference to the waiting threads list for debug use 53 /// Get a const reference to the waiting threads list for debug use
69 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; 54 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
70 55
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index d88039a16..fba2a9c85 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -56,9 +56,6 @@ Thread::~Thread() = default;
56void Thread::Stop() { 56void Thread::Stop() {
57 { 57 {
58 SchedulerLock lock(kernel); 58 SchedulerLock lock(kernel);
59 // Cancel any outstanding wakeup events for this thread
60 Core::System::GetInstance().CoreTiming().UnscheduleEvent(
61 kernel.ThreadWakeupCallbackEventType(), global_handle);
62 SetStatus(ThreadStatus::Dead); 59 SetStatus(ThreadStatus::Dead);
63 Signal(); 60 Signal();
64 kernel.GlobalHandleTable().Close(global_handle); 61 kernel.GlobalHandleTable().Close(global_handle);
@@ -75,22 +72,6 @@ void Thread::Stop() {
75 global_handle = 0; 72 global_handle = 0;
76} 73}
77 74
78void Thread::WakeAfterDelay(s64 nanoseconds) {
79 // Don't schedule a wakeup if the thread wants to wait forever
80 if (nanoseconds == -1)
81 return;
82
83 // This function might be called from any thread so we have to be cautious and use the
84 // thread-safe version of ScheduleEvent.
85 Core::System::GetInstance().CoreTiming().ScheduleEvent(
86 nanoseconds, kernel.ThreadWakeupCallbackEventType(), global_handle);
87}
88
89void Thread::CancelWakeupTimer() {
90 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
91 global_handle);
92}
93
94void Thread::ResumeFromWait() { 75void Thread::ResumeFromWait() {
95 SchedulerLock lock(kernel); 76 SchedulerLock lock(kernel);
96 switch (status) { 77 switch (status) {
@@ -284,14 +265,6 @@ void Thread::SetPriority(u32 priority) {
284 UpdatePriority(); 265 UpdatePriority();
285} 266}
286 267
287void Thread::SetWaitSynchronizationResult(ResultCode result) {
288 UNREACHABLE();
289}
290
291void Thread::SetWaitSynchronizationOutput(s32 output) {
292 UNREACHABLE();
293}
294
295void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { 268void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) {
296 signaling_object = object; 269 signaling_object = object;
297 signaling_result = result; 270 signaling_result = result;
@@ -425,13 +398,6 @@ bool Thread::AllSynchronizationObjectsReady() const {
425 }); 398 });
426} 399}
427 400
428bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
429 std::shared_ptr<SynchronizationObject> object,
430 std::size_t index) {
431 ASSERT(wakeup_callback);
432 return wakeup_callback(reason, std::move(thread), std::move(object), index);
433}
434
435bool Thread::InvokeHLECallback(std::shared_ptr<Thread> thread) { 401bool Thread::InvokeHLECallback(std::shared_ptr<Thread> thread) {
436 ASSERT(hle_callback); 402 ASSERT(hle_callback);
437 return hle_callback(std::move(thread)); 403 return hle_callback(std::move(thread));
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 61963148d..3ae0df6ef 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -128,9 +128,6 @@ public:
128 128
129 using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>; 129 using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>;
130 130
131 using WakeupCallback =
132 std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
133 std::shared_ptr<SynchronizationObject> object, std::size_t index)>;
134 using HLECallback = std::function<bool(std::shared_ptr<Thread> thread)>; 131 using HLECallback = std::function<bool(std::shared_ptr<Thread> thread)>;
135 132
136 /** 133 /**
@@ -235,7 +232,7 @@ public:
235 } 232 }
236 233
237 /// Resumes a thread from waiting 234 /// Resumes a thread from waiting
238 void /* deprecated */ ResumeFromWait(); 235 void ResumeFromWait();
239 236
240 void OnWakeUp(); 237 void OnWakeUp();
241 238
@@ -249,27 +246,6 @@ public:
249 /// 246 ///
250 void CancelWait(); 247 void CancelWait();
251 248
252 /**
253 * Schedules an event to wake up the specified thread after the specified delay
254 * @param nanoseconds The time this thread will be allowed to sleep for
255 */
256 void /* deprecated */ WakeAfterDelay(s64 nanoseconds);
257
258 /// Cancel any outstanding wakeup events for this thread
259 void /* deprecated */ CancelWakeupTimer();
260
261 /**
262 * Sets the result after the thread awakens (from svcWaitSynchronization)
263 * @param result Value to set to the returned result
264 */
265 void /*deprecated*/ SetWaitSynchronizationResult(ResultCode result);
266
267 /**
268 * Sets the output parameter value after the thread awakens (from svcWaitSynchronization)
269 * @param output Value to set to the output parameter
270 */
271 void /*deprecated*/ SetWaitSynchronizationOutput(s32 output);
272
273 void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); 249 void SetSynchronizationResults(SynchronizationObject* object, ResultCode result);
274 250
275 Core::ARM_Interface& ArmInterface(); 251 Core::ARM_Interface& ArmInterface();
@@ -330,11 +306,6 @@ public:
330 */ 306 */
331 VAddr GetCommandBufferAddress() const; 307 VAddr GetCommandBufferAddress() const;
332 308
333 /// Returns whether this thread is waiting on objects from a WaitSynchronization call.
334 bool IsSleepingOnWait() const {
335 return status == ThreadStatus::WaitSynch;
336 }
337
338 ThreadContext32& GetContext32() { 309 ThreadContext32& GetContext32() {
339 return context_32; 310 return context_32;
340 } 311 }
@@ -469,18 +440,10 @@ public:
469 arb_wait_address = address; 440 arb_wait_address = address;
470 } 441 }
471 442
472 bool HasWakeupCallback() const {
473 return wakeup_callback != nullptr;
474 }
475
476 bool HasHLECallback() const { 443 bool HasHLECallback() const {
477 return hle_callback != nullptr; 444 return hle_callback != nullptr;
478 } 445 }
479 446
480 void SetWakeupCallback(WakeupCallback callback) {
481 wakeup_callback = std::move(callback);
482 }
483
484 void SetHLECallback(HLECallback callback) { 447 void SetHLECallback(HLECallback callback) {
485 hle_callback = std::move(callback); 448 hle_callback = std::move(callback);
486 } 449 }
@@ -501,22 +464,10 @@ public:
501 return hle_object; 464 return hle_object;
502 } 465 }
503 466
504 void InvalidateWakeupCallback() {
505 SetWakeupCallback(nullptr);
506 }
507
508 void InvalidateHLECallback() { 467 void InvalidateHLECallback() {
509 SetHLECallback(nullptr); 468 SetHLECallback(nullptr);
510 } 469 }
511 470
512 /**
513 * Invokes the thread's wakeup callback.
514 *
515 * @pre A valid wakeup callback has been set. Violating this precondition
516 * will cause an assertion to trigger.
517 */
518 bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
519 std::shared_ptr<SynchronizationObject> object, std::size_t index);
520 bool InvokeHLECallback(std::shared_ptr<Thread> thread); 471 bool InvokeHLECallback(std::shared_ptr<Thread> thread);
521 472
522 u32 GetIdealCore() const { 473 u32 GetIdealCore() const {
@@ -698,11 +649,6 @@ private:
698 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. 649 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
699 Handle global_handle = 0; 650 Handle global_handle = 0;
700 651
701 /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
702 /// was waiting via WaitSynchronization then the object will be the last object that became
703 /// available. In case of a timeout, the object will be nullptr. DEPRECATED
704 WakeupCallback wakeup_callback;
705
706 /// Callback for HLE Events 652 /// Callback for HLE Events
707 HLECallback hle_callback; 653 HLECallback hle_callback;
708 Handle hle_time_event; 654 Handle hle_time_event;
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 6ada13be4..d872de16c 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -142,7 +142,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
142 } 142 }
143 143
144 // Wake the threads waiting on the ServerPort 144 // Wake the threads waiting on the ServerPort
145 server_port->WakeupAllWaitingThreads(); 145 server_port->Signal();
146 146
147 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); 147 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
148 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 148 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
diff --git a/src/core/host_timing.cpp b/src/core/host_timing.cpp
deleted file mode 100644
index 2f40de1a1..000000000
--- a/src/core/host_timing.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/host_timing.h"
6
7#include <algorithm>
8#include <mutex>
9#include <string>
10#include <tuple>
11
12#include "common/assert.h"
13#include "core/core_timing_util.h"
14
15namespace Core::HostTiming {
16
17std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
18 return std::make_shared<EventType>(std::move(callback), std::move(name));
19}
20
21struct CoreTiming::Event {
22 u64 time;
23 u64 fifo_order;
24 u64 userdata;
25 std::weak_ptr<EventType> type;
26
27 // Sort by time, unless the times are the same, in which case sort by
28 // the order added to the queue
29 friend bool operator>(const Event& left, const Event& right) {
30 return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
31 }
32
33 friend bool operator<(const Event& left, const Event& right) {
34 return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
35 }
36};
37
38CoreTiming::CoreTiming() {
39 clock =
40 Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ);
41}
42
43CoreTiming::~CoreTiming() = default;
44
45void CoreTiming::ThreadEntry(CoreTiming& instance) {
46 instance.ThreadLoop();
47}
48
49void CoreTiming::Initialize() {
50 event_fifo_id = 0;
51 const auto empty_timed_callback = [](u64, s64) {};
52 ev_lost = CreateEvent("_lost_event", empty_timed_callback);
53 timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
54}
55
56void CoreTiming::Shutdown() {
57 paused = true;
58 shutting_down = true;
59 event.Set();
60 timer_thread->join();
61 ClearPendingEvents();
62 timer_thread.reset();
63 has_started = false;
64}
65
66void CoreTiming::Pause(bool is_paused) {
67 paused = is_paused;
68}
69
70void CoreTiming::SyncPause(bool is_paused) {
71 if (is_paused == paused && paused_set == paused) {
72 return;
73 }
74 Pause(is_paused);
75 event.Set();
76 while (paused_set != is_paused)
77 ;
78}
79
80bool CoreTiming::IsRunning() const {
81 return !paused_set;
82}
83
84bool CoreTiming::HasPendingEvents() const {
85 return !(wait_set && event_queue.empty());
86}
87
88void CoreTiming::ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type,
89 u64 userdata) {
90 basic_lock.lock();
91 const u64 timeout = static_cast<u64>(GetGlobalTimeNs().count() + ns_into_future);
92
93 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
94
95 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
96 basic_lock.unlock();
97 event.Set();
98}
99
100void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata) {
101 basic_lock.lock();
102 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
103 return e.type.lock().get() == event_type.get() && e.userdata == userdata;
104 });
105
106 // Removing random items breaks the invariant so we have to re-establish it.
107 if (itr != event_queue.end()) {
108 event_queue.erase(itr, event_queue.end());
109 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
110 }
111 basic_lock.unlock();
112}
113
114void CoreTiming::AddTicks(std::size_t core_index, u64 ticks) {
115 ticks_count[core_index] += ticks;
116}
117
118void CoreTiming::ResetTicks(std::size_t core_index) {
119 ticks_count[core_index] = 0;
120}
121
122u64 CoreTiming::GetCPUTicks() const {
123 return clock->GetCPUCycles();
124}
125
126u64 CoreTiming::GetClockTicks() const {
127 return clock->GetClockCycles();
128}
129
130void CoreTiming::ClearPendingEvents() {
131 event_queue.clear();
132}
133
134void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
135 basic_lock.lock();
136
137 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
138 return e.type.lock().get() == event_type.get();
139 });
140
141 // Removing random items breaks the invariant so we have to re-establish it.
142 if (itr != event_queue.end()) {
143 event_queue.erase(itr, event_queue.end());
144 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
145 }
146 basic_lock.unlock();
147}
148
149std::optional<u64> CoreTiming::Advance() {
150 advance_lock.lock();
151 basic_lock.lock();
152 global_timer = GetGlobalTimeNs().count();
153
154 while (!event_queue.empty() && event_queue.front().time <= global_timer) {
155 Event evt = std::move(event_queue.front());
156 std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
157 event_queue.pop_back();
158 basic_lock.unlock();
159
160 if (auto event_type{evt.type.lock()}) {
161 event_type->callback(evt.userdata, global_timer - evt.time);
162 }
163
164 basic_lock.lock();
165 }
166
167 if (!event_queue.empty()) {
168 const u64 next_time = event_queue.front().time - global_timer;
169 basic_lock.unlock();
170 advance_lock.unlock();
171 return next_time;
172 } else {
173 basic_lock.unlock();
174 advance_lock.unlock();
175 return std::nullopt;
176 }
177}
178
179void CoreTiming::ThreadLoop() {
180 has_started = true;
181 while (!shutting_down) {
182 while (!paused) {
183 paused_set = false;
184 const auto next_time = Advance();
185 if (next_time) {
186 std::chrono::nanoseconds next_time_ns = std::chrono::nanoseconds(*next_time);
187 event.WaitFor(next_time_ns);
188 } else {
189 wait_set = true;
190 event.Wait();
191 }
192 wait_set = false;
193 }
194 paused_set = true;
195 }
196}
197
198std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
199 return clock->GetTimeNS();
200}
201
202std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
203 return clock->GetTimeUS();
204}
205
206} // namespace Core::HostTiming
diff --git a/src/core/host_timing.h b/src/core/host_timing.h
deleted file mode 100644
index be6b68d7c..000000000
--- a/src/core/host_timing.h
+++ /dev/null
@@ -1,160 +0,0 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <chrono>
9#include <functional>
10#include <memory>
11#include <mutex>
12#include <optional>
13#include <string>
14#include <thread>
15#include <vector>
16
17#include "common/common_types.h"
18#include "common/spin_lock.h"
19#include "common/thread.h"
20#include "common/threadsafe_queue.h"
21#include "common/wall_clock.h"
22#include "core/hardware_properties.h"
23
24namespace Core::HostTiming {
25
26/// A callback that may be scheduled for a particular core timing event.
27using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>;
28
29/// Contains the characteristics of a particular event.
30struct EventType {
31 EventType(TimedCallback&& callback, std::string&& name)
32 : callback{std::move(callback)}, name{std::move(name)} {}
33
34 /// The event's callback function.
35 TimedCallback callback;
36 /// A pointer to the name of the event.
37 const std::string name;
38};
39
40/**
41 * This is a system to schedule events into the emulated machine's future. Time is measured
42 * in main CPU clock cycles.
43 *
44 * To schedule an event, you first have to register its type. This is where you pass in the
45 * callback. You then schedule events using the type id you get back.
46 *
47 * The int cyclesLate that the callbacks get is how many cycles late it was.
48 * So to schedule a new event on a regular basis:
49 * inside callback:
50 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
51 */
52class CoreTiming {
53public:
54 CoreTiming();
55 ~CoreTiming();
56
57 CoreTiming(const CoreTiming&) = delete;
58 CoreTiming(CoreTiming&&) = delete;
59
60 CoreTiming& operator=(const CoreTiming&) = delete;
61 CoreTiming& operator=(CoreTiming&&) = delete;
62
63 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
64 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
65 void Initialize();
66
67 /// Tears down all timing related functionality.
68 void Shutdown();
69
70 /// Pauses/Unpauses the execution of the timer thread.
71 void Pause(bool is_paused);
72
73 /// Pauses/Unpauses the execution of the timer thread and waits until paused.
74 void SyncPause(bool is_paused);
75
76 /// Checks if core timing is running.
77 bool IsRunning() const;
78
79 /// Checks if the timer thread has started.
80 bool HasStarted() const {
81 return has_started;
82 }
83
84 /// Checks if there are any pending time events.
85 bool HasPendingEvents() const;
86
87 /// Schedules an event in core timing
88 void ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type,
89 u64 userdata = 0);
90
91 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
92
93 /// We only permit one event of each type in the queue at a time.
94 void RemoveEvent(const std::shared_ptr<EventType>& event_type);
95
96 void AddTicks(std::size_t core_index, u64 ticks);
97
98 void ResetTicks(std::size_t core_index);
99
100 /// Returns current time in emulated CPU cycles
101 u64 GetCPUTicks() const;
102
103 /// Returns current time in emulated in Clock cycles
104 u64 GetClockTicks() const;
105
106 /// Returns current time in microseconds.
107 std::chrono::microseconds GetGlobalTimeUs() const;
108
109 /// Returns current time in nanoseconds.
110 std::chrono::nanoseconds GetGlobalTimeNs() const;
111
112 /// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
113 std::optional<u64> Advance();
114
115private:
116 struct Event;
117
118 /// Clear all pending events. This should ONLY be done on exit.
119 void ClearPendingEvents();
120
121 static void ThreadEntry(CoreTiming& instance);
122 void ThreadLoop();
123
124 std::unique_ptr<Common::WallClock> clock;
125
126 u64 global_timer = 0;
127
128 std::chrono::nanoseconds start_point;
129
130 // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
131 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
132 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
133 // accomodated by the standard adaptor class.
134 std::vector<Event> event_queue;
135 u64 event_fifo_id = 0;
136
137 std::shared_ptr<EventType> ev_lost;
138 Common::Event event{};
139 Common::SpinLock basic_lock{};
140 Common::SpinLock advance_lock{};
141 std::unique_ptr<std::thread> timer_thread;
142 std::atomic<bool> paused{};
143 std::atomic<bool> paused_set{};
144 std::atomic<bool> wait_set{};
145 std::atomic<bool> shutting_down{};
146 std::atomic<bool> has_started{};
147
148 std::array<std::atomic<u64>, Core::Hardware::NUM_CPU_CORES> ticks_count{};
149};
150
151/// Creates a core timing event with the given name and callback.
152///
153/// @param name The name of the core timing event to create.
154/// @param callback The callback to execute for the event.
155///
156/// @returns An EventType instance representing the created event.
157///
158std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback);
159
160} // namespace Core::HostTiming
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index 795f3da09..21a5840fb 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -39,6 +39,7 @@ u64 callbacks_done = 0;
39 39
40struct ScopeInit final { 40struct ScopeInit final {
41 ScopeInit() { 41 ScopeInit() {
42 core_timing.SetMulticore(true);
42 core_timing.Initialize([]() {}); 43 core_timing.Initialize([]() {});
43 } 44 }
44 ~ScopeInit() { 45 ~ScopeInit() {
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index d2dbb259c..0226ae2e2 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -340,7 +340,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
340 340
341 if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { 341 if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
342 list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetSynchronizationObjects(), 342 list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetSynchronizationObjects(),
343 thread.IsSleepingOnWait())); 343 thread.IsWaitingSync()));
344 } 344 }
345 345
346 list.push_back(std::make_unique<WaitTreeCallstack>(thread)); 346 list.push_back(std::make_unique<WaitTreeCallstack>(thread));