diff options
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 141 |
1 files changed, 90 insertions, 51 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 76a73747d..b967b3c62 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -21,20 +21,14 @@ | |||
| 21 | 21 | ||
| 22 | // Enums | 22 | // Enums |
| 23 | 23 | ||
| 24 | enum ThreadPriority { | ||
| 25 | THREADPRIO_HIGHEST = 0, | ||
| 26 | THREADPRIO_DEFAULT = 16, | ||
| 27 | THREADPRIO_LOWEST = 31, | ||
| 28 | }; | ||
| 29 | |||
| 30 | enum ThreadStatus { | 24 | enum ThreadStatus { |
| 31 | THREADSTATUS_RUNNING = 1, | 25 | THREADSTATUS_RUNNING = 1, |
| 32 | THREADSTATUS_READY = 2, | 26 | THREADSTATUS_READY = 2, |
| 33 | THREADSTATUS_WAIT = 4, | 27 | THREADSTATUS_WAIT = 4, |
| 34 | THREADSTATUS_SUSPEND = 8, | 28 | THREADSTATUS_SUSPEND = 8, |
| 35 | THREADSTATUS_DORMANT = 16, | 29 | THREADSTATUS_DORMANT = 16, |
| 36 | THREADSTATUS_DEAD = 32, | 30 | THREADSTATUS_DEAD = 32, |
| 37 | THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND | 31 | THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND |
| 38 | }; | 32 | }; |
| 39 | 33 | ||
| 40 | enum WaitType { | 34 | enum WaitType { |
| @@ -46,8 +40,6 @@ enum WaitType { | |||
| 46 | WAITTYPE_VBLANK, | 40 | WAITTYPE_VBLANK, |
| 47 | WAITTYPE_MUTEX, | 41 | WAITTYPE_MUTEX, |
| 48 | WAITTYPE_SYNCH, | 42 | WAITTYPE_SYNCH, |
| 49 | |||
| 50 | NUM_WAITTYPES | ||
| 51 | }; | 43 | }; |
| 52 | 44 | ||
| 53 | typedef s32 Handle; | 45 | typedef s32 Handle; |
| @@ -164,32 +156,6 @@ void __KernelResetThread(Thread *t, s32 lowest_priority) { | |||
| 164 | t->wait_type = WAITTYPE_NONE; | 156 | t->wait_type = WAITTYPE_NONE; |
| 165 | } | 157 | } |
| 166 | 158 | ||
| 167 | /// Creates a new thread | ||
| 168 | Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, | ||
| 169 | s32 processor_id, u32 stack_top, int stack_size) { | ||
| 170 | static u32 _handle_count = 1; | ||
| 171 | |||
| 172 | Thread *t = new Thread; | ||
| 173 | |||
| 174 | handle = (_handle_count++); | ||
| 175 | |||
| 176 | g_thread_queue.push_back(handle); | ||
| 177 | g_thread_ready_queue.prepare(priority); | ||
| 178 | |||
| 179 | t->status = THREADSTATUS_DORMANT; | ||
| 180 | t->entry_point = entry_point; | ||
| 181 | t->stack_top = stack_top; | ||
| 182 | t->stack_size = stack_size; | ||
| 183 | t->initial_priority = t->current_priority = priority; | ||
| 184 | t->processor_id = processor_id; | ||
| 185 | t->wait_type = WAITTYPE_NONE; | ||
| 186 | |||
| 187 | strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH); | ||
| 188 | t->name[KERNEL_MAX_NAME_LENGTH] = '\0'; | ||
| 189 | |||
| 190 | return t; | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Change a thread to "ready" state | 159 | /// Change a thread to "ready" state |
| 194 | void __KernelChangeReadyState(Thread *t, bool ready) { | 160 | void __KernelChangeReadyState(Thread *t, bool ready) { |
| 195 | Handle handle = t->GetHandle(); | 161 | Handle handle = t->GetHandle(); |
| @@ -222,6 +188,79 @@ void __KernelChangeThreadState(Thread *t, ThreadStatus new_status) { | |||
| 222 | } | 188 | } |
| 223 | } | 189 | } |
| 224 | 190 | ||
| 191 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) | ||
| 192 | void __KernelCallThread(Thread *t) { | ||
| 193 | // Stop waiting | ||
| 194 | if (t->wait_type != WAITTYPE_NONE) { | ||
| 195 | t->wait_type = WAITTYPE_NONE; | ||
| 196 | } | ||
| 197 | __KernelChangeThreadState(t, THREADSTATUS_READY); | ||
| 198 | } | ||
| 199 | |||
| 200 | /// Creates a new thread | ||
| 201 | Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, | ||
| 202 | s32 processor_id, u32 stack_top, int stack_size) { | ||
| 203 | |||
| 204 | Thread *t = new Thread; | ||
| 205 | |||
| 206 | handle = g_kernel_objects.Create(t); | ||
| 207 | |||
| 208 | g_thread_queue.push_back(handle); | ||
| 209 | g_thread_ready_queue.prepare(priority); | ||
| 210 | |||
| 211 | t->status = THREADSTATUS_DORMANT; | ||
| 212 | t->entry_point = entry_point; | ||
| 213 | t->stack_top = stack_top; | ||
| 214 | t->stack_size = stack_size; | ||
| 215 | t->initial_priority = t->current_priority = priority; | ||
| 216 | t->processor_id = processor_id; | ||
| 217 | t->wait_type = WAITTYPE_NONE; | ||
| 218 | |||
| 219 | strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH); | ||
| 220 | t->name[KERNEL_MAX_NAME_LENGTH] = '\0'; | ||
| 221 | |||
| 222 | return t; | ||
| 223 | } | ||
| 224 | |||
| 225 | /// Creates a new thread - wrapper for external user | ||
| 226 | Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, s32 processor_id, | ||
| 227 | u32 stack_top, int stack_size) { | ||
| 228 | if (name == NULL) { | ||
| 229 | ERROR_LOG(KERNEL, "__KernelCreateThread(): NULL name"); | ||
| 230 | return -1; | ||
| 231 | } | ||
| 232 | if ((u32)stack_size < 0x200) { | ||
| 233 | ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid stack_size=0x%08X", name, | ||
| 234 | stack_size); | ||
| 235 | return -1; | ||
| 236 | } | ||
| 237 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | ||
| 238 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | ||
| 239 | WARN_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid priority=0x%08X, clamping to %08X", | ||
| 240 | name, priority, new_priority); | ||
| 241 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | ||
| 242 | // validity of this | ||
| 243 | priority = new_priority; | ||
| 244 | } | ||
| 245 | if (!Memory::GetPointer(entry_point)) { | ||
| 246 | ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid entry %08x", name, entry_point); | ||
| 247 | return -1; | ||
| 248 | } | ||
| 249 | Handle handle; | ||
| 250 | Thread *t = __KernelCreateThread(handle, name, entry_point, priority, processor_id, stack_top, | ||
| 251 | stack_size); | ||
| 252 | |||
| 253 | HLE::EatCycles(32000); | ||
| 254 | |||
| 255 | // This won't schedule to the new thread, but it may to one woken from eating cycles. | ||
| 256 | // Technically, this should not eat all at once, and reschedule in the middle, but that's hard. | ||
| 257 | HLE::ReSchedule("thread created"); | ||
| 258 | |||
| 259 | __KernelCallThread(t); | ||
| 260 | |||
| 261 | return handle; | ||
| 262 | } | ||
| 263 | |||
| 225 | /// Switches CPU context to that of the specified thread | 264 | /// Switches CPU context to that of the specified thread |
| 226 | void __KernelSwitchContext(Thread* t, const char *reason) { | 265 | void __KernelSwitchContext(Thread* t, const char *reason) { |
| 227 | Thread *cur = __GetCurrentThread(); | 266 | Thread *cur = __GetCurrentThread(); |
| @@ -262,22 +301,13 @@ Thread *__KernelNextThread() { | |||
| 262 | return g_kernel_objects.GetFast<Thread>(next); | 301 | return g_kernel_objects.GetFast<Thread>(next); |
| 263 | } | 302 | } |
| 264 | 303 | ||
| 265 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) | ||
| 266 | void __KernelCallThread(Thread *t) { | ||
| 267 | // Stop waiting | ||
| 268 | if (t->wait_type != WAITTYPE_NONE) { | ||
| 269 | t->wait_type = WAITTYPE_NONE; | ||
| 270 | } | ||
| 271 | __KernelChangeThreadState(t, THREADSTATUS_READY); | ||
| 272 | } | ||
| 273 | |||
| 274 | /// Sets up the primary application thread | 304 | /// Sets up the primary application thread |
| 275 | Handle __KernelSetupMainThread(s32 priority, int stack_size) { | 305 | Handle __KernelSetupMainThread(s32 priority, int stack_size) { |
| 276 | Handle handle; | 306 | Handle handle; |
| 277 | 307 | ||
| 278 | // Initialize new "main" thread | 308 | // Initialize new "main" thread |
| 279 | Thread *t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority, | 309 | Thread *t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority, |
| 280 | 0xFFFFFFFE, Memory::SCRATCHPAD_VADDR_END, stack_size); | 310 | THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); |
| 281 | 311 | ||
| 282 | __KernelResetThread(t, 0); | 312 | __KernelResetThread(t, 0); |
| 283 | 313 | ||
| @@ -322,6 +352,15 @@ void __KernelReschedule(const char *reason) { | |||
| 322 | } | 352 | } |
| 323 | } | 353 | } |
| 324 | 354 | ||
| 355 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 356 | |||
| 357 | /// Wait thread - on WaitSynchronization | ||
| 358 | void __KernelWaitThread_Synchronization() { | ||
| 359 | // TODO(bunnei): Just a placeholder function for now... FixMe | ||
| 360 | __KernelWaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called"); | ||
| 361 | } | ||
| 362 | |||
| 363 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 325 | 364 | ||
| 326 | void __KernelThreadingInit() { | 365 | void __KernelThreadingInit() { |
| 327 | } | 366 | } |