diff options
| author | 2014-12-22 11:07:22 -0200 | |
|---|---|---|
| committer | 2015-01-09 04:02:15 -0200 | |
| commit | 9bf8462b96d34b30f62b8aca745dd558e7f0a450 (patch) | |
| tree | 32606d5176a82daa4e59bb47bede34d4a941780a /src/core | |
| parent | Kernel: Move Thread's definition to the header file (diff) | |
| download | yuzu-9bf8462b96d34b30f62b8aca745dd558e7f0a450.tar.gz yuzu-9bf8462b96d34b30f62b8aca745dd558e7f0a450.tar.xz yuzu-9bf8462b96d34b30f62b8aca745dd558e7f0a450.zip | |
Thread: Reduce use of Handles and move some funcs to inside the class.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/core.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/event.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 19 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 340 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 68 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 51 |
11 files changed, 222 insertions, 302 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index cf25f87ca..e9e5c35cc 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -25,7 +25,7 @@ ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core | |||
| 25 | void RunLoop(int tight_loop) { | 25 | void RunLoop(int tight_loop) { |
| 26 | // If the current thread is an idle thread, then don't execute instructions, | 26 | // If the current thread is an idle thread, then don't execute instructions, |
| 27 | // instead advance to the next event and try to yield to the next thread | 27 | // instead advance to the next event and try to yield to the next thread |
| 28 | if (Kernel::IsIdleThread(Kernel::GetCurrentThreadHandle())) { | 28 | if (Kernel::GetCurrentThread()->IsIdle()) { |
| 29 | LOG_TRACE(Core_ARM11, "Idling"); | 29 | LOG_TRACE(Core_ARM11, "Idling"); |
| 30 | CoreTiming::Idle(); | 30 | CoreTiming::Idle(); |
| 31 | CoreTiming::Advance(); | 31 | CoreTiming::Advance(); |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 736bbc36a..28adc5500 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -30,24 +30,28 @@ public: | |||
| 30 | 30 | ||
| 31 | /// Arbitrate an address | 31 | /// Arbitrate an address |
| 32 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { | 32 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { |
| 33 | Object* object = Kernel::g_handle_table.GetGeneric(handle); | ||
| 34 | if (object == nullptr) | ||
| 35 | return InvalidHandle(ErrorModule::Kernel); | ||
| 36 | |||
| 33 | switch (type) { | 37 | switch (type) { |
| 34 | 38 | ||
| 35 | // Signal thread(s) waiting for arbitrate address... | 39 | // Signal thread(s) waiting for arbitrate address... |
| 36 | case ArbitrationType::Signal: | 40 | case ArbitrationType::Signal: |
| 37 | // Negative value means resume all threads | 41 | // Negative value means resume all threads |
| 38 | if (value < 0) { | 42 | if (value < 0) { |
| 39 | ArbitrateAllThreads(handle, address); | 43 | ArbitrateAllThreads(object, address); |
| 40 | } else { | 44 | } else { |
| 41 | // Resume first N threads | 45 | // Resume first N threads |
| 42 | for(int i = 0; i < value; i++) | 46 | for(int i = 0; i < value; i++) |
| 43 | ArbitrateHighestPriorityThread(handle, address); | 47 | ArbitrateHighestPriorityThread(object, address); |
| 44 | } | 48 | } |
| 45 | break; | 49 | break; |
| 46 | 50 | ||
| 47 | // Wait current thread (acquire the arbiter)... | 51 | // Wait current thread (acquire the arbiter)... |
| 48 | case ArbitrationType::WaitIfLessThan: | 52 | case ArbitrationType::WaitIfLessThan: |
| 49 | if ((s32)Memory::Read32(address) <= value) { | 53 | if ((s32)Memory::Read32(address) <= value) { |
| 50 | Kernel::WaitCurrentThread(WAITTYPE_ARB, handle, address); | 54 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); |
| 51 | HLE::Reschedule(__func__); | 55 | HLE::Reschedule(__func__); |
| 52 | } | 56 | } |
| 53 | break; | 57 | break; |
| @@ -57,7 +61,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | |||
| 57 | s32 memory_value = Memory::Read32(address) - 1; | 61 | s32 memory_value = Memory::Read32(address) - 1; |
| 58 | Memory::Write32(address, memory_value); | 62 | Memory::Write32(address, memory_value); |
| 59 | if (memory_value <= value) { | 63 | if (memory_value <= value) { |
| 60 | Kernel::WaitCurrentThread(WAITTYPE_ARB, handle, address); | 64 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); |
| 61 | HLE::Reschedule(__func__); | 65 | HLE::Reschedule(__func__); |
| 62 | } | 66 | } |
| 63 | break; | 67 | break; |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index e43c3ee4e..697e08681 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -33,11 +33,11 @@ public: | |||
| 33 | ResultVal<bool> WaitSynchronization() override { | 33 | ResultVal<bool> WaitSynchronization() override { |
| 34 | bool wait = locked; | 34 | bool wait = locked; |
| 35 | if (locked) { | 35 | if (locked) { |
| 36 | Handle thread = GetCurrentThreadHandle(); | 36 | Handle thread = GetCurrentThread()->GetHandle(); |
| 37 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | 37 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { |
| 38 | waiting_threads.push_back(thread); | 38 | waiting_threads.push_back(thread); |
| 39 | } | 39 | } |
| 40 | Kernel::WaitCurrentThread(WAITTYPE_EVENT, GetHandle()); | 40 | Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); |
| 41 | } | 41 | } |
| 42 | if (reset_type != RESETTYPE_STICKY && !permanent_locked) { | 42 | if (reset_type != RESETTYPE_STICKY && !permanent_locked) { |
| 43 | locked = true; | 43 | locked = true; |
| @@ -88,7 +88,9 @@ ResultCode SignalEvent(const Handle handle) { | |||
| 88 | // Resume threads waiting for event to signal | 88 | // Resume threads waiting for event to signal |
| 89 | bool event_caught = false; | 89 | bool event_caught = false; |
| 90 | for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { | 90 | for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { |
| 91 | ResumeThreadFromWait( evt->waiting_threads[i]); | 91 | Thread* thread = Kernel::g_handle_table.Get<Thread>(evt->waiting_threads[i]); |
| 92 | if (thread != nullptr) | ||
| 93 | thread->ResumeFromWait(); | ||
| 92 | 94 | ||
| 93 | // If any thread is signalled awake by this event, assume the event was "caught" and reset | 95 | // If any thread is signalled awake by this event, assume the event was "caught" and reset |
| 94 | // the event. This will result in the next thread waiting on the event to block. Otherwise, | 96 | // the event. This will result in the next thread waiting on the event to block. Otherwise, |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5dfc41bab..a1bc6c5d8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | Handle g_main_thread = 0; | 17 | Thread* g_main_thread = nullptr; |
| 18 | HandleTable g_handle_table; | 18 | HandleTable g_handle_table; |
| 19 | u64 g_program_id = 0; | 19 | u64 g_program_id = 0; |
| 20 | 20 | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3e381d776..31d80c7ac 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -16,6 +16,8 @@ const Handle INVALID_HANDLE = 0; | |||
| 16 | 16 | ||
| 17 | namespace Kernel { | 17 | namespace Kernel { |
| 18 | 18 | ||
| 19 | class Thread; | ||
| 20 | |||
| 19 | // TODO: Verify code | 21 | // TODO: Verify code |
| 20 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | 22 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, |
| 21 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); | 23 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); |
| @@ -190,7 +192,7 @@ private: | |||
| 190 | }; | 192 | }; |
| 191 | 193 | ||
| 192 | extern HandleTable g_handle_table; | 194 | extern HandleTable g_handle_table; |
| 193 | extern Handle g_main_thread; | 195 | extern Thread* g_main_thread; |
| 194 | 196 | ||
| 195 | /// The ID code of the currently running game | 197 | /// The ID code of the currently running game |
| 196 | /// TODO(Subv): This variable should not be here, | 198 | /// 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 3dfeffc9b..7d008f6cc 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -40,14 +40,21 @@ static MutexMap g_mutex_held_locks; | |||
| 40 | * @param mutex Mutex that is to be acquired | 40 | * @param mutex Mutex that is to be acquired |
| 41 | * @param thread Thread that will acquired | 41 | * @param thread Thread that will acquired |
| 42 | */ | 42 | */ |
| 43 | void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThreadHandle()) { | 43 | void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandle()) { |
| 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); | 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); |
| 45 | mutex->lock_thread = thread; | 45 | mutex->lock_thread = thread; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | bool ReleaseMutexForThread(Mutex* mutex, Handle thread) { | 48 | bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { |
| 49 | MutexAcquireLock(mutex, thread); | 49 | MutexAcquireLock(mutex, thread_handle); |
| 50 | Kernel::ResumeThreadFromWait(thread); | 50 | |
| 51 | Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle); | ||
| 52 | if (thread == nullptr) { | ||
| 53 | LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | thread->ResumeFromWait(); | ||
| 51 | return true; | 58 | return true; |
| 52 | } | 59 | } |
| 53 | 60 | ||
| @@ -168,8 +175,8 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { | |||
| 168 | ResultVal<bool> Mutex::WaitSynchronization() { | 175 | ResultVal<bool> Mutex::WaitSynchronization() { |
| 169 | bool wait = locked; | 176 | bool wait = locked; |
| 170 | if (locked) { | 177 | if (locked) { |
| 171 | waiting_threads.push_back(GetCurrentThreadHandle()); | 178 | waiting_threads.push_back(GetCurrentThread()->GetHandle()); |
| 172 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); | 179 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); |
| 173 | } else { | 180 | } else { |
| 174 | // Lock the mutex when the first thread accesses it | 181 | // Lock the mutex when the first thread accesses it |
| 175 | locked = true; | 182 | locked = true; |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 6bc8066a6..d7eeaa3da 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -37,8 +37,8 @@ public: | |||
| 37 | bool wait = !IsAvailable(); | 37 | bool wait = !IsAvailable(); |
| 38 | 38 | ||
| 39 | if (wait) { | 39 | if (wait) { |
| 40 | Kernel::WaitCurrentThread(WAITTYPE_SEMA, GetHandle()); | 40 | Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); |
| 41 | waiting_threads.push(GetCurrentThreadHandle()); | 41 | waiting_threads.push(GetCurrentThread()->GetHandle()); |
| 42 | } else { | 42 | } else { |
| 43 | --available_count; | 43 | --available_count; |
| 44 | } | 44 | } |
| @@ -84,7 +84,9 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | |||
| 84 | // Notify some of the threads that the semaphore has been released | 84 | // Notify some of the threads that the semaphore has been released |
| 85 | // stop once the semaphore is full again or there are no more waiting threads | 85 | // stop once the semaphore is full again or there are no more waiting threads |
| 86 | while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { | 86 | while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { |
| 87 | Kernel::ResumeThreadFromWait(semaphore->waiting_threads.front()); | 87 | Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()); |
| 88 | if (thread != nullptr) | ||
| 89 | thread->ResumeFromWait(); | ||
| 88 | semaphore->waiting_threads.pop(); | 90 | semaphore->waiting_threads.pop(); |
| 89 | --semaphore->available_count; | 91 | --semaphore->available_count; |
| 90 | } | 92 | } |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ef63c5f41..03244f013 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -25,23 +25,22 @@ namespace Kernel { | |||
| 25 | ResultVal<bool> Thread::WaitSynchronization() { | 25 | ResultVal<bool> Thread::WaitSynchronization() { |
| 26 | const bool wait = status != THREADSTATUS_DORMANT; | 26 | const bool wait = status != THREADSTATUS_DORMANT; |
| 27 | if (wait) { | 27 | if (wait) { |
| 28 | Handle thread = GetCurrentThreadHandle(); | 28 | Thread* thread = GetCurrentThread(); |
| 29 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | 29 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { |
| 30 | waiting_threads.push_back(thread); | 30 | waiting_threads.push_back(thread); |
| 31 | } | 31 | } |
| 32 | WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); | 32 | WaitCurrentThread(WAITTYPE_THREADEND, this); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | return MakeResult<bool>(wait); | 35 | return MakeResult<bool>(wait); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | // Lists all thread ids that aren't deleted/etc. | 38 | // Lists all thread ids that aren't deleted/etc. |
| 39 | static std::vector<Handle> thread_queue; | 39 | static std::vector<Thread*> thread_queue; // TODO(yuriks): Owned |
| 40 | 40 | ||
| 41 | // Lists only ready thread ids. | 41 | // Lists only ready thread ids. |
| 42 | static Common::ThreadQueueList<Handle, THREADPRIO_LOWEST+1> thread_ready_queue; | 42 | static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> thread_ready_queue; |
| 43 | 43 | ||
| 44 | static Handle current_thread_handle; | ||
| 45 | static Thread* current_thread; | 44 | static Thread* current_thread; |
| 46 | 45 | ||
| 47 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup | 46 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup |
| @@ -51,29 +50,8 @@ Thread* GetCurrentThread() { | |||
| 51 | return current_thread; | 50 | return current_thread; |
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | /// Gets the current thread handle | ||
| 55 | Handle GetCurrentThreadHandle() { | ||
| 56 | return GetCurrentThread()->GetHandle(); | ||
| 57 | } | ||
| 58 | |||
| 59 | /// Sets the current thread | ||
| 60 | inline void SetCurrentThread(Thread* t) { | ||
| 61 | current_thread = t; | ||
| 62 | current_thread_handle = t->GetHandle(); | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Saves the current CPU context | ||
| 66 | void SaveContext(Core::ThreadContext& ctx) { | ||
| 67 | Core::g_app_core->SaveContext(ctx); | ||
| 68 | } | ||
| 69 | |||
| 70 | /// Loads a CPU context | ||
| 71 | void LoadContext(Core::ThreadContext& ctx) { | ||
| 72 | Core::g_app_core->LoadContext(ctx); | ||
| 73 | } | ||
| 74 | |||
| 75 | /// Resets a thread | 53 | /// Resets a thread |
| 76 | void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { | 54 | static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { |
| 77 | memset(&t->context, 0, sizeof(Core::ThreadContext)); | 55 | memset(&t->context, 0, sizeof(Core::ThreadContext)); |
| 78 | 56 | ||
| 79 | t->context.cpu_registers[0] = arg; | 57 | t->context.cpu_registers[0] = arg; |
| @@ -90,22 +68,21 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { | |||
| 90 | t->current_priority = t->initial_priority; | 68 | t->current_priority = t->initial_priority; |
| 91 | } | 69 | } |
| 92 | t->wait_type = WAITTYPE_NONE; | 70 | t->wait_type = WAITTYPE_NONE; |
| 93 | t->wait_handle = 0; | 71 | t->wait_object = nullptr; |
| 94 | t->wait_address = 0; | 72 | t->wait_address = 0; |
| 95 | } | 73 | } |
| 96 | 74 | ||
| 97 | /// Change a thread to "ready" state | 75 | /// Change a thread to "ready" state |
| 98 | void ChangeReadyState(Thread* t, bool ready) { | 76 | static void ChangeReadyState(Thread* t, bool ready) { |
| 99 | Handle handle = t->GetHandle(); | ||
| 100 | if (t->IsReady()) { | 77 | if (t->IsReady()) { |
| 101 | if (!ready) { | 78 | if (!ready) { |
| 102 | thread_ready_queue.remove(t->current_priority, handle); | 79 | thread_ready_queue.remove(t->current_priority, t); |
| 103 | } | 80 | } |
| 104 | } else if (ready) { | 81 | } else if (ready) { |
| 105 | if (t->IsRunning()) { | 82 | if (t->IsRunning()) { |
| 106 | thread_ready_queue.push_front(t->current_priority, handle); | 83 | thread_ready_queue.push_front(t->current_priority, t); |
| 107 | } else { | 84 | } else { |
| 108 | thread_ready_queue.push_back(t->current_priority, handle); | 85 | thread_ready_queue.push_back(t->current_priority, t); |
| 109 | } | 86 | } |
| 110 | t->status = THREADSTATUS_READY; | 87 | t->status = THREADSTATUS_READY; |
| 111 | } | 88 | } |
| @@ -117,43 +94,36 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { | |||
| 117 | } | 94 | } |
| 118 | 95 | ||
| 119 | /// Check if a thread is blocking on a specified wait type with a specified handle | 96 | /// Check if a thread is blocking on a specified wait type with a specified handle |
| 120 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) { | 97 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { |
| 121 | return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle); | 98 | return CheckWaitType(thread, type) && wait_object == thread->wait_object; |
| 122 | } | 99 | } |
| 123 | 100 | ||
| 124 | /// Check if a thread is blocking on a specified wait type with a specified handle and address | 101 | /// Check if a thread is blocking on a specified wait type with a specified handle and address |
| 125 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | 102 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object, VAddr wait_address) { |
| 126 | return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address); | 103 | return CheckWaitType(thread, type, wait_object) && (wait_address == thread->wait_address); |
| 127 | } | 104 | } |
| 128 | 105 | ||
| 129 | /// Stops the current thread | 106 | /// Stops the current thread |
| 130 | ResultCode StopThread(Handle handle, const char* reason) { | 107 | void Thread::Stop(const char* reason) { |
| 131 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 132 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 133 | |||
| 134 | // Release all the mutexes that this thread holds | 108 | // Release all the mutexes that this thread holds |
| 135 | ReleaseThreadMutexes(handle); | 109 | ReleaseThreadMutexes(GetHandle()); |
| 136 | |||
| 137 | ChangeReadyState(thread, false); | ||
| 138 | thread->status = THREADSTATUS_DORMANT; | ||
| 139 | for (Handle waiting_handle : thread->waiting_threads) { | ||
| 140 | Thread* waiting_thread = g_handle_table.Get<Thread>(waiting_handle); | ||
| 141 | 110 | ||
| 142 | if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle)) | 111 | ChangeReadyState(this, false); |
| 143 | ResumeThreadFromWait(waiting_handle); | 112 | status = THREADSTATUS_DORMANT; |
| 113 | for (Thread* waiting_thread : waiting_threads) { | ||
| 114 | if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, this)) | ||
| 115 | waiting_thread->ResumeFromWait(); | ||
| 144 | } | 116 | } |
| 145 | thread->waiting_threads.clear(); | 117 | waiting_threads.clear(); |
| 146 | 118 | ||
| 147 | // Stopped threads are never waiting. | 119 | // Stopped threads are never waiting. |
| 148 | thread->wait_type = WAITTYPE_NONE; | 120 | wait_type = WAITTYPE_NONE; |
| 149 | thread->wait_handle = 0; | 121 | wait_object = nullptr; |
| 150 | thread->wait_address = 0; | 122 | wait_address = 0; |
| 151 | |||
| 152 | return RESULT_SUCCESS; | ||
| 153 | } | 123 | } |
| 154 | 124 | ||
| 155 | /// Changes a threads state | 125 | /// Changes a threads state |
| 156 | void ChangeThreadState(Thread* t, ThreadStatus new_status) { | 126 | static void ChangeThreadState(Thread* t, ThreadStatus new_status) { |
| 157 | if (!t || t->status == new_status) { | 127 | if (!t || t->status == new_status) { |
| 158 | return; | 128 | return; |
| 159 | } | 129 | } |
| @@ -168,14 +138,12 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { | |||
| 168 | } | 138 | } |
| 169 | 139 | ||
| 170 | /// Arbitrate the highest priority thread that is waiting | 140 | /// Arbitrate the highest priority thread that is waiting |
| 171 | Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | 141 | Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { |
| 172 | Handle highest_priority_thread = 0; | 142 | Thread* highest_priority_thread = nullptr; |
| 173 | s32 priority = THREADPRIO_LOWEST; | 143 | s32 priority = THREADPRIO_LOWEST; |
| 174 | 144 | ||
| 175 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 145 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 176 | for (Handle handle : thread_queue) { | 146 | for (Thread* thread : thread_queue) { |
| 177 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 178 | |||
| 179 | if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) | 147 | if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 180 | continue; | 148 | continue; |
| 181 | 149 | ||
| @@ -183,31 +151,31 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | |||
| 183 | continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. | 151 | continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. |
| 184 | 152 | ||
| 185 | if(thread->current_priority <= priority) { | 153 | if(thread->current_priority <= priority) { |
| 186 | highest_priority_thread = handle; | 154 | highest_priority_thread = thread; |
| 187 | priority = thread->current_priority; | 155 | priority = thread->current_priority; |
| 188 | } | 156 | } |
| 189 | } | 157 | } |
| 158 | |||
| 190 | // If a thread was arbitrated, resume it | 159 | // If a thread was arbitrated, resume it |
| 191 | if (0 != highest_priority_thread) | 160 | if (nullptr != highest_priority_thread) { |
| 192 | ResumeThreadFromWait(highest_priority_thread); | 161 | highest_priority_thread->ResumeFromWait(); |
| 162 | } | ||
| 193 | 163 | ||
| 194 | return highest_priority_thread; | 164 | return highest_priority_thread; |
| 195 | } | 165 | } |
| 196 | 166 | ||
| 197 | /// Arbitrate all threads currently waiting | 167 | /// Arbitrate all threads currently waiting |
| 198 | void ArbitrateAllThreads(u32 arbiter, u32 address) { | 168 | void ArbitrateAllThreads(Object* arbiter, u32 address) { |
| 199 | 169 | ||
| 200 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 170 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 201 | for (Handle handle : thread_queue) { | 171 | for (Thread* thread : thread_queue) { |
| 202 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 203 | |||
| 204 | if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) | 172 | if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 205 | ResumeThreadFromWait(handle); | 173 | thread->ResumeFromWait(); |
| 206 | } | 174 | } |
| 207 | } | 175 | } |
| 208 | 176 | ||
| 209 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) | 177 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) |
| 210 | void CallThread(Thread* t) { | 178 | static void CallThread(Thread* t) { |
| 211 | // Stop waiting | 179 | // Stop waiting |
| 212 | if (t->wait_type != WAITTYPE_NONE) { | 180 | if (t->wait_type != WAITTYPE_NONE) { |
| 213 | t->wait_type = WAITTYPE_NONE; | 181 | t->wait_type = WAITTYPE_NONE; |
| @@ -216,12 +184,12 @@ void CallThread(Thread* t) { | |||
| 216 | } | 184 | } |
| 217 | 185 | ||
| 218 | /// Switches CPU context to that of the specified thread | 186 | /// Switches CPU context to that of the specified thread |
| 219 | void SwitchContext(Thread* t) { | 187 | static void SwitchContext(Thread* t) { |
| 220 | Thread* cur = GetCurrentThread(); | 188 | Thread* cur = GetCurrentThread(); |
| 221 | 189 | ||
| 222 | // Save context for current thread | 190 | // Save context for current thread |
| 223 | if (cur) { | 191 | if (cur) { |
| 224 | SaveContext(cur->context); | 192 | Core::g_app_core->SaveContext(cur->context); |
| 225 | 193 | ||
| 226 | if (cur->IsRunning()) { | 194 | if (cur->IsRunning()) { |
| 227 | ChangeReadyState(cur, true); | 195 | ChangeReadyState(cur, true); |
| @@ -229,19 +197,19 @@ void SwitchContext(Thread* t) { | |||
| 229 | } | 197 | } |
| 230 | // Load context of new thread | 198 | // Load context of new thread |
| 231 | if (t) { | 199 | if (t) { |
| 232 | SetCurrentThread(t); | 200 | current_thread = t; |
| 233 | ChangeReadyState(t, false); | 201 | ChangeReadyState(t, false); |
| 234 | t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; | 202 | t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; |
| 235 | t->wait_type = WAITTYPE_NONE; | 203 | t->wait_type = WAITTYPE_NONE; |
| 236 | LoadContext(t->context); | 204 | Core::g_app_core->LoadContext(t->context); |
| 237 | } else { | 205 | } else { |
| 238 | SetCurrentThread(nullptr); | 206 | current_thread = nullptr; |
| 239 | } | 207 | } |
| 240 | } | 208 | } |
| 241 | 209 | ||
| 242 | /// Gets the next thread that is ready to be run by priority | 210 | /// Gets the next thread that is ready to be run by priority |
| 243 | Thread* NextThread() { | 211 | static Thread* NextThread() { |
| 244 | Handle next; | 212 | Thread* next; |
| 245 | Thread* cur = GetCurrentThread(); | 213 | Thread* cur = GetCurrentThread(); |
| 246 | 214 | ||
| 247 | if (cur && cur->IsRunning()) { | 215 | if (cur && cur->IsRunning()) { |
| @@ -252,18 +220,18 @@ Thread* NextThread() { | |||
| 252 | if (next == 0) { | 220 | if (next == 0) { |
| 253 | return nullptr; | 221 | return nullptr; |
| 254 | } | 222 | } |
| 255 | return Kernel::g_handle_table.Get<Thread>(next); | 223 | return next; |
| 256 | } | 224 | } |
| 257 | 225 | ||
| 258 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { | 226 | void WaitCurrentThread(WaitType wait_type, Object* wait_object) { |
| 259 | Thread* thread = GetCurrentThread(); | 227 | Thread* thread = GetCurrentThread(); |
| 260 | thread->wait_type = wait_type; | 228 | thread->wait_type = wait_type; |
| 261 | thread->wait_handle = wait_handle; | 229 | thread->wait_object = wait_object; |
| 262 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | 230 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); |
| 263 | } | 231 | } |
| 264 | 232 | ||
| 265 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address) { | 233 | void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address) { |
| 266 | WaitCurrentThread(wait_type, wait_handle); | 234 | WaitCurrentThread(wait_type, wait_object); |
| 267 | GetCurrentThread()->wait_address = wait_address; | 235 | GetCurrentThread()->wait_address = wait_address; |
| 268 | } | 236 | } |
| 269 | 237 | ||
| @@ -279,67 +247,84 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { | |||
| 279 | return; | 247 | return; |
| 280 | } | 248 | } |
| 281 | 249 | ||
| 282 | Kernel::ResumeThreadFromWait(handle); | 250 | thread->ResumeFromWait(); |
| 283 | } | 251 | } |
| 284 | 252 | ||
| 285 | 253 | ||
| 286 | void WakeThreadAfterDelay(Handle handle, s64 nanoseconds) { | 254 | void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { |
| 287 | // Don't schedule a wakeup if the thread wants to wait forever | 255 | // Don't schedule a wakeup if the thread wants to wait forever |
| 288 | if (nanoseconds == -1) | 256 | if (nanoseconds == -1) |
| 289 | return; | 257 | return; |
| 290 | 258 | _dbg_assert_(Kernel, thread != nullptr); | |
| 291 | Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); | ||
| 292 | if (thread == nullptr) { | ||
| 293 | LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); | ||
| 294 | return; | ||
| 295 | } | ||
| 296 | 259 | ||
| 297 | u64 microseconds = nanoseconds / 1000; | 260 | u64 microseconds = nanoseconds / 1000; |
| 298 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, handle); | 261 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); |
| 299 | } | 262 | } |
| 300 | 263 | ||
| 301 | /// Resumes a thread from waiting by marking it as "ready" | 264 | /// Resumes a thread from waiting by marking it as "ready" |
| 302 | void ResumeThreadFromWait(Handle handle) { | 265 | void Thread::ResumeFromWait() { |
| 303 | Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); | 266 | status &= ~THREADSTATUS_WAIT; |
| 304 | if (thread) { | 267 | wait_object = nullptr; |
| 305 | thread->status &= ~THREADSTATUS_WAIT; | 268 | wait_type = WAITTYPE_NONE; |
| 306 | thread->wait_handle = 0; | 269 | if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 307 | thread->wait_type = WAITTYPE_NONE; | 270 | ChangeReadyState(this, true); |
| 308 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | ||
| 309 | ChangeReadyState(thread, true); | ||
| 310 | } | ||
| 311 | } | 271 | } |
| 312 | } | 272 | } |
| 313 | 273 | ||
| 314 | /// Prints the thread queue for debugging purposes | 274 | /// Prints the thread queue for debugging purposes |
| 315 | void DebugThreadQueue() { | 275 | static void DebugThreadQueue() { |
| 316 | Thread* thread = GetCurrentThread(); | 276 | Thread* thread = GetCurrentThread(); |
| 317 | if (!thread) { | 277 | if (!thread) { |
| 318 | return; | 278 | return; |
| 319 | } | 279 | } |
| 320 | LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); | 280 | LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle()); |
| 321 | for (u32 i = 0; i < thread_queue.size(); i++) { | 281 | for (Thread* t : thread_queue) { |
| 322 | Handle handle = thread_queue[i]; | 282 | s32 priority = thread_ready_queue.contains(t); |
| 323 | s32 priority = thread_ready_queue.contains(handle); | ||
| 324 | if (priority != -1) { | 283 | if (priority != -1) { |
| 325 | LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, handle); | 284 | LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle()); |
| 326 | } | 285 | } |
| 327 | } | 286 | } |
| 328 | } | 287 | } |
| 329 | 288 | ||
| 330 | /// Creates a new thread | 289 | ResultVal<Thread*> Thread::Create(const char* name, u32 entry_point, s32 priority, u32 arg, |
| 331 | Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, | 290 | s32 processor_id, u32 stack_top, int stack_size) { |
| 332 | s32 processor_id, u32 stack_top, int stack_size) { | 291 | _dbg_assert_(Kernel, name != nullptr); |
| 292 | |||
| 293 | if ((u32)stack_size < 0x200) { | ||
| 294 | LOG_ERROR(Kernel, "(name=%s): invalid stack_size=0x%08X", name, stack_size); | ||
| 295 | // TODO: Verify error | ||
| 296 | return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Kernel, | ||
| 297 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 298 | } | ||
| 299 | |||
| 300 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | ||
| 301 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | ||
| 302 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", | ||
| 303 | name, priority, new_priority); | ||
| 304 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | ||
| 305 | // validity of this | ||
| 306 | priority = new_priority; | ||
| 307 | } | ||
| 333 | 308 | ||
| 334 | _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), | 309 | if (!Memory::GetPointer(entry_point)) { |
| 335 | "priority=%d, outside of allowable range!", priority) | 310 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name, entry_point); |
| 311 | // TODO: Verify error | ||
| 312 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||
| 313 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 314 | } | ||
| 336 | 315 | ||
| 337 | Thread* thread = new Thread; | 316 | Thread* thread = new Thread; |
| 338 | 317 | ||
| 339 | // TOOD(yuriks): Fix error reporting | 318 | // TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for |
| 340 | handle = Kernel::g_handle_table.Create(thread).ValueOr(INVALID_HANDLE); | 319 | // the time being. Create a handle here, it will be copied to the handle field in |
| 320 | // the object and use by the rest of the code. This should be removed when other | ||
| 321 | // code doesn't rely on the handle anymore. | ||
| 322 | ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread); | ||
| 323 | // TODO(yuriks): Plug memory leak | ||
| 324 | if (handle.Failed()) | ||
| 325 | return handle.Code(); | ||
| 341 | 326 | ||
| 342 | thread_queue.push_back(handle); | 327 | thread_queue.push_back(thread); |
| 343 | thread_ready_queue.prepare(priority); | 328 | thread_ready_queue.prepare(priority); |
| 344 | 329 | ||
| 345 | thread->thread_id = next_thread_id++; | 330 | thread->thread_id = next_thread_id++; |
| @@ -350,69 +335,18 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio | |||
| 350 | thread->initial_priority = thread->current_priority = priority; | 335 | thread->initial_priority = thread->current_priority = priority; |
| 351 | thread->processor_id = processor_id; | 336 | thread->processor_id = processor_id; |
| 352 | thread->wait_type = WAITTYPE_NONE; | 337 | thread->wait_type = WAITTYPE_NONE; |
| 353 | thread->wait_handle = 0; | 338 | thread->wait_object = nullptr; |
| 354 | thread->wait_address = 0; | 339 | thread->wait_address = 0; |
| 355 | thread->name = name; | 340 | thread->name = name; |
| 356 | 341 | ||
| 357 | return thread; | ||
| 358 | } | ||
| 359 | |||
| 360 | /// Creates a new thread - wrapper for external user | ||
| 361 | Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, | ||
| 362 | u32 stack_top, int stack_size) { | ||
| 363 | |||
| 364 | if (name == nullptr) { | ||
| 365 | LOG_ERROR(Kernel_SVC, "nullptr name"); | ||
| 366 | return -1; | ||
| 367 | } | ||
| 368 | if ((u32)stack_size < 0x200) { | ||
| 369 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid stack_size=0x%08X", name, | ||
| 370 | stack_size); | ||
| 371 | return -1; | ||
| 372 | } | ||
| 373 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | ||
| 374 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | ||
| 375 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", | ||
| 376 | name, priority, new_priority); | ||
| 377 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | ||
| 378 | // validity of this | ||
| 379 | priority = new_priority; | ||
| 380 | } | ||
| 381 | if (!Memory::GetPointer(entry_point)) { | ||
| 382 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name, entry_point); | ||
| 383 | return -1; | ||
| 384 | } | ||
| 385 | Handle handle; | ||
| 386 | Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, | ||
| 387 | stack_size); | ||
| 388 | |||
| 389 | ResetThread(thread, arg, 0); | 342 | ResetThread(thread, arg, 0); |
| 390 | CallThread(thread); | 343 | CallThread(thread); |
| 391 | 344 | ||
| 392 | return handle; | 345 | return MakeResult<Thread*>(thread); |
| 393 | } | ||
| 394 | |||
| 395 | /// Get the priority of the thread specified by handle | ||
| 396 | ResultVal<u32> GetThreadPriority(const Handle handle) { | ||
| 397 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 398 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 399 | |||
| 400 | return MakeResult<u32>(thread->current_priority); | ||
| 401 | } | 346 | } |
| 402 | 347 | ||
| 403 | /// Set the priority of the thread specified by handle | 348 | /// Set the priority of the thread specified by handle |
| 404 | ResultCode SetThreadPriority(Handle handle, s32 priority) { | 349 | void Thread::SetPriority(s32 priority) { |
| 405 | Thread* thread = nullptr; | ||
| 406 | if (!handle) { | ||
| 407 | thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? | ||
| 408 | } else { | ||
| 409 | thread = g_handle_table.Get<Thread>(handle); | ||
| 410 | if (thread == nullptr) { | ||
| 411 | return InvalidHandle(ErrorModule::Kernel); | ||
| 412 | } | ||
| 413 | } | ||
| 414 | _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||
| 415 | |||
| 416 | // If priority is invalid, clamp to valid range | 350 | // If priority is invalid, clamp to valid range |
| 417 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | 351 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { |
| 418 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | 352 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); |
| @@ -423,38 +357,39 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) { | |||
| 423 | } | 357 | } |
| 424 | 358 | ||
| 425 | // Change thread priority | 359 | // Change thread priority |
| 426 | s32 old = thread->current_priority; | 360 | s32 old = current_priority; |
| 427 | thread_ready_queue.remove(old, handle); | 361 | thread_ready_queue.remove(old, this); |
| 428 | thread->current_priority = priority; | 362 | current_priority = priority; |
| 429 | thread_ready_queue.prepare(thread->current_priority); | 363 | thread_ready_queue.prepare(current_priority); |
| 430 | 364 | ||
| 431 | // Change thread status to "ready" and push to ready queue | 365 | // Change thread status to "ready" and push to ready queue |
| 432 | if (thread->IsRunning()) { | 366 | if (IsRunning()) { |
| 433 | thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; | 367 | status = (status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; |
| 434 | } | 368 | } |
| 435 | if (thread->IsReady()) { | 369 | if (IsReady()) { |
| 436 | thread_ready_queue.push_back(thread->current_priority, handle); | 370 | thread_ready_queue.push_back(current_priority, this); |
| 437 | } | 371 | } |
| 438 | |||
| 439 | return RESULT_SUCCESS; | ||
| 440 | } | 372 | } |
| 441 | 373 | ||
| 442 | Handle SetupIdleThread() { | 374 | Handle SetupIdleThread() { |
| 443 | Handle handle; | 375 | // We need to pass a few valid values to get around parameter checking in Thread::Create. |
| 444 | Thread* thread = CreateThread(handle, "idle", 0, THREADPRIO_LOWEST, THREADPROCESSORID_0, 0, 0); | 376 | auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, |
| 377 | THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE); | ||
| 378 | _dbg_assert_(Kernel, thread_res.Succeeded()); | ||
| 379 | Thread* thread = *thread_res; | ||
| 380 | |||
| 445 | thread->idle = true; | 381 | thread->idle = true; |
| 446 | CallThread(thread); | 382 | CallThread(thread); |
| 447 | return handle; | 383 | return thread->GetHandle(); |
| 448 | } | 384 | } |
| 449 | 385 | ||
| 450 | Handle SetupMainThread(s32 priority, int stack_size) { | 386 | Thread* SetupMainThread(s32 priority, int stack_size) { |
| 451 | Handle handle; | ||
| 452 | |||
| 453 | // Initialize new "main" thread | 387 | // Initialize new "main" thread |
| 454 | Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, | 388 | ResultVal<Thread*> thread_res = Thread::Create("main", Core::g_app_core->GetPC(), priority, 0, |
| 455 | THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); | 389 | THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); |
| 456 | 390 | // TODO(yuriks): Propagate error | |
| 457 | ResetThread(thread, 0, 0); | 391 | _dbg_assert_(Kernel, thread_res.Succeeded()); |
| 392 | Thread* thread = *thread_res; | ||
| 458 | 393 | ||
| 459 | // If running another thread already, set it to "ready" state | 394 | // If running another thread already, set it to "ready" state |
| 460 | Thread* cur = GetCurrentThread(); | 395 | Thread* cur = GetCurrentThread(); |
| @@ -463,11 +398,11 @@ Handle SetupMainThread(s32 priority, int stack_size) { | |||
| 463 | } | 398 | } |
| 464 | 399 | ||
| 465 | // Run new "main" thread | 400 | // Run new "main" thread |
| 466 | SetCurrentThread(thread); | 401 | current_thread = thread; |
| 467 | thread->status = THREADSTATUS_RUNNING; | 402 | thread->status = THREADSTATUS_RUNNING; |
| 468 | LoadContext(thread->context); | 403 | Core::g_app_core->LoadContext(thread->context); |
| 469 | 404 | ||
| 470 | return handle; | 405 | return thread; |
| 471 | } | 406 | } |
| 472 | 407 | ||
| 473 | 408 | ||
| @@ -483,34 +418,13 @@ void Reschedule() { | |||
| 483 | } else { | 418 | } else { |
| 484 | LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); | 419 | LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); |
| 485 | 420 | ||
| 486 | for (Handle handle : thread_queue) { | 421 | for (Thread* thread : thread_queue) { |
| 487 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 488 | LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", | 422 | LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", |
| 489 | thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); | 423 | thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_object->GetHandle()); |
| 490 | } | 424 | } |
| 491 | } | 425 | } |
| 492 | } | 426 | } |
| 493 | 427 | ||
| 494 | bool IsIdleThread(Handle handle) { | ||
| 495 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 496 | if (!thread) { | ||
| 497 | LOG_ERROR(Kernel, "Thread not found %u", handle); | ||
| 498 | return false; | ||
| 499 | } | ||
| 500 | return thread->IsIdle(); | ||
| 501 | } | ||
| 502 | |||
| 503 | ResultCode GetThreadId(u32* thread_id, Handle handle) { | ||
| 504 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 505 | if (thread == nullptr) | ||
| 506 | return ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS, | ||
| 507 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 508 | |||
| 509 | *thread_id = thread->thread_id; | ||
| 510 | |||
| 511 | return RESULT_SUCCESS; | ||
| 512 | } | ||
| 513 | |||
| 514 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 428 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 515 | 429 | ||
| 516 | void ThreadingInit() { | 430 | void ThreadingInit() { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 51290975e..24450379c 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -54,6 +54,9 @@ namespace Kernel { | |||
| 54 | 54 | ||
| 55 | class Thread : public Kernel::Object { | 55 | class Thread : public Kernel::Object { |
| 56 | public: | 56 | public: |
| 57 | static ResultVal<Thread*> Create(const char* name, u32 entry_point, s32 priority, u32 arg, | ||
| 58 | s32 processor_id, u32 stack_top, int stack_size = Kernel::DEFAULT_STACK_SIZE); | ||
| 59 | |||
| 57 | std::string GetName() const override { return name; } | 60 | std::string GetName() const override { return name; } |
| 58 | std::string GetTypeName() const override { return "Thread"; } | 61 | std::string GetTypeName() const override { return "Thread"; } |
| 59 | 62 | ||
| @@ -69,6 +72,15 @@ public: | |||
| 69 | 72 | ||
| 70 | ResultVal<bool> WaitSynchronization() override; | 73 | ResultVal<bool> WaitSynchronization() override; |
| 71 | 74 | ||
| 75 | s32 GetPriority() const { return current_priority; } | ||
| 76 | void SetPriority(s32 priority); | ||
| 77 | |||
| 78 | u32 GetThreadId() const { return thread_id; } | ||
| 79 | |||
| 80 | void Stop(const char* reason); | ||
| 81 | /// Resumes a thread from waiting by marking it as "ready". | ||
| 82 | void ResumeFromWait(); | ||
| 83 | |||
| 72 | Core::ThreadContext context; | 84 | Core::ThreadContext context; |
| 73 | 85 | ||
| 74 | u32 thread_id; | 86 | u32 thread_id; |
| @@ -84,10 +96,10 @@ public: | |||
| 84 | s32 processor_id; | 96 | s32 processor_id; |
| 85 | 97 | ||
| 86 | WaitType wait_type; | 98 | WaitType wait_type; |
| 87 | Handle wait_handle; | 99 | Object* wait_object; |
| 88 | VAddr wait_address; | 100 | VAddr wait_address; |
| 89 | 101 | ||
| 90 | std::vector<Handle> waiting_threads; | 102 | std::vector<Thread*> waiting_threads; // TODO(yuriks): Owned |
| 91 | 103 | ||
| 92 | std::string name; | 104 | std::string name; |
| 93 | 105 | ||
| @@ -95,79 +107,47 @@ public: | |||
| 95 | bool idle = false; | 107 | bool idle = false; |
| 96 | 108 | ||
| 97 | private: | 109 | private: |
| 98 | // TODO(yuriks) Temporary until the creation logic can be moved into a static function | ||
| 99 | friend Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, | ||
| 100 | s32 processor_id, u32 stack_top, int stack_size); | ||
| 101 | |||
| 102 | Thread() = default; | 110 | Thread() = default; |
| 103 | }; | 111 | }; |
| 104 | 112 | ||
| 105 | /// Creates a new thread - wrapper for external user | ||
| 106 | Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, | ||
| 107 | u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE); | ||
| 108 | |||
| 109 | /// Sets up the primary application thread | 113 | /// Sets up the primary application thread |
| 110 | Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); | 114 | Thread* SetupMainThread(s32 priority, int stack_size = Kernel::DEFAULT_STACK_SIZE); |
| 111 | 115 | ||
| 112 | /// Reschedules to the next available thread (call after current thread is suspended) | 116 | /// Reschedules to the next available thread (call after current thread is suspended) |
| 113 | void Reschedule(); | 117 | void Reschedule(); |
| 114 | 118 | ||
| 115 | /// Stops the current thread | ||
| 116 | ResultCode StopThread(Handle thread, const char* reason); | ||
| 117 | |||
| 118 | /** | ||
| 119 | * Retrieves the ID of the specified thread handle | ||
| 120 | * @param thread_id Will contain the output thread id | ||
| 121 | * @param handle Handle to the thread we want | ||
| 122 | * @return Whether the function was successful or not | ||
| 123 | */ | ||
| 124 | ResultCode GetThreadId(u32* thread_id, Handle handle); | ||
| 125 | |||
| 126 | /// Resumes a thread from waiting by marking it as "ready" | ||
| 127 | void ResumeThreadFromWait(Handle handle); | ||
| 128 | |||
| 129 | /// Arbitrate the highest priority thread that is waiting | 119 | /// Arbitrate the highest priority thread that is waiting |
| 130 | Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address); | 120 | Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address); |
| 131 | 121 | ||
| 132 | /// Arbitrate all threads currently waiting... | 122 | /// Arbitrate all threads currently waiting... |
| 133 | void ArbitrateAllThreads(u32 arbiter, u32 address); | 123 | void ArbitrateAllThreads(Object* arbiter, u32 address); |
| 134 | 124 | ||
| 135 | /// Gets the current thread | 125 | /// Gets the current thread |
| 136 | Thread* GetCurrentThread(); | 126 | Thread* GetCurrentThread(); |
| 137 | 127 | ||
| 138 | /// Gets the current thread handle | ||
| 139 | Handle GetCurrentThreadHandle(); | ||
| 140 | |||
| 141 | /** | 128 | /** |
| 142 | * Puts the current thread in the wait state for the given type | 129 | * Puts the current thread in the wait state for the given type |
| 143 | * @param wait_type Type of wait | 130 | * @param wait_type Type of wait |
| 144 | * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread | 131 | * @param wait_object Kernel object that we are waiting on, defaults to current thread |
| 145 | */ | 132 | */ |
| 146 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle()); | 133 | void WaitCurrentThread(WaitType wait_type, Object* wait_object = GetCurrentThread()); |
| 147 | 134 | ||
| 148 | /** | 135 | /** |
| 149 | * Schedules an event to wake up the specified thread after the specified delay. | 136 | * Schedules an event to wake up the specified thread after the specified delay. |
| 150 | * @param handle The thread handle. | 137 | * @param handle The thread handle. |
| 151 | * @param nanoseconds The time this thread will be allowed to sleep for. | 138 | * @param nanoseconds The time this thread will be allowed to sleep for. |
| 152 | */ | 139 | */ |
| 153 | void WakeThreadAfterDelay(Handle handle, s64 nanoseconds); | 140 | void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); |
| 154 | 141 | ||
| 155 | /** | 142 | /** |
| 156 | * Puts the current thread in the wait state for the given type | 143 | * Puts the current thread in the wait state for the given type |
| 157 | * @param wait_type Type of wait | 144 | * @param wait_type Type of wait |
| 158 | * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread | 145 | * @param wait_object Kernel object that we are waiting on |
| 159 | * @param wait_address Arbitration address used to resume from wait | 146 | * @param wait_address Arbitration address used to resume from wait |
| 160 | */ | 147 | */ |
| 161 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address); | 148 | void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address); |
| 162 | 149 | ||
| 163 | /// Put current thread in a wait state - on WaitSynchronization | ||
| 164 | void WaitThread_Synchronization(); | ||
| 165 | 150 | ||
| 166 | /// Get the priority of the thread specified by handle | ||
| 167 | ResultVal<u32> GetThreadPriority(const Handle handle); | ||
| 168 | |||
| 169 | /// Set the priority of the thread specified by handle | ||
| 170 | ResultCode SetThreadPriority(Handle handle, s32 priority); | ||
| 171 | 151 | ||
| 172 | /** | 152 | /** |
| 173 | * Sets up the idle thread, this is a thread that is intended to never execute instructions, | 153 | * Sets up the idle thread, this is a thread that is intended to never execute instructions, |
| @@ -176,10 +156,6 @@ ResultCode SetThreadPriority(Handle handle, s32 priority); | |||
| 176 | * @returns The handle of the idle thread | 156 | * @returns The handle of the idle thread |
| 177 | */ | 157 | */ |
| 178 | Handle SetupIdleThread(); | 158 | Handle SetupIdleThread(); |
| 179 | |||
| 180 | /// Whether the current thread is an idle thread | ||
| 181 | bool IsIdleThread(Handle thread); | ||
| 182 | |||
| 183 | /// Initialize threading | 159 | /// Initialize threading |
| 184 | void ThreadingInit(); | 160 | void ThreadingInit(); |
| 185 | 161 | ||
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 7ac669e31..685a202c0 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -33,8 +33,8 @@ public: | |||
| 33 | ResultVal<bool> WaitSynchronization() override { | 33 | ResultVal<bool> WaitSynchronization() override { |
| 34 | bool wait = !signaled; | 34 | bool wait = !signaled; |
| 35 | if (wait) { | 35 | if (wait) { |
| 36 | waiting_threads.insert(GetCurrentThreadHandle()); | 36 | waiting_threads.insert(GetCurrentThread()->GetHandle()); |
| 37 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, GetHandle()); | 37 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); |
| 38 | } | 38 | } |
| 39 | return MakeResult<bool>(wait); | 39 | return MakeResult<bool>(wait); |
| 40 | } | 40 | } |
| @@ -92,8 +92,10 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 92 | timer->signaled = true; | 92 | timer->signaled = true; |
| 93 | 93 | ||
| 94 | // Resume all waiting threads | 94 | // Resume all waiting threads |
| 95 | for (Handle thread : timer->waiting_threads) | 95 | for (Handle thread_handle : timer->waiting_threads) { |
| 96 | ResumeThreadFromWait(thread); | 96 | if (Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle)) |
| 97 | thread->ResumeFromWait(); | ||
| 98 | } | ||
| 97 | 99 | ||
| 98 | timer->waiting_threads.clear(); | 100 | timer->waiting_threads.clear(); |
| 99 | 101 | ||
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 92de442e8..6380d214c 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -231,41 +231,47 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top | |||
| 231 | name = Common::StringFromFormat("unknown-%08x", entry_point); | 231 | name = Common::StringFromFormat("unknown-%08x", entry_point); |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, | 234 | ResultVal<Kernel::Thread*> thread_res = Kernel::Thread::Create(name.c_str(), entry_point, priority, arg, |
| 235 | stack_top); | 235 | processor_id, stack_top); |
| 236 | if (thread_res.Failed()) | ||
| 237 | return thread_res.Code().raw; | ||
| 238 | Kernel::Thread* thread = *thread_res; | ||
| 236 | 239 | ||
| 237 | Core::g_app_core->SetReg(1, thread); | 240 | Core::g_app_core->SetReg(1, thread->GetHandle()); |
| 238 | 241 | ||
| 239 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | 242 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |
| 240 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, | 243 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, |
| 241 | name.c_str(), arg, stack_top, priority, processor_id, thread); | 244 | name.c_str(), arg, stack_top, priority, processor_id, thread->GetHandle()); |
| 242 | 245 | ||
| 243 | return 0; | 246 | return 0; |
| 244 | } | 247 | } |
| 245 | 248 | ||
| 246 | /// Called when a thread exits | 249 | /// Called when a thread exits |
| 247 | static u32 ExitThread() { | 250 | static void ExitThread() { |
| 248 | Handle thread = Kernel::GetCurrentThreadHandle(); | 251 | LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); |
| 249 | 252 | ||
| 250 | LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C | 253 | Kernel::GetCurrentThread()->Stop(__func__); |
| 251 | |||
| 252 | Kernel::StopThread(thread, __func__); | ||
| 253 | HLE::Reschedule(__func__); | 254 | HLE::Reschedule(__func__); |
| 254 | return 0; | ||
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | /// Gets the priority for the specified thread | 257 | /// Gets the priority for the specified thread |
| 258 | static Result GetThreadPriority(s32* priority, Handle handle) { | 258 | static Result GetThreadPriority(s32* priority, Handle handle) { |
| 259 | ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle); | 259 | const Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 260 | if (priority_result.Succeeded()) { | 260 | if (thread == nullptr) |
| 261 | *priority = *priority_result; | 261 | return InvalidHandle(ErrorModule::Kernel).raw; |
| 262 | } | 262 | |
| 263 | return priority_result.Code().raw; | 263 | *priority = thread->GetPriority(); |
| 264 | return RESULT_SUCCESS.raw; | ||
| 264 | } | 265 | } |
| 265 | 266 | ||
| 266 | /// Sets the priority for the specified thread | 267 | /// Sets the priority for the specified thread |
| 267 | static Result SetThreadPriority(Handle handle, s32 priority) { | 268 | static Result SetThreadPriority(Handle handle, s32 priority) { |
| 268 | return Kernel::SetThreadPriority(handle, priority).raw; | 269 | Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 270 | if (thread == nullptr) | ||
| 271 | return InvalidHandle(ErrorModule::Kernel).raw; | ||
| 272 | |||
| 273 | thread->SetPriority(priority); | ||
| 274 | return RESULT_SUCCESS.raw; | ||
| 269 | } | 275 | } |
| 270 | 276 | ||
| 271 | /// Create a mutex | 277 | /// Create a mutex |
| @@ -286,8 +292,13 @@ static Result ReleaseMutex(Handle handle) { | |||
| 286 | /// Get the ID for the specified thread. | 292 | /// Get the ID for the specified thread. |
| 287 | static Result GetThreadId(u32* thread_id, Handle handle) { | 293 | static Result GetThreadId(u32* thread_id, Handle handle) { |
| 288 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); | 294 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); |
| 289 | ResultCode result = Kernel::GetThreadId(thread_id, handle); | 295 | |
| 290 | return result.raw; | 296 | const Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 297 | if (thread == nullptr) | ||
| 298 | return InvalidHandle(ErrorModule::Kernel).raw; | ||
| 299 | |||
| 300 | *thread_id = thread->GetThreadId(); | ||
| 301 | return RESULT_SUCCESS.raw; | ||
| 291 | } | 302 | } |
| 292 | 303 | ||
| 293 | /// Creates a semaphore | 304 | /// Creates a semaphore |
| @@ -375,7 +386,7 @@ static void SleepThread(s64 nanoseconds) { | |||
| 375 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); | 386 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); |
| 376 | 387 | ||
| 377 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 388 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 378 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThreadHandle(), nanoseconds); | 389 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds); |
| 379 | 390 | ||
| 380 | HLE::Reschedule(__func__); | 391 | HLE::Reschedule(__func__); |
| 381 | } | 392 | } |
| @@ -407,7 +418,7 @@ const HLE::FunctionDef SVC_Table[] = { | |||
| 407 | {0x06, nullptr, "GetProcessIdealProcessor"}, | 418 | {0x06, nullptr, "GetProcessIdealProcessor"}, |
| 408 | {0x07, nullptr, "SetProcessIdealProcessor"}, | 419 | {0x07, nullptr, "SetProcessIdealProcessor"}, |
| 409 | {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, | 420 | {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, |
| 410 | {0x09, HLE::Wrap<ExitThread>, "ExitThread"}, | 421 | {0x09, ExitThread, "ExitThread"}, |
| 411 | {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, | 422 | {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, |
| 412 | {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, | 423 | {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, |
| 413 | {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, | 424 | {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, |