thread.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. class Thread : public Kernel::Object {
  19. public:
  20. const char* GetName() { return name; }
  21. const char* GetTypeName() { return "Thread"; }
  22. static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
  23. Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
  24. inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
  25. inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
  26. inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
  27. inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
  28. inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
  29. /**
  30. * Synchronize kernel object
  31. * @param wait Boolean wait set if current thread should wait as a result of sync operation
  32. * @return Result of operation, 0 on success, otherwise error code
  33. */
  34. Result SyncRequest(bool* wait) {
  35. return 0;
  36. }
  37. ThreadContext context;
  38. u32 status;
  39. u32 entry_point;
  40. u32 stack_top;
  41. u32 stack_size;
  42. s32 initial_priority;
  43. s32 current_priority;
  44. s32 processor_id;
  45. WaitType wait_type;
  46. char name[Kernel::MAX_NAME_LENGTH + 1];
  47. };
  48. // Lists all thread ids that aren't deleted/etc.
  49. std::vector<Handle> g_thread_queue;
  50. // Lists only ready thread ids.
  51. Common::ThreadQueueList<Handle> g_thread_ready_queue;
  52. Handle g_current_thread_handle;
  53. Thread* g_current_thread;
  54. /// Gets the current thread
  55. inline Thread* GetCurrentThread() {
  56. return g_current_thread;
  57. }
  58. /// Gets the current thread handle
  59. Handle GetCurrentThreadHandle() {
  60. return GetCurrentThread()->GetHandle();
  61. }
  62. /// Sets the current thread
  63. inline void SetCurrentThread(Thread* t) {
  64. g_current_thread = t;
  65. g_current_thread_handle = t->GetHandle();
  66. }
  67. /// Saves the current CPU context
  68. void SaveContext(ThreadContext& ctx) {
  69. Core::g_app_core->SaveContext(ctx);
  70. }
  71. /// Loads a CPU context
  72. void LoadContext(ThreadContext& ctx) {
  73. Core::g_app_core->LoadContext(ctx);
  74. }
  75. /// Resets a thread
  76. void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
  77. memset(&t->context, 0, sizeof(ThreadContext));
  78. t->context.cpu_registers[0] = arg;
  79. t->context.pc = t->entry_point;
  80. t->context.sp = t->stack_top;
  81. t->context.cpsr = 0x1F; // Usermode
  82. if (t->current_priority < lowest_priority) {
  83. t->current_priority = t->initial_priority;
  84. }
  85. t->wait_type = WAITTYPE_NONE;
  86. }
  87. /// Change a thread to "ready" state
  88. void ChangeReadyState(Thread* t, bool ready) {
  89. Handle handle = t->GetHandle();
  90. if (t->IsReady()) {
  91. if (!ready) {
  92. g_thread_ready_queue.remove(t->current_priority, handle);
  93. }
  94. } else if (ready) {
  95. if (t->IsRunning()) {
  96. g_thread_ready_queue.push_front(t->current_priority, handle);
  97. } else {
  98. g_thread_ready_queue.push_back(t->current_priority, handle);
  99. }
  100. t->status = THREADSTATUS_READY;
  101. }
  102. }
  103. /// Changes a threads state
  104. void ChangeThreadState(Thread* t, ThreadStatus new_status) {
  105. if (!t || t->status == new_status) {
  106. return;
  107. }
  108. ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
  109. t->status = new_status;
  110. if (new_status == THREADSTATUS_WAIT) {
  111. if (t->wait_type == WAITTYPE_NONE) {
  112. printf("ERROR: Waittype none not allowed here\n");
  113. }
  114. }
  115. }
  116. /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
  117. void CallThread(Thread* t) {
  118. // Stop waiting
  119. if (t->wait_type != WAITTYPE_NONE) {
  120. t->wait_type = WAITTYPE_NONE;
  121. }
  122. ChangeThreadState(t, THREADSTATUS_READY);
  123. }
  124. /// Switches CPU context to that of the specified thread
  125. void SwitchContext(Thread* t) {
  126. Thread* cur = GetCurrentThread();
  127. // Save context for current thread
  128. if (cur) {
  129. SaveContext(cur->context);
  130. if (cur->IsRunning()) {
  131. ChangeReadyState(cur, true);
  132. }
  133. }
  134. // Load context of new thread
  135. if (t) {
  136. SetCurrentThread(t);
  137. ChangeReadyState(t, false);
  138. t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
  139. t->wait_type = WAITTYPE_NONE;
  140. LoadContext(t->context);
  141. } else {
  142. SetCurrentThread(NULL);
  143. }
  144. }
  145. /// Gets the next thread that is ready to be run by priority
  146. Thread* NextThread() {
  147. Handle next;
  148. Thread* cur = GetCurrentThread();
  149. if (cur && cur->IsRunning()) {
  150. next = g_thread_ready_queue.pop_first_better(cur->current_priority);
  151. } else {
  152. next = g_thread_ready_queue.pop_first();
  153. }
  154. if (next == 0) {
  155. return NULL;
  156. }
  157. return Kernel::g_object_pool.GetFast<Thread>(next);
  158. }
  159. /// Puts the current thread in the wait state for the given type
  160. void WaitCurrentThread(WaitType wait_type) {
  161. Thread* t = GetCurrentThread();
  162. t->wait_type = wait_type;
  163. ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
  164. }
  165. /// Resumes a thread from waiting by marking it as "ready"
  166. void ResumeThreadFromWait(Handle handle) {
  167. u32 error;
  168. Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error);
  169. if (t) {
  170. t->status &= ~THREADSTATUS_WAIT;
  171. if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
  172. ChangeReadyState(t, true);
  173. }
  174. }
  175. }
  176. /// Creates a new thread
  177. Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
  178. s32 processor_id, u32 stack_top, int stack_size) {
  179. _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
  180. "CreateThread priority=%d, outside of allowable range!", priority)
  181. Thread* t = new Thread;
  182. handle = Kernel::g_object_pool.Create(t);
  183. g_thread_queue.push_back(handle);
  184. g_thread_ready_queue.prepare(priority);
  185. t->status = THREADSTATUS_DORMANT;
  186. t->entry_point = entry_point;
  187. t->stack_top = stack_top;
  188. t->stack_size = stack_size;
  189. t->initial_priority = t->current_priority = priority;
  190. t->processor_id = processor_id;
  191. t->wait_type = WAITTYPE_NONE;
  192. strncpy(t->name, name, Kernel::MAX_NAME_LENGTH);
  193. t->name[Kernel::MAX_NAME_LENGTH] = '\0';
  194. return t;
  195. }
  196. /// Creates a new thread - wrapper for external user
  197. Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
  198. u32 stack_top, int stack_size) {
  199. if (name == NULL) {
  200. ERROR_LOG(KERNEL, "CreateThread(): NULL name");
  201. return -1;
  202. }
  203. if ((u32)stack_size < 0x200) {
  204. ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name,
  205. stack_size);
  206. return -1;
  207. }
  208. if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
  209. s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
  210. WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X",
  211. name, priority, new_priority);
  212. // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
  213. // validity of this
  214. priority = new_priority;
  215. }
  216. if (!Memory::GetPointer(entry_point)) {
  217. ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point);
  218. return -1;
  219. }
  220. Handle handle;
  221. Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
  222. stack_size);
  223. ResetThread(t, arg, 0);
  224. HLE::EatCycles(32000);
  225. // This won't schedule to the new thread, but it may to one woken from eating cycles.
  226. // Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
  227. HLE::ReSchedule("thread created");
  228. CallThread(t);
  229. return handle;
  230. }
  231. /// Sets up the primary application thread
  232. Handle SetupMainThread(s32 priority, int stack_size) {
  233. Handle handle;
  234. // Initialize new "main" thread
  235. Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
  236. THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
  237. ResetThread(t, 0, 0);
  238. // If running another thread already, set it to "ready" state
  239. Thread* cur = GetCurrentThread();
  240. if (cur && cur->IsRunning()) {
  241. ChangeReadyState(cur, true);
  242. }
  243. // Run new "main" thread
  244. SetCurrentThread(t);
  245. t->status = THREADSTATUS_RUNNING;
  246. LoadContext(t->context);
  247. return handle;
  248. }
  249. /// Reschedules to the next available thread (call after current thread is suspended)
  250. void Reschedule() {
  251. Thread* prev = GetCurrentThread();
  252. Thread* next = NextThread();
  253. if (next > 0) {
  254. SwitchContext(next);
  255. // Hack - automatically change previous thread (which would have been in "wait" state) to
  256. // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
  257. // actually wait for whatever event it is supposed to be waiting on.
  258. ChangeReadyState(prev, true);
  259. }
  260. }
  261. ////////////////////////////////////////////////////////////////////////////////////////////////////
  262. void ThreadingInit() {
  263. }
  264. void ThreadingShutdown() {
  265. }
  266. } // namespace