summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorGravatar bunnei2015-02-02 13:04:04 -0500
committerGravatar bunnei2015-02-02 13:04:04 -0500
commit7f730ed158bc9bba064100b9644b318134ef0bb3 (patch)
treec4181a69ff882e1af1b7d65bf3596a6cb3dd88b9 /src/core/hle/kernel
parentMerge pull request #517 from bunnei/blend-factors (diff)
parentKernel: Stop creating useless Handles during object creation (diff)
downloadyuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar.gz
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar.xz
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.zip
Merge pull request #523 from yuriks/kernel-lifetime5
Kernel Lifetime Reform Pt. 5: The Reckoning
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp13
-rw-r--r--src/core/hle/kernel/address_arbiter.h5
-rw-r--r--src/core/hle/kernel/event.cpp9
-rw-r--r--src/core/hle/kernel/event.h5
-rw-r--r--src/core/hle/kernel/kernel.cpp17
-rw-r--r--src/core/hle/kernel/kernel.h21
-rw-r--r--src/core/hle/kernel/mutex.cpp41
-rw-r--r--src/core/hle/kernel/mutex.h7
-rw-r--r--src/core/hle/kernel/semaphore.cpp5
-rw-r--r--src/core/hle/kernel/semaphore.h3
-rw-r--r--src/core/hle/kernel/session.cpp13
-rw-r--r--src/core/hle/kernel/session.h4
-rw-r--r--src/core/hle/kernel/shared_memory.cpp17
-rw-r--r--src/core/hle/kernel/shared_memory.h5
-rw-r--r--src/core/hle/kernel/thread.cpp53
-rw-r--r--src/core/hle/kernel/thread.h31
-rw-r--r--src/core/hle/kernel/timer.cpp28
-rw-r--r--src/core/hle/kernel/timer.h8
18 files changed, 158 insertions, 127 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2d01e2ef5..42f8ce2d9 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -15,14 +15,15 @@
15 15
16namespace Kernel { 16namespace Kernel {
17 17
18ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) { 18AddressArbiter::AddressArbiter() {}
19AddressArbiter::~AddressArbiter() {}
20
21SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) {
19 SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); 22 SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter);
20 // TOOD(yuriks): Don't create Handle (see Thread::Create())
21 CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter));
22 23
23 address_arbiter->name = std::move(name); 24 address_arbiter->name = std::move(name);
24 25
25 return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter)); 26 return address_arbiter;
26} 27}
27 28
28ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, 29ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value,
@@ -51,7 +52,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
51 case ArbitrationType::WaitIfLessThanWithTimeout: 52 case ArbitrationType::WaitIfLessThanWithTimeout:
52 if ((s32)Memory::Read32(address) <= value) { 53 if ((s32)Memory::Read32(address) <= value) {
53 Kernel::WaitCurrentThread_ArbitrateAddress(address); 54 Kernel::WaitCurrentThread_ArbitrateAddress(address);
54 Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); 55 GetCurrentThread()->WakeAfterDelay(nanoseconds);
55 HLE::Reschedule(__func__); 56 HLE::Reschedule(__func__);
56 } 57 }
57 break; 58 break;
@@ -71,7 +72,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
71 Memory::Write32(address, memory_value); 72 Memory::Write32(address, memory_value);
72 if (memory_value <= value) { 73 if (memory_value <= value) {
73 Kernel::WaitCurrentThread_ArbitrateAddress(address); 74 Kernel::WaitCurrentThread_ArbitrateAddress(address);
74 Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); 75 GetCurrentThread()->WakeAfterDelay(nanoseconds);
75 HLE::Reschedule(__func__); 76 HLE::Reschedule(__func__);
76 } 77 }
77 break; 78 break;
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 638afff9e..8f6a1a8df 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -34,7 +34,7 @@ public:
34 * @param name Optional name used for debugging. 34 * @param name Optional name used for debugging.
35 * @returns The created AddressArbiter. 35 * @returns The created AddressArbiter.
36 */ 36 */
37 static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown"); 37 static SharedPtr<AddressArbiter> Create(std::string name = "Unknown");
38 38
39 std::string GetTypeName() const override { return "Arbiter"; } 39 std::string GetTypeName() const override { return "Arbiter"; }
40 std::string GetName() const override { return name; } 40 std::string GetName() const override { return name; }
@@ -47,7 +47,8 @@ public:
47 ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); 47 ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds);
48 48
49private: 49private:
50 AddressArbiter() = default; 50 AddressArbiter();
51 ~AddressArbiter() override;
51}; 52};
52 53
53} // namespace FileSys 54} // namespace FileSys
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index d9ad40c6a..898e1c98f 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -14,16 +14,17 @@
14 14
15namespace Kernel { 15namespace Kernel {
16 16
17ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) { 17Event::Event() {}
18Event::~Event() {}
19
20SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
18 SharedPtr<Event> evt(new Event); 21 SharedPtr<Event> evt(new Event);
19 // TOOD(yuriks): Don't create Handle (see Thread::Create())
20 CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt));
21 22
22 evt->signaled = false; 23 evt->signaled = false;
23 evt->reset_type = evt->intitial_reset_type = reset_type; 24 evt->reset_type = evt->intitial_reset_type = reset_type;
24 evt->name = std::move(name); 25 evt->name = std::move(name);
25 26
26 return MakeResult<SharedPtr<Event>>(evt); 27 return evt;
27} 28}
28 29
29bool Event::ShouldWait() { 30bool Event::ShouldWait() {
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 2c3e6b14e..fba960d2a 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -18,7 +18,7 @@ public:
18 * @param reset_type ResetType describing how to create event 18 * @param reset_type ResetType describing how to create event
19 * @param name Optional name of event 19 * @param name Optional name of event
20 */ 20 */
21 static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown"); 21 static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown");
22 22
23 std::string GetTypeName() const override { return "Event"; } 23 std::string GetTypeName() const override { return "Event"; }
24 std::string GetName() const override { return name; } 24 std::string GetName() const override { return name; }
@@ -39,7 +39,8 @@ public:
39 void Clear(); 39 void Clear();
40 40
41private: 41private:
42 Event() = default; 42 Event();
43 ~Event() override;
43}; 44};
44 45
45} // namespace 46} // namespace
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index d7fa4dcea..7e0b9542e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -14,14 +14,16 @@
14 14
15namespace Kernel { 15namespace Kernel {
16 16
17unsigned int Object::next_object_id = 0;
18
17SharedPtr<Thread> g_main_thread = nullptr; 19SharedPtr<Thread> g_main_thread = nullptr;
18HandleTable g_handle_table; 20HandleTable g_handle_table;
19u64 g_program_id = 0; 21u64 g_program_id = 0;
20 22
21void WaitObject::AddWaitingThread(Thread* thread) { 23void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
22 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); 24 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
23 if (itr == waiting_threads.end()) 25 if (itr == waiting_threads.end())
24 waiting_threads.push_back(thread); 26 waiting_threads.push_back(std::move(thread));
25} 27}
26 28
27void WaitObject::RemoveWaitingThread(Thread* thread) { 29void WaitObject::RemoveWaitingThread(Thread* thread) {
@@ -30,11 +32,11 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
30 waiting_threads.erase(itr); 32 waiting_threads.erase(itr);
31} 33}
32 34
33Thread* WaitObject::WakeupNextThread() { 35SharedPtr<Thread> WaitObject::WakeupNextThread() {
34 if (waiting_threads.empty()) 36 if (waiting_threads.empty())
35 return nullptr; 37 return nullptr;
36 38
37 auto next_thread = waiting_threads.front(); 39 auto next_thread = std::move(waiting_threads.front());
38 waiting_threads.erase(waiting_threads.begin()); 40 waiting_threads.erase(waiting_threads.begin());
39 41
40 next_thread->ReleaseWaitObject(this); 42 next_thread->ReleaseWaitObject(this);
@@ -74,13 +76,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
74 // CTR-OS doesn't use generation 0, so skip straight to 1. 76 // CTR-OS doesn't use generation 0, so skip straight to 1.
75 if (next_generation >= (1 << 15)) next_generation = 1; 77 if (next_generation >= (1 << 15)) next_generation = 1;
76 78
77 Handle handle = generation | (slot << 15);
78 if (obj->handle == INVALID_HANDLE)
79 obj->handle = handle;
80
81 generations[slot] = generation; 79 generations[slot] = generation;
82 objects[slot] = std::move(obj); 80 objects[slot] = std::move(obj);
83 81
82 Handle handle = generation | (slot << 15);
84 return MakeResult<Handle>(handle); 83 return MakeResult<Handle>(handle);
85} 84}
86 85
@@ -102,7 +101,7 @@ ResultCode HandleTable::Close(Handle handle) {
102 101
103 objects[slot] = nullptr; 102 objects[slot] = nullptr;
104 103
105 generations[generation] = next_free_slot; 104 generations[slot] = next_free_slot;
106 next_free_slot = slot; 105 next_free_slot = slot;
107 return RESULT_SUCCESS; 106 return RESULT_SUCCESS;
108} 107}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 9860479ac..4d8e388b6 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -58,14 +58,12 @@ enum {
58 DEFAULT_STACK_SIZE = 0x4000, 58 DEFAULT_STACK_SIZE = 0x4000,
59}; 59};
60 60
61class HandleTable;
62
63class Object : NonCopyable { 61class Object : NonCopyable {
64 friend class HandleTable;
65 u32 handle = INVALID_HANDLE;
66public: 62public:
67 virtual ~Object() {} 63 virtual ~Object() {}
68 Handle GetHandle() const { return handle; } 64
65 /// Returns a unique identifier for the object. For debugging purposes only.
66 unsigned int GetObjectId() const { return object_id; }
69 67
70 virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } 68 virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
71 virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } 69 virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
@@ -101,7 +99,10 @@ private:
101 friend void intrusive_ptr_add_ref(Object*); 99 friend void intrusive_ptr_add_ref(Object*);
102 friend void intrusive_ptr_release(Object*); 100 friend void intrusive_ptr_release(Object*);
103 101
102 static unsigned int next_object_id;
103
104 unsigned int ref_count = 0; 104 unsigned int ref_count = 0;
105 unsigned int object_id = next_object_id++;
105}; 106};
106 107
107// Special functions used by boost::instrusive_ptr to do automatic ref-counting 108// Special functions used by boost::instrusive_ptr to do automatic ref-counting
@@ -135,25 +136,26 @@ public:
135 * Add a thread to wait on this object 136 * Add a thread to wait on this object
136 * @param thread Pointer to thread to add 137 * @param thread Pointer to thread to add
137 */ 138 */
138 void AddWaitingThread(Thread* thread); 139 void AddWaitingThread(SharedPtr<Thread> thread);
139 140
140 /** 141 /**
141 * Removes a thread from waiting on this object (e.g. if it was resumed already) 142 * Removes a thread from waiting on this object (e.g. if it was resumed already)
142 * @param thread Pointer to thread to remove 143 * @param thread Pointer to thread to remove
143 */ 144 */
144 void RemoveWaitingThread(Thread* thead); 145 void RemoveWaitingThread(Thread* thread);
145 146
146 /** 147 /**
147 * Wake up the next thread waiting on this object 148 * Wake up the next thread waiting on this object
148 * @return Pointer to the thread that was resumed, nullptr if no threads are waiting 149 * @return Pointer to the thread that was resumed, nullptr if no threads are waiting
149 */ 150 */
150 Thread* WakeupNextThread(); 151 SharedPtr<Thread> WakeupNextThread();
151 152
152 /// Wake up all threads waiting on this object 153 /// Wake up all threads waiting on this object
153 void WakeupAllWaitingThreads(); 154 void WakeupAllWaitingThreads();
154 155
155private: 156private:
156 std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available 157 /// Threads waiting for this object to become available
158 std::vector<SharedPtr<Thread>> waiting_threads;
157}; 159};
158 160
159/** 161/**
@@ -274,7 +276,6 @@ private:
274}; 276};
275 277
276extern HandleTable g_handle_table; 278extern HandleTable g_handle_table;
277extern SharedPtr<Thread> g_main_thread;
278 279
279/// The ID code of the currently running game 280/// The ID code of the currently running game
280/// TODO(Subv): This variable should not be here, 281/// TODO(Subv): This variable should not be here,
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index acf484659..9f7166ca4 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -5,6 +5,8 @@
5#include <map> 5#include <map>
6#include <vector> 6#include <vector>
7 7
8#include <boost/range/algorithm_ext/erase.hpp>
9
8#include "common/common.h" 10#include "common/common.h"
9 11
10#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
@@ -13,9 +15,6 @@
13 15
14namespace Kernel { 16namespace Kernel {
15 17
16typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap;
17static MutexMap g_mutex_held_locks;
18
19/** 18/**
20 * Resumes a thread waiting for the specified mutex 19 * Resumes a thread waiting for the specified mutex
21 * @param mutex The mutex that some thread is waiting on 20 * @param mutex The mutex that some thread is waiting on
@@ -33,21 +32,17 @@ static void ResumeWaitingThread(Mutex* mutex) {
33} 32}
34 33
35void ReleaseThreadMutexes(Thread* thread) { 34void ReleaseThreadMutexes(Thread* thread) {
36 auto locked_range = g_mutex_held_locks.equal_range(thread); 35 for (auto& mtx : thread->held_mutexes) {
37 36 ResumeWaitingThread(mtx.get());
38 // Release every mutex that the thread holds, and resume execution on the waiting threads
39 for (auto iter = locked_range.first; iter != locked_range.second; ++iter) {
40 ResumeWaitingThread(iter->second.get());
41 } 37 }
42 38 thread->held_mutexes.clear();
43 // Erase all the locks that this thread holds
44 g_mutex_held_locks.erase(thread);
45} 39}
46 40
47ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { 41Mutex::Mutex() {}
42Mutex::~Mutex() {}
43
44SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
48 SharedPtr<Mutex> mutex(new Mutex); 45 SharedPtr<Mutex> mutex(new Mutex);
49 // TOOD(yuriks): Don't create Handle (see Thread::Create())
50 CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex));
51 46
52 mutex->initial_locked = initial_locked; 47 mutex->initial_locked = initial_locked;
53 mutex->locked = false; 48 mutex->locked = false;
@@ -58,7 +53,7 @@ ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name)
58 if (initial_locked) 53 if (initial_locked)
59 mutex->Acquire(); 54 mutex->Acquire();
60 55
61 return MakeResult<SharedPtr<Mutex>>(mutex); 56 return mutex;
62} 57}
63 58
64bool Mutex::ShouldWait() { 59bool Mutex::ShouldWait() {
@@ -69,30 +64,22 @@ void Mutex::Acquire() {
69 Acquire(GetCurrentThread()); 64 Acquire(GetCurrentThread());
70} 65}
71 66
72void Mutex::Acquire(Thread* thread) { 67void Mutex::Acquire(SharedPtr<Thread> thread) {
73 _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); 68 _assert_msg_(Kernel, !ShouldWait(), "object unavailable!");
74 if (locked) 69 if (locked)
75 return; 70 return;
76 71
77 locked = true; 72 locked = true;
78 73
79 g_mutex_held_locks.insert(std::make_pair(thread, this)); 74 thread->held_mutexes.insert(this);
80 holding_thread = thread; 75 holding_thread = std::move(thread);
81} 76}
82 77
83void Mutex::Release() { 78void Mutex::Release() {
84 if (!locked) 79 if (!locked)
85 return; 80 return;
86 81
87 auto locked_range = g_mutex_held_locks.equal_range(holding_thread); 82 holding_thread->held_mutexes.erase(this);
88
89 for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) {
90 if (iter->second == this) {
91 g_mutex_held_locks.erase(iter);
92 break;
93 }
94 }
95
96 ResumeWaitingThread(this); 83 ResumeWaitingThread(this);
97} 84}
98 85
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 1e69528f1..548403614 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -22,7 +22,7 @@ public:
22 * @param name Optional name of mutex 22 * @param name Optional name of mutex
23 * @return Pointer to new Mutex object 23 * @return Pointer to new Mutex object
24 */ 24 */
25 static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown"); 25 static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown");
26 26
27 std::string GetTypeName() const override { return "Mutex"; } 27 std::string GetTypeName() const override { return "Mutex"; }
28 std::string GetName() const override { return name; } 28 std::string GetName() const override { return name; }
@@ -43,11 +43,12 @@ public:
43 * @param mutex Mutex that is to be acquired 43 * @param mutex Mutex that is to be acquired
44 * @param thread Thread that will acquire the mutex 44 * @param thread Thread that will acquire the mutex
45 */ 45 */
46 void Acquire(Thread* thread); 46 void Acquire(SharedPtr<Thread> thread);
47 void Release(); 47 void Release();
48 48
49private: 49private:
50 Mutex() = default; 50 Mutex();
51 ~Mutex() override;
51}; 52};
52 53
53/** 54/**
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index a9e406ef4..c8cf8b9a2 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -10,6 +10,9 @@
10 10
11namespace Kernel { 11namespace Kernel {
12 12
13Semaphore::Semaphore() {}
14Semaphore::~Semaphore() {}
15
13ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, 16ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count,
14 std::string name) { 17 std::string name) {
15 18
@@ -18,8 +21,6 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou
18 ErrorSummary::WrongArgument, ErrorLevel::Permanent); 21 ErrorSummary::WrongArgument, ErrorLevel::Permanent);
19 22
20 SharedPtr<Semaphore> semaphore(new Semaphore); 23 SharedPtr<Semaphore> semaphore(new Semaphore);
21 // TOOD(yuriks): Don't create Handle (see Thread::Create())
22 CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore));
23 24
24 // When the semaphore is created, some slots are reserved for other threads, 25 // When the semaphore is created, some slots are reserved for other threads,
25 // and the rest is reserved for the caller thread 26 // and the rest is reserved for the caller thread
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index 9bb404ab6..d8dc1fd78 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -47,7 +47,8 @@ public:
47 ResultVal<s32> Release(s32 release_count); 47 ResultVal<s32> Release(s32 release_count);
48 48
49private: 49private:
50 Semaphore() = default; 50 Semaphore();
51 ~Semaphore() override;
51}; 52};
52 53
53} // namespace 54} // namespace
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
new file mode 100644
index 000000000..0594967f8
--- /dev/null
+++ b/src/core/hle/kernel/session.cpp
@@ -0,0 +1,13 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/session.h"
6#include "core/hle/kernel/thread.h"
7
8namespace Kernel {
9
10Session::Session() {}
11Session::~Session() {}
12
13}
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 1788e4375..7cc9332c9 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h" 7#include "core/hle/kernel/kernel.h"
8#include "core/mem_map.h"
8 9
9namespace Kernel { 10namespace Kernel {
10 11
@@ -43,6 +44,9 @@ inline static u32* GetCommandBuffer(const int offset=0) {
43 */ 44 */
44class Session : public WaitObject { 45class Session : public WaitObject {
45public: 46public:
47 Session();
48 ~Session() override;
49
46 std::string GetTypeName() const override { return "Session"; } 50 std::string GetTypeName() const override { return "Session"; }
47 51
48 static const HandleType HANDLE_TYPE = HandleType::Session; 52 static const HandleType HANDLE_TYPE = HandleType::Session;
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index eff68d481..4211fcf04 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -9,22 +9,23 @@
9 9
10namespace Kernel { 10namespace Kernel {
11 11
12ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) { 12SharedMemory::SharedMemory() {}
13 SharedPtr<SharedMemory> shared_memory(new SharedMemory); 13SharedMemory::~SharedMemory() {}
14 14
15 // TOOD(yuriks): Don't create Handle (see Thread::Create()) 15SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
16 CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); 16 SharedPtr<SharedMemory> shared_memory(new SharedMemory);
17 17
18 shared_memory->name = std::move(name); 18 shared_memory->name = std::move(name);
19 return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory)); 19
20 return shared_memory;
20} 21}
21 22
22ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, 23ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
23 MemoryPermission other_permissions) { 24 MemoryPermission other_permissions) {
24 25
25 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { 26 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
26 LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", 27 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!",
27 GetHandle(), address); 28 GetObjectId(), address);
28 // TODO: Verify error code with hardware 29 // TODO: Verify error code with hardware
29 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 30 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
30 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); 31 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
@@ -41,7 +42,7 @@ ResultVal<u8*> SharedMemory::GetPointer(u32 offset) {
41 if (base_address != 0) 42 if (base_address != 0)
42 return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); 43 return MakeResult<u8*>(Memory::GetPointer(base_address + offset));
43 44
44 LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); 45 LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
45 // TODO(yuriks): Verify error code. 46 // TODO(yuriks): Verify error code.
46 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 47 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
47 ErrorSummary::InvalidState, ErrorLevel::Permanent); 48 ErrorSummary::InvalidState, ErrorLevel::Permanent);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index d393e8175..5833b411c 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -29,7 +29,7 @@ public:
29 * Creates a shared memory object 29 * Creates a shared memory object
30 * @param name Optional object name, used only for debugging purposes. 30 * @param name Optional object name, used only for debugging purposes.
31 */ 31 */
32 static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown"); 32 static SharedPtr<SharedMemory> Create(std::string name = "Unknown");
33 33
34 std::string GetTypeName() const override { return "SharedMemory"; } 34 std::string GetTypeName() const override { return "SharedMemory"; }
35 35
@@ -57,7 +57,8 @@ public:
57 std::string name; ///< Name of shared memory object (optional) 57 std::string name; ///< Name of shared memory object (optional)
58 58
59private: 59private:
60 SharedMemory() = default; 60 SharedMemory();
61 ~SharedMemory() override;
61}; 62};
62 63
63} // namespace 64} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 56950ebd4..3987f9608 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -4,7 +4,6 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <list> 6#include <list>
7#include <map>
8#include <vector> 7#include <vector>
9 8
10#include "common/common.h" 9#include "common/common.h"
@@ -41,6 +40,9 @@ static Thread* current_thread;
41static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup 40static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
42static u32 next_thread_id; ///< The next available thread id 41static u32 next_thread_id; ///< The next available thread id
43 42
43Thread::Thread() {}
44Thread::~Thread() {}
45
44Thread* GetCurrentThread() { 46Thread* GetCurrentThread() {
45 return current_thread; 47 return current_thread;
46} 48}
@@ -108,6 +110,9 @@ void Thread::Stop(const char* reason) {
108 WakeupAllWaitingThreads(); 110 WakeupAllWaitingThreads();
109 111
110 // Stopped threads are never waiting. 112 // Stopped threads are never waiting.
113 for (auto& wait_object : wait_objects) {
114 wait_object->RemoveWaitingThread(this);
115 }
111 wait_objects.clear(); 116 wait_objects.clear();
112 wait_address = 0; 117 wait_address = 0;
113} 118}
@@ -228,13 +233,15 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
228 233
229/// Event type for the thread wake up event 234/// Event type for the thread wake up event
230static int ThreadWakeupEventType = -1; 235static int ThreadWakeupEventType = -1;
236// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
237// us to simply use a pool index or similar.
238static Kernel::HandleTable wakeup_callback_handle_table;
231 239
232/// Callback that will wake up the thread it was scheduled for 240/// Callback that will wake up the thread it was scheduled for
233static void ThreadWakeupCallback(u64 parameter, int cycles_late) { 241static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
234 Handle handle = static_cast<Handle>(parameter); 242 SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle);
235 SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(handle);
236 if (thread == nullptr) { 243 if (thread == nullptr) {
237 LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); 244 LOG_CRITICAL(Kernel, "Callback fired for invalid thread %08X", thread_handle);
238 return; 245 return;
239 } 246 }
240 247
@@ -248,14 +255,13 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) {
248} 255}
249 256
250 257
251void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { 258void Thread::WakeAfterDelay(s64 nanoseconds) {
252 // Don't schedule a wakeup if the thread wants to wait forever 259 // Don't schedule a wakeup if the thread wants to wait forever
253 if (nanoseconds == -1) 260 if (nanoseconds == -1)
254 return; 261 return;
255 _dbg_assert_(Kernel, thread != nullptr);
256 262
257 u64 microseconds = nanoseconds / 1000; 263 u64 microseconds = nanoseconds / 1000;
258 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); 264 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle);
259} 265}
260 266
261void Thread::ReleaseWaitObject(WaitObject* wait_object) { 267void Thread::ReleaseWaitObject(WaitObject* wait_object) {
@@ -302,7 +308,7 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) {
302 308
303void Thread::ResumeFromWait() { 309void Thread::ResumeFromWait() {
304 // Cancel any outstanding wakeup events 310 // Cancel any outstanding wakeup events
305 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); 311 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
306 312
307 status &= ~THREADSTATUS_WAIT; 313 status &= ~THREADSTATUS_WAIT;
308 314
@@ -326,11 +332,11 @@ static void DebugThreadQueue() {
326 if (!thread) { 332 if (!thread) {
327 return; 333 return;
328 } 334 }
329 LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle()); 335 LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId());
330 for (auto& t : thread_list) { 336 for (auto& t : thread_list) {
331 s32 priority = thread_ready_queue.contains(t.get()); 337 s32 priority = thread_ready_queue.contains(t.get());
332 if (priority != -1) { 338 if (priority != -1) {
333 LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle()); 339 LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId());
334 } 340 }
335 } 341 }
336} 342}
@@ -362,14 +368,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
362 368
363 SharedPtr<Thread> thread(new Thread); 369 SharedPtr<Thread> thread(new Thread);
364 370
365 // TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for
366 // the time being. Create a handle here, it will be copied to the handle field in
367 // the object and use by the rest of the code. This should be removed when other
368 // code doesn't rely on the handle anymore.
369 ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread);
370 if (handle.Failed())
371 return handle.Code();
372
373 thread_list.push_back(thread); 371 thread_list.push_back(thread);
374 thread_ready_queue.prepare(priority); 372 thread_ready_queue.prepare(priority);
375 373
@@ -385,6 +383,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
385 thread->wait_objects.clear(); 383 thread->wait_objects.clear();
386 thread->wait_address = 0; 384 thread->wait_address = 0;
387 thread->name = std::move(name); 385 thread->name = std::move(name);
386 thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
388 387
389 ResetThread(thread.get(), arg, 0); 388 ResetThread(thread.get(), arg, 0);
390 CallThread(thread.get()); 389 CallThread(thread.get());
@@ -418,16 +417,14 @@ void Thread::SetPriority(s32 priority) {
418 } 417 }
419} 418}
420 419
421Handle SetupIdleThread() { 420SharedPtr<Thread> SetupIdleThread() {
422 // We need to pass a few valid values to get around parameter checking in Thread::Create. 421 // We need to pass a few valid values to get around parameter checking in Thread::Create.
423 auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, 422 auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0,
424 THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE); 423 THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE).MoveFrom();
425 _dbg_assert_(Kernel, thread_res.Succeeded());
426 SharedPtr<Thread> thread = std::move(*thread_res);
427 424
428 thread->idle = true; 425 thread->idle = true;
429 CallThread(thread.get()); 426 CallThread(thread.get());
430 return thread->GetHandle(); 427 return thread;
431} 428}
432 429
433SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size) { 430SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size) {
@@ -460,13 +457,13 @@ void Reschedule() {
460 HLE::g_reschedule = false; 457 HLE::g_reschedule = false;
461 458
462 if (next != nullptr) { 459 if (next != nullptr) {
463 LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); 460 LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId());
464 SwitchContext(next); 461 SwitchContext(next);
465 } else { 462 } else {
466 LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); 463 LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId());
467 464
468 for (auto& thread : thread_list) { 465 for (auto& thread : thread_list) {
469 LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X", thread->GetHandle(), 466 LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(),
470 thread->current_priority, thread->status); 467 thread->current_priority, thread->status);
471 } 468 }
472 } 469 }
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index d6299364a..633bb7c98 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -7,6 +7,8 @@
7#include <string> 7#include <string>
8#include <vector> 8#include <vector>
9 9
10#include <boost/container/flat_set.hpp>
11
10#include "common/common_types.h" 12#include "common/common_types.h"
11 13
12#include "core/core.h" 14#include "core/core.h"
@@ -40,6 +42,8 @@ enum ThreadStatus {
40 42
41namespace Kernel { 43namespace Kernel {
42 44
45class Mutex;
46
43class Thread final : public WaitObject { 47class Thread final : public WaitObject {
44public: 48public:
45 static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, 49 static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,
@@ -78,6 +82,12 @@ public:
78 void ResumeFromWait(); 82 void ResumeFromWait();
79 83
80 /** 84 /**
85 * Schedules an event to wake up the specified thread after the specified delay.
86 * @param nanoseconds The time this thread will be allowed to sleep for.
87 */
88 void WakeAfterDelay(s64 nanoseconds);
89
90 /**
81 * Sets the result after the thread awakens (from either WaitSynchronization SVC) 91 * Sets the result after the thread awakens (from either WaitSynchronization SVC)
82 * @param result Value to set to the returned result 92 * @param result Value to set to the returned result
83 */ 93 */
@@ -103,8 +113,10 @@ public:
103 113
104 s32 processor_id; 114 s32 processor_id;
105 115
106 std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on 116 /// Mutexes currently held by this thread, which will be released when it exits.
117 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
107 118
119 std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
108 VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address 120 VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
109 bool wait_all; ///< True if the thread is waiting on all objects before resuming 121 bool wait_all; ///< True if the thread is waiting on all objects before resuming
110 bool wait_set_output; ///< True if the output parameter should be set on thread wakeup 122 bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
@@ -115,9 +127,15 @@ public:
115 bool idle = false; 127 bool idle = false;
116 128
117private: 129private:
118 Thread() = default; 130 Thread();
131 ~Thread() override;
132
133 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
134 Handle callback_handle;
119}; 135};
120 136
137extern SharedPtr<Thread> g_main_thread;
138
121/// Sets up the primary application thread 139/// Sets up the primary application thread
122SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size); 140SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size);
123 141
@@ -151,19 +169,12 @@ void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bo
151void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); 169void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
152 170
153/** 171/**
154 * Schedules an event to wake up the specified thread after the specified delay.
155 * @param handle The thread handle.
156 * @param nanoseconds The time this thread will be allowed to sleep for.
157 */
158void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds);
159
160/**
161 * Sets up the idle thread, this is a thread that is intended to never execute instructions, 172 * Sets up the idle thread, this is a thread that is intended to never execute instructions,
162 * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue 173 * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue
163 * and will try to yield on every call. 174 * and will try to yield on every call.
164 * @returns The handle of the idle thread 175 * @returns The handle of the idle thread
165 */ 176 */
166Handle SetupIdleThread(); 177SharedPtr<Thread> SetupIdleThread();
167 178
168/// Initialize threading 179/// Initialize threading
169void ThreadingInit(); 180void ThreadingInit();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 503a5d2ce..4352fc99c 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -2,8 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <set>
6
7#include "common/common.h" 5#include "common/common.h"
8 6
9#include "core/core_timing.h" 7#include "core/core_timing.h"
@@ -15,18 +13,24 @@ namespace Kernel {
15 13
16/// The event type of the generic timer callback event 14/// The event type of the generic timer callback event
17static int timer_callback_event_type = -1; 15static int timer_callback_event_type = -1;
16// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
17// us to simply use a pool index or similar.
18static Kernel::HandleTable timer_callback_handle_table;
19
20Timer::Timer() {}
21Timer::~Timer() {}
18 22
19ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) { 23SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
20 SharedPtr<Timer> timer(new Timer); 24 SharedPtr<Timer> timer(new Timer);
21 // TOOD(yuriks): Don't create Handle (see Thread::Create())
22 CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer));
23 25
24 timer->reset_type = reset_type; 26 timer->reset_type = reset_type;
25 timer->signaled = false; 27 timer->signaled = false;
26 timer->name = std::move(name); 28 timer->name = std::move(name);
27 timer->initial_delay = 0; 29 timer->initial_delay = 0;
28 timer->interval_delay = 0; 30 timer->interval_delay = 0;
29 return MakeResult<SharedPtr<Timer>>(timer); 31 timer->callback_handle = timer_callback_handle_table.Create(timer).MoveFrom();
32
33 return timer;
30} 34}
31 35
32bool Timer::ShouldWait() { 36bool Timer::ShouldWait() {
@@ -38,17 +42,19 @@ void Timer::Acquire() {
38} 42}
39 43
40void Timer::Set(s64 initial, s64 interval) { 44void Timer::Set(s64 initial, s64 interval) {
45 // Ensure we get rid of any previous scheduled event
46 Cancel();
47
41 initial_delay = initial; 48 initial_delay = initial;
42 interval_delay = interval; 49 interval_delay = interval;
43 50
44 u64 initial_microseconds = initial / 1000; 51 u64 initial_microseconds = initial / 1000;
45 // TODO(yuriks): Figure out a replacement for GetHandle here 52 CoreTiming::ScheduleEvent(usToCycles(initial_microseconds),
46 CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, 53 timer_callback_event_type, callback_handle);
47 GetHandle());
48} 54}
49 55
50void Timer::Cancel() { 56void Timer::Cancel() {
51 CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle()); 57 CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
52} 58}
53 59
54void Timer::Clear() { 60void Timer::Clear() {
@@ -57,7 +63,7 @@ void Timer::Clear() {
57 63
58/// The timer callback event, called when a timer is fired 64/// The timer callback event, called when a timer is fired
59static void TimerCallback(u64 timer_handle, int cycles_late) { 65static void TimerCallback(u64 timer_handle, int cycles_late) {
60 SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); 66 SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(timer_handle);
61 67
62 if (timer == nullptr) { 68 if (timer == nullptr) {
63 LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); 69 LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle);
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index c45e79954..540e4e187 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -19,7 +19,7 @@ public:
19 * @param name Optional name of timer 19 * @param name Optional name of timer
20 * @return The created Timer 20 * @return The created Timer
21 */ 21 */
22 static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown"); 22 static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown");
23 23
24 std::string GetTypeName() const override { return "Timer"; } 24 std::string GetTypeName() const override { return "Timer"; }
25 std::string GetName() const override { return name; } 25 std::string GetName() const override { return name; }
@@ -49,7 +49,11 @@ public:
49 void Clear(); 49 void Clear();
50 50
51private: 51private:
52 Timer() = default; 52 Timer();
53 ~Timer() override;
54
55 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
56 Handle callback_handle;
53}; 57};
54 58
55/// Initializes the required variables for timers 59/// Initializes the required variables for timers