thread.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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 <vector>
  7. #include <map>
  8. #include <string>
  9. #include "common/common.h"
  10. #include "common/thread_queue_list.h"
  11. #include "core/core.h"
  12. #include "core/mem_map.h"
  13. #include "core/hle/hle.h"
  14. #include "core/hle/svc.h"
  15. #include "core/hle/kernel/kernel.h"
  16. #include "core/hle/kernel/thread.h"
  17. namespace Kernel {
  18. enum ThreadStatus {
  19. THREADSTATUS_RUNNING = 1,
  20. THREADSTATUS_READY = 2,
  21. THREADSTATUS_WAIT = 4,
  22. THREADSTATUS_SUSPEND = 8,
  23. THREADSTATUS_DORMANT = 16,
  24. THREADSTATUS_DEAD = 32,
  25. THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
  26. };
  27. enum WaitType {
  28. WAITTYPE_NONE,
  29. WAITTYPE_SLEEP,
  30. WAITTYPE_SEMA,
  31. WAITTYPE_EVENTFLAG,
  32. WAITTYPE_THREADEND,
  33. WAITTYPE_VBLANK,
  34. WAITTYPE_MUTEX,
  35. WAITTYPE_SYNCH,
  36. };
  37. class Thread : public Kernel::Object {
  38. public:
  39. const char* GetName() { return name; }
  40. const char* GetTypeName() { return "Thread"; }
  41. static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
  42. Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
  43. inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
  44. inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
  45. inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
  46. inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
  47. inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
  48. ThreadContext context;
  49. u32 status;
  50. u32 entry_point;
  51. u32 stack_top;
  52. u32 stack_size;
  53. s32 initial_priority;
  54. s32 current_priority;
  55. s32 processor_id;
  56. WaitType wait_type;
  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. /// Sets the current thread
  70. inline void __SetCurrentThread(Thread* t) {
  71. g_current_thread = t;
  72. g_current_thread_handle = t->GetHandle();
  73. }
  74. /// Saves the current CPU context
  75. void __SaveContext(ThreadContext& ctx) {
  76. Core::g_app_core->SaveContext(ctx);
  77. }
  78. /// Loads a CPU context
  79. void __LoadContext(const ThreadContext& ctx) {
  80. Core::g_app_core->LoadContext(ctx);
  81. }
  82. /// Resets a thread
  83. void __ResetThread(Thread* t, s32 lowest_priority) {
  84. memset(&t->context, 0, sizeof(ThreadContext));
  85. t->context.pc = t->entry_point;
  86. t->context.sp = t->stack_top;
  87. if (t->current_priority < lowest_priority) {
  88. t->current_priority = t->initial_priority;
  89. }
  90. t->wait_type = WAITTYPE_NONE;
  91. }
  92. /// Change a thread to "ready" state
  93. void __ChangeReadyState(Thread* t, bool ready) {
  94. Handle handle = t->GetHandle();
  95. if (t->IsReady()) {
  96. if (!ready) {
  97. g_thread_ready_queue.remove(t->current_priority, handle);
  98. }
  99. } else if (ready) {
  100. if (t->IsRunning()) {
  101. g_thread_ready_queue.push_front(t->current_priority, handle);
  102. } else {
  103. g_thread_ready_queue.push_back(t->current_priority, handle);
  104. }
  105. t->status = THREADSTATUS_READY;
  106. }
  107. }
  108. /// Changes a threads state
  109. void __ChangeThreadState(Thread* t, ThreadStatus new_status) {
  110. if (!t || t->status == new_status) {
  111. return;
  112. }
  113. __ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
  114. t->status = new_status;
  115. if (new_status == THREADSTATUS_WAIT) {
  116. if (t->wait_type == WAITTYPE_NONE) {
  117. printf("ERROR: Waittype none not allowed here\n");
  118. }
  119. }
  120. }
  121. /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
  122. void __CallThread(Thread* t) {
  123. // Stop waiting
  124. if (t->wait_type != WAITTYPE_NONE) {
  125. t->wait_type = WAITTYPE_NONE;
  126. }
  127. __ChangeThreadState(t, THREADSTATUS_READY);
  128. }
  129. /// Switches CPU context to that of the specified thread
  130. void __SwitchContext(Thread* t, const char* reason) {
  131. Thread* cur = __GetCurrentThread();
  132. // Save context for current thread
  133. if (cur) {
  134. __SaveContext(cur->context);
  135. if (cur->IsRunning()) {
  136. __ChangeReadyState(cur, true);
  137. }
  138. }
  139. // Load context of new thread
  140. if (t) {
  141. __SetCurrentThread(t);
  142. __ChangeReadyState(t, false);
  143. t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
  144. t->wait_type = WAITTYPE_NONE;
  145. __LoadContext(t->context);
  146. } else {
  147. __SetCurrentThread(NULL);
  148. }
  149. }
  150. /// Gets the next thread that is ready to be run by priority
  151. Thread* __NextThread() {
  152. Handle next;
  153. Thread* cur = __GetCurrentThread();
  154. if (cur && cur->IsRunning()) {
  155. next = g_thread_ready_queue.pop_first_better(cur->current_priority);
  156. } else {
  157. next = g_thread_ready_queue.pop_first();
  158. }
  159. if (next < 0) {
  160. return NULL;
  161. }
  162. return Kernel::g_object_pool.GetFast<Thread>(next);
  163. }
  164. /// Puts a thread in the wait state for the given type/reason
  165. void __WaitCurThread(WaitType wait_type, const char* reason) {
  166. Thread* t = __GetCurrentThread();
  167. t->wait_type = wait_type;
  168. __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
  169. }
  170. /// Resumes a thread from waiting by marking it as "ready"
  171. void ResumeThreadFromWait(Handle handle) {
  172. u32 error;
  173. Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error);
  174. if (t) {
  175. t->status &= ~THREADSTATUS_WAIT;
  176. if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
  177. __ChangeReadyState(t, true);
  178. }
  179. }
  180. }
  181. /// Creates a new thread
  182. Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
  183. s32 processor_id, u32 stack_top, int stack_size) {
  184. _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
  185. "CreateThread priority=%d, outside of allowable range!", priority)
  186. Thread* t = new Thread;
  187. handle = Kernel::g_object_pool.Create(t);
  188. g_thread_queue.push_back(handle);
  189. g_thread_ready_queue.prepare(priority);
  190. t->status = THREADSTATUS_DORMANT;
  191. t->entry_point = entry_point;
  192. t->stack_top = stack_top;
  193. t->stack_size = stack_size;
  194. t->initial_priority = t->current_priority = priority;
  195. t->processor_id = processor_id;
  196. t->wait_type = WAITTYPE_NONE;
  197. strncpy(t->name, name, Kernel::MAX_NAME_LENGTH);
  198. t->name[Kernel::MAX_NAME_LENGTH] = '\0';
  199. return t;
  200. }
  201. /// Creates a new thread - wrapper for external user
  202. Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id,
  203. u32 stack_top, int stack_size) {
  204. if (name == NULL) {
  205. ERROR_LOG(KERNEL, "CreateThread(): NULL name");
  206. return -1;
  207. }
  208. if ((u32)stack_size < 0x200) {
  209. ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name,
  210. stack_size);
  211. return -1;
  212. }
  213. if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
  214. s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
  215. WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X",
  216. name, priority, new_priority);
  217. // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
  218. // validity of this
  219. priority = new_priority;
  220. }
  221. if (!Memory::GetPointer(entry_point)) {
  222. ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point);
  223. return -1;
  224. }
  225. Handle handle;
  226. Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
  227. stack_size);
  228. HLE::EatCycles(32000);
  229. // This won't schedule to the new thread, but it may to one woken from eating cycles.
  230. // Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
  231. HLE::ReSchedule("thread created");
  232. __CallThread(t);
  233. return handle;
  234. }
  235. /// Gets the current thread
  236. Handle GetCurrentThread() {
  237. return __GetCurrentThread()->GetHandle();
  238. }
  239. /// Sets up the primary application thread
  240. Handle SetupMainThread(s32 priority, int stack_size) {
  241. Handle handle;
  242. // Initialize new "main" thread
  243. Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
  244. THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
  245. __ResetThread(t, 0);
  246. // If running another thread already, set it to "ready" state
  247. Thread* cur = __GetCurrentThread();
  248. if (cur && cur->IsRunning()) {
  249. __ChangeReadyState(cur, true);
  250. }
  251. // Run new "main" thread
  252. __SetCurrentThread(t);
  253. t->status = THREADSTATUS_RUNNING;
  254. __LoadContext(t->context);
  255. return handle;
  256. }
  257. /// Reschedules to the next available thread (call after current thread is suspended)
  258. void Reschedule(const char* reason) {
  259. Thread* next = __NextThread();
  260. if (next > 0) {
  261. __SwitchContext(next, reason);
  262. }
  263. }
  264. ////////////////////////////////////////////////////////////////////////////////////////////////////
  265. /// Put current thread in a wait state - on WaitSynchronization
  266. void WaitThread_Synchronization() {
  267. // TODO(bunnei): Just a placeholder function for now... FixMe
  268. __WaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called");
  269. }
  270. ////////////////////////////////////////////////////////////////////////////////////////////////////
  271. void ThreadingInit() {
  272. }
  273. void ThreadingShutdown() {
  274. }
  275. } // namespace