thread.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright 2014 Citra Emulator Project / PPSSPP Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <list>
  6. #include <map>
  7. #include <vector>
  8. #include "common/common.h"
  9. #include "common/thread_queue_list.h"
  10. #include "core/core.h"
  11. #include "core/mem_map.h"
  12. #include "core/hle/hle.h"
  13. #include "core/hle/kernel/kernel.h"
  14. #include "core/hle/kernel/thread.h"
  15. namespace Kernel {
  16. class Thread : public Kernel::Object {
  17. public:
  18. std::string GetName() const override { return name; }
  19. std::string GetTypeName() const override { return "Thread"; }
  20. static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
  21. Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; }
  22. inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
  23. inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
  24. inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
  25. inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
  26. inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
  27. /**
  28. * Wait for kernel object to synchronize
  29. * @param wait Boolean wait set if current thread should wait as a result of sync operation
  30. * @return Result of operation, 0 on success, otherwise error code
  31. */
  32. Result WaitSynchronization(bool* wait) override {
  33. if (status != THREADSTATUS_DORMANT) {
  34. Handle thread = GetCurrentThreadHandle();
  35. if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
  36. waiting_threads.push_back(thread);
  37. }
  38. WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
  39. *wait = true;
  40. }
  41. return 0;
  42. }
  43. ThreadContext context;
  44. u32 status;
  45. u32 entry_point;
  46. u32 stack_top;
  47. u32 stack_size;
  48. s32 initial_priority;
  49. s32 current_priority;
  50. s32 processor_id;
  51. WaitType wait_type;
  52. Handle wait_handle;
  53. std::vector<Handle> waiting_threads;
  54. std::string name;
  55. };
  56. // Lists all thread ids that aren't deleted/etc.
  57. std::vector<Handle> g_thread_queue;
  58. // Lists only ready thread ids.
  59. Common::ThreadQueueList<Handle> g_thread_ready_queue;
  60. Handle g_current_thread_handle;
  61. Thread* g_current_thread;
  62. /// Gets the current thread
  63. inline Thread* GetCurrentThread() {
  64. return g_current_thread;
  65. }
  66. /// Gets the current thread handle
  67. Handle GetCurrentThreadHandle() {
  68. return GetCurrentThread()->GetHandle();
  69. }
  70. /// Sets the current thread
  71. inline void SetCurrentThread(Thread* t) {
  72. g_current_thread = t;
  73. g_current_thread_handle = t->GetHandle();
  74. }
  75. /// Saves the current CPU context
  76. void SaveContext(ThreadContext& ctx) {
  77. Core::g_app_core->SaveContext(ctx);
  78. }
  79. /// Loads a CPU context
  80. void LoadContext(ThreadContext& ctx) {
  81. Core::g_app_core->LoadContext(ctx);
  82. }
  83. /// Resets a thread
  84. void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
  85. memset(&t->context, 0, sizeof(ThreadContext));
  86. t->context.cpu_registers[0] = arg;
  87. t->context.pc = t->context.reg_15 = t->entry_point;
  88. t->context.sp = t->stack_top;
  89. t->context.cpsr = 0x1F; // Usermode
  90. // TODO(bunnei): This instructs the CPU core to start the execution as if it is "resuming" a
  91. // thread. This is somewhat Sky-Eye specific, and should be re-architected in the future to be
  92. // agnostic of the CPU core.
  93. t->context.mode = 8;
  94. if (t->current_priority < lowest_priority) {
  95. t->current_priority = t->initial_priority;
  96. }
  97. t->wait_type = WAITTYPE_NONE;
  98. t->wait_handle = 0;
  99. }
  100. /// Change a thread to "ready" state
  101. void ChangeReadyState(Thread* t, bool ready) {
  102. Handle handle = t->GetHandle();
  103. if (t->IsReady()) {
  104. if (!ready) {
  105. g_thread_ready_queue.remove(t->current_priority, handle);
  106. }
  107. } else if (ready) {
  108. if (t->IsRunning()) {
  109. g_thread_ready_queue.push_front(t->current_priority, handle);
  110. } else {
  111. g_thread_ready_queue.push_back(t->current_priority, handle);
  112. }
  113. t->status = THREADSTATUS_READY;
  114. }
  115. }
  116. /// Verify that a thread has not been released from waiting
  117. inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) {
  118. Thread* thread = g_object_pool.GetFast<Thread>(handle);
  119. _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
  120. if (type != thread->wait_type || wait_handle != thread->wait_handle)
  121. return false;
  122. return true;
  123. }
  124. /// Stops the current thread
  125. void StopThread(Handle handle, const char* reason) {
  126. Thread* thread = g_object_pool.GetFast<Thread>(handle);
  127. _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
  128. ChangeReadyState(thread, false);
  129. thread->status = THREADSTATUS_DORMANT;
  130. for (size_t i = 0; i < thread->waiting_threads.size(); ++i) {
  131. const Handle waiting_thread = thread->waiting_threads[i];
  132. if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
  133. ResumeThreadFromWait(waiting_thread);
  134. }
  135. }
  136. thread->waiting_threads.clear();
  137. // Stopped threads are never waiting.
  138. thread->wait_type = WAITTYPE_NONE;
  139. thread->wait_handle = 0;
  140. }
  141. /// Changes a threads state
  142. void ChangeThreadState(Thread* t, ThreadStatus new_status) {
  143. if (!t || t->status == new_status) {
  144. return;
  145. }
  146. ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
  147. t->status = new_status;
  148. if (new_status == THREADSTATUS_WAIT) {
  149. if (t->wait_type == WAITTYPE_NONE) {
  150. ERROR_LOG(KERNEL, "Waittype none not allowed");
  151. }
  152. }
  153. }
  154. /// Arbitrate the highest priority thread that is waiting
  155. Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
  156. Handle highest_priority_thread = 0;
  157. s32 priority = THREADPRIO_LOWEST;
  158. // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
  159. for (const auto& handle : g_thread_queue) {
  160. // TODO(bunnei): Verify arbiter address...
  161. if (!VerifyWait(handle, WAITTYPE_ARB, arbiter))
  162. continue;
  163. Thread* thread = g_object_pool.GetFast<Thread>(handle);
  164. if(thread->current_priority <= priority) {
  165. highest_priority_thread = handle;
  166. priority = thread->current_priority;
  167. }
  168. }
  169. // If a thread was arbitrated, resume it
  170. if (0 != highest_priority_thread)
  171. ResumeThreadFromWait(highest_priority_thread);
  172. return highest_priority_thread;
  173. }
  174. /// Arbitrate all threads currently waiting
  175. void ArbitrateAllThreads(u32 arbiter, u32 address) {
  176. // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
  177. for (const auto& handle : g_thread_queue) {
  178. // TODO(bunnei): Verify arbiter address...
  179. if (VerifyWait(handle, WAITTYPE_ARB, arbiter))
  180. ResumeThreadFromWait(handle);
  181. }
  182. }
  183. /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
  184. void CallThread(Thread* t) {
  185. // Stop waiting
  186. if (t->wait_type != WAITTYPE_NONE) {
  187. t->wait_type = WAITTYPE_NONE;
  188. }
  189. ChangeThreadState(t, THREADSTATUS_READY);
  190. }
  191. /// Switches CPU context to that of the specified thread
  192. void SwitchContext(Thread* t) {
  193. Thread* cur = GetCurrentThread();
  194. // Save context for current thread
  195. if (cur) {
  196. SaveContext(cur->context);
  197. if (cur->IsRunning()) {
  198. ChangeReadyState(cur, true);
  199. }
  200. }
  201. // Load context of new thread
  202. if (t) {
  203. SetCurrentThread(t);
  204. ChangeReadyState(t, false);
  205. t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
  206. t->wait_type = WAITTYPE_NONE;
  207. LoadContext(t->context);
  208. } else {
  209. SetCurrentThread(nullptr);
  210. }
  211. }
  212. /// Gets the next thread that is ready to be run by priority
  213. Thread* NextThread() {
  214. Handle next;
  215. Thread* cur = GetCurrentThread();
  216. if (cur && cur->IsRunning()) {
  217. next = g_thread_ready_queue.pop_first_better(cur->current_priority);
  218. } else {
  219. next = g_thread_ready_queue.pop_first();
  220. }
  221. if (next == 0) {
  222. return nullptr;
  223. }
  224. return Kernel::g_object_pool.GetFast<Thread>(next);
  225. }
  226. /**
  227. * Puts the current thread in the wait state for the given type
  228. * @param wait_type Type of wait
  229. * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
  230. */
  231. void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
  232. Thread* thread = GetCurrentThread();
  233. thread->wait_type = wait_type;
  234. thread->wait_handle = wait_handle;
  235. ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
  236. }
  237. /// Resumes a thread from waiting by marking it as "ready"
  238. void ResumeThreadFromWait(Handle handle) {
  239. u32 error;
  240. Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
  241. if (thread) {
  242. thread->status &= ~THREADSTATUS_WAIT;
  243. if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
  244. ChangeReadyState(thread, true);
  245. }
  246. }
  247. }
  248. /// Prints the thread queue for debugging purposes
  249. void DebugThreadQueue() {
  250. Thread* thread = GetCurrentThread();
  251. if (!thread) {
  252. return;
  253. }
  254. INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle());
  255. for (u32 i = 0; i < g_thread_queue.size(); i++) {
  256. Handle handle = g_thread_queue[i];
  257. s32 priority = g_thread_ready_queue.contains(handle);
  258. if (priority != -1) {
  259. INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle);
  260. }
  261. }
  262. }
  263. /// Creates a new thread
  264. Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
  265. s32 processor_id, u32 stack_top, int stack_size) {
  266. _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
  267. "CreateThread priority=%d, outside of allowable range!", priority)
  268. Thread* thread = new Thread;
  269. handle = Kernel::g_object_pool.Create(thread);
  270. g_thread_queue.push_back(handle);
  271. g_thread_ready_queue.prepare(priority);
  272. thread->status = THREADSTATUS_DORMANT;
  273. thread->entry_point = entry_point;
  274. thread->stack_top = stack_top;
  275. thread->stack_size = stack_size;
  276. thread->initial_priority = thread->current_priority = priority;
  277. thread->processor_id = processor_id;
  278. thread->wait_type = WAITTYPE_NONE;
  279. thread->wait_handle = 0;
  280. thread->name = name;
  281. return thread;
  282. }
  283. /// Creates a new thread - wrapper for external user
  284. Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
  285. u32 stack_top, int stack_size) {
  286. if (name == nullptr) {
  287. ERROR_LOG(KERNEL, "CreateThread(): nullptr name");
  288. return -1;
  289. }
  290. if ((u32)stack_size < 0x200) {
  291. ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name,
  292. stack_size);
  293. return -1;
  294. }
  295. if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
  296. s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
  297. WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X",
  298. name, priority, new_priority);
  299. // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
  300. // validity of this
  301. priority = new_priority;
  302. }
  303. if (!Memory::GetPointer(entry_point)) {
  304. ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point);
  305. return -1;
  306. }
  307. Handle handle;
  308. Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
  309. stack_size);
  310. ResetThread(thread, arg, 0);
  311. CallThread(thread);
  312. return handle;
  313. }
  314. /// Get the priority of the thread specified by handle
  315. u32 GetThreadPriority(const Handle handle) {
  316. Thread* thread = g_object_pool.GetFast<Thread>(handle);
  317. _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
  318. return thread->current_priority;
  319. }
  320. /// Set the priority of the thread specified by handle
  321. Result SetThreadPriority(Handle handle, s32 priority) {
  322. Thread* thread = nullptr;
  323. if (!handle) {
  324. thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
  325. } else {
  326. thread = g_object_pool.GetFast<Thread>(handle);
  327. }
  328. _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
  329. // If priority is invalid, clamp to valid range
  330. if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
  331. s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
  332. WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority);
  333. // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
  334. // validity of this
  335. priority = new_priority;
  336. }
  337. // Change thread priority
  338. s32 old = thread->current_priority;
  339. g_thread_ready_queue.remove(old, handle);
  340. thread->current_priority = priority;
  341. g_thread_ready_queue.prepare(thread->current_priority);
  342. // Change thread status to "ready" and push to ready queue
  343. if (thread->IsRunning()) {
  344. thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY;
  345. }
  346. if (thread->IsReady()) {
  347. g_thread_ready_queue.push_back(thread->current_priority, handle);
  348. }
  349. return 0;
  350. }
  351. /// Sets up the primary application thread
  352. Handle SetupMainThread(s32 priority, int stack_size) {
  353. Handle handle;
  354. // Initialize new "main" thread
  355. Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
  356. THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
  357. ResetThread(thread, 0, 0);
  358. // If running another thread already, set it to "ready" state
  359. Thread* cur = GetCurrentThread();
  360. if (cur && cur->IsRunning()) {
  361. ChangeReadyState(cur, true);
  362. }
  363. // Run new "main" thread
  364. SetCurrentThread(thread);
  365. thread->status = THREADSTATUS_RUNNING;
  366. LoadContext(thread->context);
  367. return handle;
  368. }
  369. /// Reschedules to the next available thread (call after current thread is suspended)
  370. void Reschedule() {
  371. Thread* prev = GetCurrentThread();
  372. Thread* next = NextThread();
  373. HLE::g_reschedule = false;
  374. if (next > 0) {
  375. INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
  376. SwitchContext(next);
  377. // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
  378. // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
  379. // This results in the current thread yielding on a VBLANK once, and then it will be
  380. // immediately placed back in the queue for execution.
  381. if (prev->wait_type == WAITTYPE_VBLANK) {
  382. ResumeThreadFromWait(prev->GetHandle());
  383. }
  384. }
  385. }
  386. ////////////////////////////////////////////////////////////////////////////////////////////////////
  387. void ThreadingInit() {
  388. }
  389. void ThreadingShutdown() {
  390. }
  391. } // namespace