thread.cpp 14 KB

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