diff options
| author | 2015-01-09 12:59:35 -0500 | |
|---|---|---|
| committer | 2015-01-09 12:59:35 -0500 | |
| commit | 6ae12424df58f0ea171fc75ca4b700ab1fffc192 (patch) | |
| tree | 93d87f3cb19d08541c6b8f8a9e0ceb730a2b13d9 | |
| parent | Merge pull request #436 from kevinhartman/system-core (diff) | |
| parent | Thread: Fix nullptr access in a logging function (diff) | |
| download | yuzu-6ae12424df58f0ea171fc75ca4b700ab1fffc192.tar.gz yuzu-6ae12424df58f0ea171fc75ca4b700ab1fffc192.tar.xz yuzu-6ae12424df58f0ea171fc75ca4b700ab1fffc192.zip | |
Merge pull request #444 from yuriks/handle-reform2
Kernel Lifetime Reform Pt. 2
25 files changed, 330 insertions, 374 deletions
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 8db73752f..da084ab24 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "core/core.h" | 13 | #include "core/core.h" |
| 14 | #include "common/break_points.h" | 14 | #include "common/break_points.h" |
| 15 | #include "common/symbols.h" | 15 | #include "common/symbols.h" |
| 16 | #include "core/arm/arm_interface.h" | ||
| 16 | #include "core/arm/skyeye_common/armdefs.h" | 17 | #include "core/arm/skyeye_common/armdefs.h" |
| 17 | #include "core/arm/disassembler/arm_disasm.h" | 18 | #include "core/arm/disassembler/arm_disasm.h" |
| 18 | 19 | ||
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index d3bd4a9a3..e612f7439 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -7,7 +7,9 @@ | |||
| 7 | #include "common/common.h" | 7 | #include "common/common.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | 9 | ||
| 10 | #include "core/hle/svc.h" | 10 | namespace Core { |
| 11 | struct ThreadContext; | ||
| 12 | } | ||
| 11 | 13 | ||
| 12 | /// Generic ARM11 CPU interface | 14 | /// Generic ARM11 CPU interface |
| 13 | class ARM_Interface : NonCopyable { | 15 | class ARM_Interface : NonCopyable { |
| @@ -87,13 +89,13 @@ public: | |||
| 87 | * Saves the current CPU context | 89 | * Saves the current CPU context |
| 88 | * @param ctx Thread context to save | 90 | * @param ctx Thread context to save |
| 89 | */ | 91 | */ |
| 90 | virtual void SaveContext(ThreadContext& ctx) = 0; | 92 | virtual void SaveContext(Core::ThreadContext& ctx) = 0; |
| 91 | 93 | ||
| 92 | /** | 94 | /** |
| 93 | * Loads a CPU context | 95 | * Loads a CPU context |
| 94 | * @param ctx Thread context to load | 96 | * @param ctx Thread context to load |
| 95 | */ | 97 | */ |
| 96 | virtual void LoadContext(const ThreadContext& ctx) = 0; | 98 | virtual void LoadContext(const Core::ThreadContext& ctx) = 0; |
| 97 | 99 | ||
| 98 | /// Prepare core for thread reschedule (if needed to correctly handle state) | 100 | /// Prepare core for thread reschedule (if needed to correctly handle state) |
| 99 | virtual void PrepareReschedule() = 0; | 101 | virtual void PrepareReschedule() = 0; |
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 31eb879a2..9c4cc90f2 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/arm/dyncom/arm_dyncom.h" | 9 | #include "core/arm/dyncom/arm_dyncom.h" |
| 10 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | 10 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" |
| 11 | 11 | ||
| 12 | #include "core/core.h" | ||
| 12 | #include "core/core_timing.h" | 13 | #include "core/core_timing.h" |
| 13 | 14 | ||
| 14 | const static cpu_config_t s_arm11_cpu_info = { | 15 | const static cpu_config_t s_arm11_cpu_info = { |
| @@ -94,7 +95,7 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) { | |||
| 94 | AddTicks(ticks_executed); | 95 | AddTicks(ticks_executed); |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | void ARM_DynCom::SaveContext(ThreadContext& ctx) { | 98 | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { |
| 98 | memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); | 99 | memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); |
| 99 | memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); | 100 | memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); |
| 100 | 101 | ||
| @@ -110,7 +111,7 @@ void ARM_DynCom::SaveContext(ThreadContext& ctx) { | |||
| 110 | ctx.mode = state->NextInstr; | 111 | ctx.mode = state->NextInstr; |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | void ARM_DynCom::LoadContext(const ThreadContext& ctx) { | 114 | void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { |
| 114 | memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); | 115 | memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); |
| 115 | memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); | 116 | memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); |
| 116 | 117 | ||
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 9e102a46e..f16fb070c 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h | |||
| @@ -71,13 +71,13 @@ public: | |||
| 71 | * Saves the current CPU context | 71 | * Saves the current CPU context |
| 72 | * @param ctx Thread context to save | 72 | * @param ctx Thread context to save |
| 73 | */ | 73 | */ |
| 74 | void SaveContext(ThreadContext& ctx) override; | 74 | void SaveContext(Core::ThreadContext& ctx) override; |
| 75 | 75 | ||
| 76 | /** | 76 | /** |
| 77 | * Loads a CPU context | 77 | * Loads a CPU context |
| 78 | * @param ctx Thread context to load | 78 | * @param ctx Thread context to load |
| 79 | */ | 79 | */ |
| 80 | void LoadContext(const ThreadContext& ctx) override; | 80 | void LoadContext(const Core::ThreadContext& ctx) override; |
| 81 | 81 | ||
| 82 | /// Prepare core for thread reschedule (if needed to correctly handle state) | 82 | /// Prepare core for thread reschedule (if needed to correctly handle state) |
| 83 | void PrepareReschedule() override; | 83 | void PrepareReschedule() override; |
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp index 80ebc359e..c76d371a2 100644 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ b/src/core/arm/interpreter/arm_interpreter.cpp | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #include "core/arm/interpreter/arm_interpreter.h" | 5 | #include "core/arm/interpreter/arm_interpreter.h" |
| 6 | 6 | ||
| 7 | #include "core/core.h" | ||
| 8 | |||
| 7 | const static cpu_config_t arm11_cpu_info = { | 9 | const static cpu_config_t arm11_cpu_info = { |
| 8 | "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE | 10 | "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE |
| 9 | }; | 11 | }; |
| @@ -75,7 +77,7 @@ void ARM_Interpreter::ExecuteInstructions(int num_instructions) { | |||
| 75 | ARMul_Emulate32(state); | 77 | ARMul_Emulate32(state); |
| 76 | } | 78 | } |
| 77 | 79 | ||
| 78 | void ARM_Interpreter::SaveContext(ThreadContext& ctx) { | 80 | void ARM_Interpreter::SaveContext(Core::ThreadContext& ctx) { |
| 79 | memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); | 81 | memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); |
| 80 | memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); | 82 | memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); |
| 81 | 83 | ||
| @@ -91,7 +93,7 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) { | |||
| 91 | ctx.mode = state->NextInstr; | 93 | ctx.mode = state->NextInstr; |
| 92 | } | 94 | } |
| 93 | 95 | ||
| 94 | void ARM_Interpreter::LoadContext(const ThreadContext& ctx) { | 96 | void ARM_Interpreter::LoadContext(const Core::ThreadContext& ctx) { |
| 95 | memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); | 97 | memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); |
| 96 | memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); | 98 | memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); |
| 97 | 99 | ||
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h index 019dad5df..e5ecc69c2 100644 --- a/src/core/arm/interpreter/arm_interpreter.h +++ b/src/core/arm/interpreter/arm_interpreter.h | |||
| @@ -70,13 +70,13 @@ public: | |||
| 70 | * Saves the current CPU context | 70 | * Saves the current CPU context |
| 71 | * @param ctx Thread context to save | 71 | * @param ctx Thread context to save |
| 72 | */ | 72 | */ |
| 73 | void SaveContext(ThreadContext& ctx) override; | 73 | void SaveContext(Core::ThreadContext& ctx) override; |
| 74 | 74 | ||
| 75 | /** | 75 | /** |
| 76 | * Loads a CPU context | 76 | * Loads a CPU context |
| 77 | * @param ctx Thread context to load | 77 | * @param ctx Thread context to load |
| 78 | */ | 78 | */ |
| 79 | void LoadContext(const ThreadContext& ctx) override; | 79 | void LoadContext(const Core::ThreadContext& ctx) override; |
| 80 | 80 | ||
| 81 | /// Prepare core for thread reschedule (if needed to correctly handle state) | 81 | /// Prepare core for thread reschedule (if needed to correctly handle state) |
| 82 | void PrepareReschedule() override; | 82 | void PrepareReschedule() override; |
diff --git a/src/core/core.cpp b/src/core/core.cpp index ff506d67d..e9e5c35cc 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | 9 | ||
| 10 | #include "core/settings.h" | 10 | #include "core/settings.h" |
| 11 | #include "core/arm/arm_interface.h" | ||
| 11 | #include "core/arm/disassembler/arm_disasm.h" | 12 | #include "core/arm/disassembler/arm_disasm.h" |
| 12 | #include "core/arm/interpreter/arm_interpreter.h" | 13 | #include "core/arm/interpreter/arm_interpreter.h" |
| 13 | #include "core/arm/dyncom/arm_dyncom.h" | 14 | #include "core/arm/dyncom/arm_dyncom.h" |
| @@ -24,7 +25,7 @@ ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core | |||
| 24 | void RunLoop(int tight_loop) { | 25 | void RunLoop(int tight_loop) { |
| 25 | // If the current thread is an idle thread, then don't execute instructions, | 26 | // If the current thread is an idle thread, then don't execute instructions, |
| 26 | // instead advance to the next event and try to yield to the next thread | 27 | // instead advance to the next event and try to yield to the next thread |
| 27 | if (Kernel::IsIdleThread(Kernel::GetCurrentThreadHandle())) { | 28 | if (Kernel::GetCurrentThread()->IsIdle()) { |
| 28 | LOG_TRACE(Core_ARM11, "Idling"); | 29 | LOG_TRACE(Core_ARM11, "Idling"); |
| 29 | CoreTiming::Idle(); | 30 | CoreTiming::Idle(); |
| 30 | CoreTiming::Advance(); | 31 | CoreTiming::Advance(); |
diff --git a/src/core/core.h b/src/core/core.h index ecd58a73a..2f5e8bc6b 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -4,8 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/arm/arm_interface.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/arm/skyeye_common/armdefs.h" | 8 | |
| 9 | class ARM_Interface; | ||
| 9 | 10 | ||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 11 | 12 | ||
| @@ -16,6 +17,21 @@ enum CPUCore { | |||
| 16 | CPU_OldInterpreter, | 17 | CPU_OldInterpreter, |
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| 20 | struct ThreadContext { | ||
| 21 | u32 cpu_registers[13]; | ||
| 22 | u32 sp; | ||
| 23 | u32 lr; | ||
| 24 | u32 pc; | ||
| 25 | u32 cpsr; | ||
| 26 | u32 fpu_registers[32]; | ||
| 27 | u32 fpscr; | ||
| 28 | u32 fpexc; | ||
| 29 | |||
| 30 | // These are not part of native ThreadContext, but needed by emu | ||
| 31 | u32 reg_15; | ||
| 32 | u32 mode; | ||
| 33 | }; | ||
| 34 | |||
| 19 | extern ARM_Interface* g_app_core; ///< ARM11 application core | 35 | extern ARM_Interface* g_app_core; ///< ARM11 application core |
| 20 | extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core | 36 | extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core |
| 21 | 37 | ||
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 833199680..ec9d52a08 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/chunk_file.h" | 10 | #include "common/chunk_file.h" |
| 11 | #include "common/log.h" | 11 | #include "common/log.h" |
| 12 | |||
| 13 | #include "core/arm/arm_interface.h" | ||
| 12 | #include "core/core.h" | 14 | #include "core/core.h" |
| 13 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 14 | 16 | ||
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 8eb4f252b..a2f51b41b 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | |||
| 9 | #include "core/arm/arm_interface.h" | ||
| 8 | #include "core/mem_map.h" | 10 | #include "core/mem_map.h" |
| 9 | #include "core/hle/hle.h" | 11 | #include "core/hle/hle.h" |
| 10 | 12 | ||
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 33ac12507..5d77a1458 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | 6 | ||
| 7 | #include "core/arm/arm_interface.h" | ||
| 7 | #include "core/mem_map.h" | 8 | #include "core/mem_map.h" |
| 8 | #include "core/hle/hle.h" | 9 | #include "core/hle/hle.h" |
| 9 | #include "core/hle/kernel/thread.h" | 10 | #include "core/hle/kernel/thread.h" |
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h index 59b770f02..3f6f9a4b5 100644 --- a/src/core/hle/hle.h +++ b/src/core/hle/hle.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | #include "core/core.h" | 10 | #include "core/core.h" |
| 9 | 11 | ||
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 736bbc36a..28adc5500 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -30,24 +30,28 @@ public: | |||
| 30 | 30 | ||
| 31 | /// Arbitrate an address | 31 | /// Arbitrate an address |
| 32 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { | 32 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { |
| 33 | Object* object = Kernel::g_handle_table.GetGeneric(handle); | ||
| 34 | if (object == nullptr) | ||
| 35 | return InvalidHandle(ErrorModule::Kernel); | ||
| 36 | |||
| 33 | switch (type) { | 37 | switch (type) { |
| 34 | 38 | ||
| 35 | // Signal thread(s) waiting for arbitrate address... | 39 | // Signal thread(s) waiting for arbitrate address... |
| 36 | case ArbitrationType::Signal: | 40 | case ArbitrationType::Signal: |
| 37 | // Negative value means resume all threads | 41 | // Negative value means resume all threads |
| 38 | if (value < 0) { | 42 | if (value < 0) { |
| 39 | ArbitrateAllThreads(handle, address); | 43 | ArbitrateAllThreads(object, address); |
| 40 | } else { | 44 | } else { |
| 41 | // Resume first N threads | 45 | // Resume first N threads |
| 42 | for(int i = 0; i < value; i++) | 46 | for(int i = 0; i < value; i++) |
| 43 | ArbitrateHighestPriorityThread(handle, address); | 47 | ArbitrateHighestPriorityThread(object, address); |
| 44 | } | 48 | } |
| 45 | break; | 49 | break; |
| 46 | 50 | ||
| 47 | // Wait current thread (acquire the arbiter)... | 51 | // Wait current thread (acquire the arbiter)... |
| 48 | case ArbitrationType::WaitIfLessThan: | 52 | case ArbitrationType::WaitIfLessThan: |
| 49 | if ((s32)Memory::Read32(address) <= value) { | 53 | if ((s32)Memory::Read32(address) <= value) { |
| 50 | Kernel::WaitCurrentThread(WAITTYPE_ARB, handle, address); | 54 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); |
| 51 | HLE::Reschedule(__func__); | 55 | HLE::Reschedule(__func__); |
| 52 | } | 56 | } |
| 53 | break; | 57 | break; |
| @@ -57,7 +61,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | |||
| 57 | s32 memory_value = Memory::Read32(address) - 1; | 61 | s32 memory_value = Memory::Read32(address) - 1; |
| 58 | Memory::Write32(address, memory_value); | 62 | Memory::Write32(address, memory_value); |
| 59 | if (memory_value <= value) { | 63 | if (memory_value <= value) { |
| 60 | Kernel::WaitCurrentThread(WAITTYPE_ARB, handle, address); | 64 | Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); |
| 61 | HLE::Reschedule(__func__); | 65 | HLE::Reschedule(__func__); |
| 62 | } | 66 | } |
| 63 | break; | 67 | break; |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index e43c3ee4e..697e08681 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -33,11 +33,11 @@ public: | |||
| 33 | ResultVal<bool> WaitSynchronization() override { | 33 | ResultVal<bool> WaitSynchronization() override { |
| 34 | bool wait = locked; | 34 | bool wait = locked; |
| 35 | if (locked) { | 35 | if (locked) { |
| 36 | Handle thread = GetCurrentThreadHandle(); | 36 | Handle thread = GetCurrentThread()->GetHandle(); |
| 37 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | 37 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { |
| 38 | waiting_threads.push_back(thread); | 38 | waiting_threads.push_back(thread); |
| 39 | } | 39 | } |
| 40 | Kernel::WaitCurrentThread(WAITTYPE_EVENT, GetHandle()); | 40 | Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); |
| 41 | } | 41 | } |
| 42 | if (reset_type != RESETTYPE_STICKY && !permanent_locked) { | 42 | if (reset_type != RESETTYPE_STICKY && !permanent_locked) { |
| 43 | locked = true; | 43 | locked = true; |
| @@ -88,7 +88,9 @@ ResultCode SignalEvent(const Handle handle) { | |||
| 88 | // Resume threads waiting for event to signal | 88 | // Resume threads waiting for event to signal |
| 89 | bool event_caught = false; | 89 | bool event_caught = false; |
| 90 | for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { | 90 | for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { |
| 91 | ResumeThreadFromWait( evt->waiting_threads[i]); | 91 | Thread* thread = Kernel::g_handle_table.Get<Thread>(evt->waiting_threads[i]); |
| 92 | if (thread != nullptr) | ||
| 93 | thread->ResumeFromWait(); | ||
| 92 | 94 | ||
| 93 | // If any thread is signalled awake by this event, assume the event was "caught" and reset | 95 | // If any thread is signalled awake by this event, assume the event was "caught" and reset |
| 94 | // the event. This will result in the next thread waiting on the event to block. Otherwise, | 96 | // the event. This will result in the next thread waiting on the event to block. Otherwise, |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 391e833c0..a1bc6c5d8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common.h" | 7 | #include "common/common.h" |
| 8 | 8 | ||
| 9 | #include "core/arm/arm_interface.h" | ||
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| @@ -13,7 +14,7 @@ | |||
| 13 | 14 | ||
| 14 | namespace Kernel { | 15 | namespace Kernel { |
| 15 | 16 | ||
| 16 | Handle g_main_thread = 0; | 17 | Thread* g_main_thread = nullptr; |
| 17 | HandleTable g_handle_table; | 18 | HandleTable g_handle_table; |
| 18 | u64 g_program_id = 0; | 19 | u64 g_program_id = 0; |
| 19 | 20 | ||
| @@ -80,8 +81,7 @@ bool HandleTable::IsValid(Handle handle) const { | |||
| 80 | 81 | ||
| 81 | Object* HandleTable::GetGeneric(Handle handle) const { | 82 | Object* HandleTable::GetGeneric(Handle handle) const { |
| 82 | if (handle == CurrentThread) { | 83 | if (handle == CurrentThread) { |
| 83 | // TODO(yuriks) Directly return the pointer once this is possible. | 84 | return GetCurrentThread(); |
| 84 | handle = GetCurrentThreadHandle(); | ||
| 85 | } else if (handle == CurrentProcess) { | 85 | } else if (handle == CurrentProcess) { |
| 86 | LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess); | 86 | LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess); |
| 87 | return nullptr; | 87 | return nullptr; |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3e381d776..31d80c7ac 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -16,6 +16,8 @@ const Handle INVALID_HANDLE = 0; | |||
| 16 | 16 | ||
| 17 | namespace Kernel { | 17 | namespace Kernel { |
| 18 | 18 | ||
| 19 | class Thread; | ||
| 20 | |||
| 19 | // TODO: Verify code | 21 | // TODO: Verify code |
| 20 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | 22 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, |
| 21 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); | 23 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); |
| @@ -190,7 +192,7 @@ private: | |||
| 190 | }; | 192 | }; |
| 191 | 193 | ||
| 192 | extern HandleTable g_handle_table; | 194 | extern HandleTable g_handle_table; |
| 193 | extern Handle g_main_thread; | 195 | extern Thread* g_main_thread; |
| 194 | 196 | ||
| 195 | /// The ID code of the currently running game | 197 | /// The ID code of the currently running game |
| 196 | /// TODO(Subv): This variable should not be here, | 198 | /// TODO(Subv): This variable should not be here, |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 3dfeffc9b..7d008f6cc 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -40,14 +40,21 @@ static MutexMap g_mutex_held_locks; | |||
| 40 | * @param mutex Mutex that is to be acquired | 40 | * @param mutex Mutex that is to be acquired |
| 41 | * @param thread Thread that will acquired | 41 | * @param thread Thread that will acquired |
| 42 | */ | 42 | */ |
| 43 | void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThreadHandle()) { | 43 | void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandle()) { |
| 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); | 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); |
| 45 | mutex->lock_thread = thread; | 45 | mutex->lock_thread = thread; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | bool ReleaseMutexForThread(Mutex* mutex, Handle thread) { | 48 | bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { |
| 49 | MutexAcquireLock(mutex, thread); | 49 | MutexAcquireLock(mutex, thread_handle); |
| 50 | Kernel::ResumeThreadFromWait(thread); | 50 | |
| 51 | Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle); | ||
| 52 | if (thread == nullptr) { | ||
| 53 | LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | thread->ResumeFromWait(); | ||
| 51 | return true; | 58 | return true; |
| 52 | } | 59 | } |
| 53 | 60 | ||
| @@ -168,8 +175,8 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { | |||
| 168 | ResultVal<bool> Mutex::WaitSynchronization() { | 175 | ResultVal<bool> Mutex::WaitSynchronization() { |
| 169 | bool wait = locked; | 176 | bool wait = locked; |
| 170 | if (locked) { | 177 | if (locked) { |
| 171 | waiting_threads.push_back(GetCurrentThreadHandle()); | 178 | waiting_threads.push_back(GetCurrentThread()->GetHandle()); |
| 172 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); | 179 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); |
| 173 | } else { | 180 | } else { |
| 174 | // Lock the mutex when the first thread accesses it | 181 | // Lock the mutex when the first thread accesses it |
| 175 | locked = true; | 182 | locked = true; |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 6bc8066a6..d7eeaa3da 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -37,8 +37,8 @@ public: | |||
| 37 | bool wait = !IsAvailable(); | 37 | bool wait = !IsAvailable(); |
| 38 | 38 | ||
| 39 | if (wait) { | 39 | if (wait) { |
| 40 | Kernel::WaitCurrentThread(WAITTYPE_SEMA, GetHandle()); | 40 | Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); |
| 41 | waiting_threads.push(GetCurrentThreadHandle()); | 41 | waiting_threads.push(GetCurrentThread()->GetHandle()); |
| 42 | } else { | 42 | } else { |
| 43 | --available_count; | 43 | --available_count; |
| 44 | } | 44 | } |
| @@ -84,7 +84,9 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | |||
| 84 | // Notify some of the threads that the semaphore has been released | 84 | // Notify some of the threads that the semaphore has been released |
| 85 | // stop once the semaphore is full again or there are no more waiting threads | 85 | // stop once the semaphore is full again or there are no more waiting threads |
| 86 | while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { | 86 | while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { |
| 87 | Kernel::ResumeThreadFromWait(semaphore->waiting_threads.front()); | 87 | Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()); |
| 88 | if (thread != nullptr) | ||
| 89 | thread->ResumeFromWait(); | ||
| 88 | semaphore->waiting_threads.pop(); | 90 | semaphore->waiting_threads.pop(); |
| 89 | --semaphore->available_count; | 91 | --semaphore->available_count; |
| 90 | } | 92 | } |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 954bd09a0..0ae1a21df 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/common.h" | 10 | #include "common/common.h" |
| 11 | #include "common/thread_queue_list.h" | 11 | #include "common/thread_queue_list.h" |
| 12 | 12 | ||
| 13 | #include "core/arm/arm_interface.h" | ||
| 13 | #include "core/core.h" | 14 | #include "core/core.h" |
| 14 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 15 | #include "core/hle/hle.h" | 16 | #include "core/hle/hle.h" |
| @@ -21,68 +22,25 @@ | |||
| 21 | 22 | ||
| 22 | namespace Kernel { | 23 | namespace Kernel { |
| 23 | 24 | ||
| 24 | class Thread : public Kernel::Object { | 25 | ResultVal<bool> Thread::WaitSynchronization() { |
| 25 | public: | 26 | const bool wait = status != THREADSTATUS_DORMANT; |
| 26 | 27 | if (wait) { | |
| 27 | std::string GetName() const override { return name; } | 28 | Thread* thread = GetCurrentThread(); |
| 28 | std::string GetTypeName() const override { return "Thread"; } | 29 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { |
| 29 | 30 | waiting_threads.push_back(thread); | |
| 30 | static const HandleType HANDLE_TYPE = HandleType::Thread; | ||
| 31 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 32 | |||
| 33 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } | ||
| 34 | inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } | ||
| 35 | inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; } | ||
| 36 | inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } | ||
| 37 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | ||
| 38 | inline bool IsIdle() const { return idle; } | ||
| 39 | |||
| 40 | ResultVal<bool> WaitSynchronization() override { | ||
| 41 | const bool wait = status != THREADSTATUS_DORMANT; | ||
| 42 | if (wait) { | ||
| 43 | Handle thread = GetCurrentThreadHandle(); | ||
| 44 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||
| 45 | waiting_threads.push_back(thread); | ||
| 46 | } | ||
| 47 | WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); | ||
| 48 | } | 31 | } |
| 49 | 32 | WaitCurrentThread(WAITTYPE_THREADEND, this); | |
| 50 | return MakeResult<bool>(wait); | ||
| 51 | } | 33 | } |
| 52 | 34 | ||
| 53 | ThreadContext context; | 35 | return MakeResult<bool>(wait); |
| 54 | 36 | } | |
| 55 | u32 thread_id; | ||
| 56 | |||
| 57 | u32 status; | ||
| 58 | u32 entry_point; | ||
| 59 | u32 stack_top; | ||
| 60 | u32 stack_size; | ||
| 61 | |||
| 62 | s32 initial_priority; | ||
| 63 | s32 current_priority; | ||
| 64 | |||
| 65 | s32 processor_id; | ||
| 66 | |||
| 67 | WaitType wait_type; | ||
| 68 | Handle wait_handle; | ||
| 69 | VAddr wait_address; | ||
| 70 | |||
| 71 | std::vector<Handle> waiting_threads; | ||
| 72 | |||
| 73 | std::string name; | ||
| 74 | |||
| 75 | /// Whether this thread is intended to never actually be executed, i.e. always idle | ||
| 76 | bool idle = false; | ||
| 77 | }; | ||
| 78 | 37 | ||
| 79 | // Lists all thread ids that aren't deleted/etc. | 38 | // Lists all thread ids that aren't deleted/etc. |
| 80 | static std::vector<Handle> thread_queue; | 39 | static std::vector<Thread*> thread_list; // TODO(yuriks): Owned |
| 81 | 40 | ||
| 82 | // Lists only ready thread ids. | 41 | // Lists only ready thread ids. |
| 83 | static Common::ThreadQueueList<Handle, THREADPRIO_LOWEST+1> thread_ready_queue; | 42 | static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> thread_ready_queue; |
| 84 | 43 | ||
| 85 | static Handle current_thread_handle; | ||
| 86 | static Thread* current_thread; | 44 | static Thread* current_thread; |
| 87 | 45 | ||
| 88 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup | 46 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup |
| @@ -92,30 +50,9 @@ Thread* GetCurrentThread() { | |||
| 92 | return current_thread; | 50 | return current_thread; |
| 93 | } | 51 | } |
| 94 | 52 | ||
| 95 | /// Gets the current thread handle | ||
| 96 | Handle GetCurrentThreadHandle() { | ||
| 97 | return GetCurrentThread()->GetHandle(); | ||
| 98 | } | ||
| 99 | |||
| 100 | /// Sets the current thread | ||
| 101 | inline void SetCurrentThread(Thread* t) { | ||
| 102 | current_thread = t; | ||
| 103 | current_thread_handle = t->GetHandle(); | ||
| 104 | } | ||
| 105 | |||
| 106 | /// Saves the current CPU context | ||
| 107 | void SaveContext(ThreadContext& ctx) { | ||
| 108 | Core::g_app_core->SaveContext(ctx); | ||
| 109 | } | ||
| 110 | |||
| 111 | /// Loads a CPU context | ||
| 112 | void LoadContext(ThreadContext& ctx) { | ||
| 113 | Core::g_app_core->LoadContext(ctx); | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Resets a thread | 53 | /// Resets a thread |
| 117 | void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { | 54 | static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { |
| 118 | memset(&t->context, 0, sizeof(ThreadContext)); | 55 | memset(&t->context, 0, sizeof(Core::ThreadContext)); |
| 119 | 56 | ||
| 120 | t->context.cpu_registers[0] = arg; | 57 | t->context.cpu_registers[0] = arg; |
| 121 | t->context.pc = t->context.reg_15 = t->entry_point; | 58 | t->context.pc = t->context.reg_15 = t->entry_point; |
| @@ -131,22 +68,21 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { | |||
| 131 | t->current_priority = t->initial_priority; | 68 | t->current_priority = t->initial_priority; |
| 132 | } | 69 | } |
| 133 | t->wait_type = WAITTYPE_NONE; | 70 | t->wait_type = WAITTYPE_NONE; |
| 134 | t->wait_handle = 0; | 71 | t->wait_object = nullptr; |
| 135 | t->wait_address = 0; | 72 | t->wait_address = 0; |
| 136 | } | 73 | } |
| 137 | 74 | ||
| 138 | /// Change a thread to "ready" state | 75 | /// Change a thread to "ready" state |
| 139 | void ChangeReadyState(Thread* t, bool ready) { | 76 | static void ChangeReadyState(Thread* t, bool ready) { |
| 140 | Handle handle = t->GetHandle(); | ||
| 141 | if (t->IsReady()) { | 77 | if (t->IsReady()) { |
| 142 | if (!ready) { | 78 | if (!ready) { |
| 143 | thread_ready_queue.remove(t->current_priority, handle); | 79 | thread_ready_queue.remove(t->current_priority, t); |
| 144 | } | 80 | } |
| 145 | } else if (ready) { | 81 | } else if (ready) { |
| 146 | if (t->IsRunning()) { | 82 | if (t->IsRunning()) { |
| 147 | thread_ready_queue.push_front(t->current_priority, handle); | 83 | thread_ready_queue.push_front(t->current_priority, t); |
| 148 | } else { | 84 | } else { |
| 149 | thread_ready_queue.push_back(t->current_priority, handle); | 85 | thread_ready_queue.push_back(t->current_priority, t); |
| 150 | } | 86 | } |
| 151 | t->status = THREADSTATUS_READY; | 87 | t->status = THREADSTATUS_READY; |
| 152 | } | 88 | } |
| @@ -158,43 +94,36 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { | |||
| 158 | } | 94 | } |
| 159 | 95 | ||
| 160 | /// Check if a thread is blocking on a specified wait type with a specified handle | 96 | /// Check if a thread is blocking on a specified wait type with a specified handle |
| 161 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) { | 97 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { |
| 162 | return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle); | 98 | return CheckWaitType(thread, type) && wait_object == thread->wait_object; |
| 163 | } | 99 | } |
| 164 | 100 | ||
| 165 | /// Check if a thread is blocking on a specified wait type with a specified handle and address | 101 | /// Check if a thread is blocking on a specified wait type with a specified handle and address |
| 166 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | 102 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object, VAddr wait_address) { |
| 167 | return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address); | 103 | return CheckWaitType(thread, type, wait_object) && (wait_address == thread->wait_address); |
| 168 | } | 104 | } |
| 169 | 105 | ||
| 170 | /// Stops the current thread | 106 | /// Stops the current thread |
| 171 | ResultCode StopThread(Handle handle, const char* reason) { | 107 | void Thread::Stop(const char* reason) { |
| 172 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 173 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 174 | |||
| 175 | // Release all the mutexes that this thread holds | 108 | // Release all the mutexes that this thread holds |
| 176 | ReleaseThreadMutexes(handle); | 109 | ReleaseThreadMutexes(GetHandle()); |
| 177 | |||
| 178 | ChangeReadyState(thread, false); | ||
| 179 | thread->status = THREADSTATUS_DORMANT; | ||
| 180 | for (Handle waiting_handle : thread->waiting_threads) { | ||
| 181 | Thread* waiting_thread = g_handle_table.Get<Thread>(waiting_handle); | ||
| 182 | 110 | ||
| 183 | if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle)) | 111 | ChangeReadyState(this, false); |
| 184 | ResumeThreadFromWait(waiting_handle); | 112 | status = THREADSTATUS_DORMANT; |
| 113 | for (Thread* waiting_thread : waiting_threads) { | ||
| 114 | if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, this)) | ||
| 115 | waiting_thread->ResumeFromWait(); | ||
| 185 | } | 116 | } |
| 186 | thread->waiting_threads.clear(); | 117 | waiting_threads.clear(); |
| 187 | 118 | ||
| 188 | // Stopped threads are never waiting. | 119 | // Stopped threads are never waiting. |
| 189 | thread->wait_type = WAITTYPE_NONE; | 120 | wait_type = WAITTYPE_NONE; |
| 190 | thread->wait_handle = 0; | 121 | wait_object = nullptr; |
| 191 | thread->wait_address = 0; | 122 | wait_address = 0; |
| 192 | |||
| 193 | return RESULT_SUCCESS; | ||
| 194 | } | 123 | } |
| 195 | 124 | ||
| 196 | /// Changes a threads state | 125 | /// Changes a threads state |
| 197 | void ChangeThreadState(Thread* t, ThreadStatus new_status) { | 126 | static void ChangeThreadState(Thread* t, ThreadStatus new_status) { |
| 198 | if (!t || t->status == new_status) { | 127 | if (!t || t->status == new_status) { |
| 199 | return; | 128 | return; |
| 200 | } | 129 | } |
| @@ -209,14 +138,12 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { | |||
| 209 | } | 138 | } |
| 210 | 139 | ||
| 211 | /// Arbitrate the highest priority thread that is waiting | 140 | /// Arbitrate the highest priority thread that is waiting |
| 212 | Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | 141 | Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { |
| 213 | Handle highest_priority_thread = 0; | 142 | Thread* highest_priority_thread = nullptr; |
| 214 | s32 priority = THREADPRIO_LOWEST; | 143 | s32 priority = THREADPRIO_LOWEST; |
| 215 | 144 | ||
| 216 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 145 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 217 | for (Handle handle : thread_queue) { | 146 | for (Thread* thread : thread_list) { |
| 218 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 219 | |||
| 220 | if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) | 147 | if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 221 | continue; | 148 | continue; |
| 222 | 149 | ||
| @@ -224,31 +151,31 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | |||
| 224 | continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. | 151 | continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. |
| 225 | 152 | ||
| 226 | if(thread->current_priority <= priority) { | 153 | if(thread->current_priority <= priority) { |
| 227 | highest_priority_thread = handle; | 154 | highest_priority_thread = thread; |
| 228 | priority = thread->current_priority; | 155 | priority = thread->current_priority; |
| 229 | } | 156 | } |
| 230 | } | 157 | } |
| 158 | |||
| 231 | // If a thread was arbitrated, resume it | 159 | // If a thread was arbitrated, resume it |
| 232 | if (0 != highest_priority_thread) | 160 | if (nullptr != highest_priority_thread) { |
| 233 | ResumeThreadFromWait(highest_priority_thread); | 161 | highest_priority_thread->ResumeFromWait(); |
| 162 | } | ||
| 234 | 163 | ||
| 235 | return highest_priority_thread; | 164 | return highest_priority_thread; |
| 236 | } | 165 | } |
| 237 | 166 | ||
| 238 | /// Arbitrate all threads currently waiting | 167 | /// Arbitrate all threads currently waiting |
| 239 | void ArbitrateAllThreads(u32 arbiter, u32 address) { | 168 | void ArbitrateAllThreads(Object* arbiter, u32 address) { |
| 240 | 169 | ||
| 241 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 170 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 242 | for (Handle handle : thread_queue) { | 171 | for (Thread* thread : thread_list) { |
| 243 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 244 | |||
| 245 | if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) | 172 | if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 246 | ResumeThreadFromWait(handle); | 173 | thread->ResumeFromWait(); |
| 247 | } | 174 | } |
| 248 | } | 175 | } |
| 249 | 176 | ||
| 250 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) | 177 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) |
| 251 | void CallThread(Thread* t) { | 178 | static void CallThread(Thread* t) { |
| 252 | // Stop waiting | 179 | // Stop waiting |
| 253 | if (t->wait_type != WAITTYPE_NONE) { | 180 | if (t->wait_type != WAITTYPE_NONE) { |
| 254 | t->wait_type = WAITTYPE_NONE; | 181 | t->wait_type = WAITTYPE_NONE; |
| @@ -257,12 +184,12 @@ void CallThread(Thread* t) { | |||
| 257 | } | 184 | } |
| 258 | 185 | ||
| 259 | /// Switches CPU context to that of the specified thread | 186 | /// Switches CPU context to that of the specified thread |
| 260 | void SwitchContext(Thread* t) { | 187 | static void SwitchContext(Thread* t) { |
| 261 | Thread* cur = GetCurrentThread(); | 188 | Thread* cur = GetCurrentThread(); |
| 262 | 189 | ||
| 263 | // Save context for current thread | 190 | // Save context for current thread |
| 264 | if (cur) { | 191 | if (cur) { |
| 265 | SaveContext(cur->context); | 192 | Core::g_app_core->SaveContext(cur->context); |
| 266 | 193 | ||
| 267 | if (cur->IsRunning()) { | 194 | if (cur->IsRunning()) { |
| 268 | ChangeReadyState(cur, true); | 195 | ChangeReadyState(cur, true); |
| @@ -270,19 +197,19 @@ void SwitchContext(Thread* t) { | |||
| 270 | } | 197 | } |
| 271 | // Load context of new thread | 198 | // Load context of new thread |
| 272 | if (t) { | 199 | if (t) { |
| 273 | SetCurrentThread(t); | 200 | current_thread = t; |
| 274 | ChangeReadyState(t, false); | 201 | ChangeReadyState(t, false); |
| 275 | t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; | 202 | t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; |
| 276 | t->wait_type = WAITTYPE_NONE; | 203 | t->wait_type = WAITTYPE_NONE; |
| 277 | LoadContext(t->context); | 204 | Core::g_app_core->LoadContext(t->context); |
| 278 | } else { | 205 | } else { |
| 279 | SetCurrentThread(nullptr); | 206 | current_thread = nullptr; |
| 280 | } | 207 | } |
| 281 | } | 208 | } |
| 282 | 209 | ||
| 283 | /// Gets the next thread that is ready to be run by priority | 210 | /// Gets the next thread that is ready to be run by priority |
| 284 | Thread* NextThread() { | 211 | static Thread* NextThread() { |
| 285 | Handle next; | 212 | Thread* next; |
| 286 | Thread* cur = GetCurrentThread(); | 213 | Thread* cur = GetCurrentThread(); |
| 287 | 214 | ||
| 288 | if (cur && cur->IsRunning()) { | 215 | if (cur && cur->IsRunning()) { |
| @@ -293,18 +220,18 @@ Thread* NextThread() { | |||
| 293 | if (next == 0) { | 220 | if (next == 0) { |
| 294 | return nullptr; | 221 | return nullptr; |
| 295 | } | 222 | } |
| 296 | return Kernel::g_handle_table.Get<Thread>(next); | 223 | return next; |
| 297 | } | 224 | } |
| 298 | 225 | ||
| 299 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { | 226 | void WaitCurrentThread(WaitType wait_type, Object* wait_object) { |
| 300 | Thread* thread = GetCurrentThread(); | 227 | Thread* thread = GetCurrentThread(); |
| 301 | thread->wait_type = wait_type; | 228 | thread->wait_type = wait_type; |
| 302 | thread->wait_handle = wait_handle; | 229 | thread->wait_object = wait_object; |
| 303 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | 230 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); |
| 304 | } | 231 | } |
| 305 | 232 | ||
| 306 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address) { | 233 | void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address) { |
| 307 | WaitCurrentThread(wait_type, wait_handle); | 234 | WaitCurrentThread(wait_type, wait_object); |
| 308 | GetCurrentThread()->wait_address = wait_address; | 235 | GetCurrentThread()->wait_address = wait_address; |
| 309 | } | 236 | } |
| 310 | 237 | ||
| @@ -320,67 +247,84 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { | |||
| 320 | return; | 247 | return; |
| 321 | } | 248 | } |
| 322 | 249 | ||
| 323 | Kernel::ResumeThreadFromWait(handle); | 250 | thread->ResumeFromWait(); |
| 324 | } | 251 | } |
| 325 | 252 | ||
| 326 | 253 | ||
| 327 | void WakeThreadAfterDelay(Handle handle, s64 nanoseconds) { | 254 | void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { |
| 328 | // Don't schedule a wakeup if the thread wants to wait forever | 255 | // Don't schedule a wakeup if the thread wants to wait forever |
| 329 | if (nanoseconds == -1) | 256 | if (nanoseconds == -1) |
| 330 | return; | 257 | return; |
| 331 | 258 | _dbg_assert_(Kernel, thread != nullptr); | |
| 332 | Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); | ||
| 333 | if (thread == nullptr) { | ||
| 334 | LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | 259 | ||
| 338 | u64 microseconds = nanoseconds / 1000; | 260 | u64 microseconds = nanoseconds / 1000; |
| 339 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, handle); | 261 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); |
| 340 | } | 262 | } |
| 341 | 263 | ||
| 342 | /// Resumes a thread from waiting by marking it as "ready" | 264 | /// Resumes a thread from waiting by marking it as "ready" |
| 343 | void ResumeThreadFromWait(Handle handle) { | 265 | void Thread::ResumeFromWait() { |
| 344 | Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); | 266 | status &= ~THREADSTATUS_WAIT; |
| 345 | if (thread) { | 267 | wait_object = nullptr; |
| 346 | thread->status &= ~THREADSTATUS_WAIT; | 268 | wait_type = WAITTYPE_NONE; |
| 347 | thread->wait_handle = 0; | 269 | if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 348 | thread->wait_type = WAITTYPE_NONE; | 270 | ChangeReadyState(this, true); |
| 349 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | ||
| 350 | ChangeReadyState(thread, true); | ||
| 351 | } | ||
| 352 | } | 271 | } |
| 353 | } | 272 | } |
| 354 | 273 | ||
| 355 | /// Prints the thread queue for debugging purposes | 274 | /// Prints the thread queue for debugging purposes |
| 356 | void DebugThreadQueue() { | 275 | static void DebugThreadQueue() { |
| 357 | Thread* thread = GetCurrentThread(); | 276 | Thread* thread = GetCurrentThread(); |
| 358 | if (!thread) { | 277 | if (!thread) { |
| 359 | return; | 278 | return; |
| 360 | } | 279 | } |
| 361 | LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); | 280 | LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle()); |
| 362 | for (u32 i = 0; i < thread_queue.size(); i++) { | 281 | for (Thread* t : thread_list) { |
| 363 | Handle handle = thread_queue[i]; | 282 | s32 priority = thread_ready_queue.contains(t); |
| 364 | s32 priority = thread_ready_queue.contains(handle); | ||
| 365 | if (priority != -1) { | 283 | if (priority != -1) { |
| 366 | LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, handle); | 284 | LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle()); |
| 367 | } | 285 | } |
| 368 | } | 286 | } |
| 369 | } | 287 | } |
| 370 | 288 | ||
| 371 | /// Creates a new thread | 289 | ResultVal<Thread*> Thread::Create(const char* name, u32 entry_point, s32 priority, u32 arg, |
| 372 | Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, | 290 | s32 processor_id, u32 stack_top, int stack_size) { |
| 373 | s32 processor_id, u32 stack_top, int stack_size) { | 291 | _dbg_assert_(Kernel, name != nullptr); |
| 292 | |||
| 293 | if ((u32)stack_size < 0x200) { | ||
| 294 | LOG_ERROR(Kernel, "(name=%s): invalid stack_size=0x%08X", name, stack_size); | ||
| 295 | // TODO: Verify error | ||
| 296 | return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Kernel, | ||
| 297 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 298 | } | ||
| 299 | |||
| 300 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | ||
| 301 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | ||
| 302 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", | ||
| 303 | name, priority, new_priority); | ||
| 304 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | ||
| 305 | // validity of this | ||
| 306 | priority = new_priority; | ||
| 307 | } | ||
| 374 | 308 | ||
| 375 | _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), | 309 | if (!Memory::GetPointer(entry_point)) { |
| 376 | "priority=%d, outside of allowable range!", priority) | 310 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name, entry_point); |
| 311 | // TODO: Verify error | ||
| 312 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||
| 313 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 314 | } | ||
| 377 | 315 | ||
| 378 | Thread* thread = new Thread; | 316 | Thread* thread = new Thread; |
| 379 | 317 | ||
| 380 | // TOOD(yuriks): Fix error reporting | 318 | // TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for |
| 381 | handle = Kernel::g_handle_table.Create(thread).ValueOr(INVALID_HANDLE); | 319 | // the time being. Create a handle here, it will be copied to the handle field in |
| 320 | // the object and use by the rest of the code. This should be removed when other | ||
| 321 | // code doesn't rely on the handle anymore. | ||
| 322 | ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread); | ||
| 323 | // TODO(yuriks): Plug memory leak | ||
| 324 | if (handle.Failed()) | ||
| 325 | return handle.Code(); | ||
| 382 | 326 | ||
| 383 | thread_queue.push_back(handle); | 327 | thread_list.push_back(thread); |
| 384 | thread_ready_queue.prepare(priority); | 328 | thread_ready_queue.prepare(priority); |
| 385 | 329 | ||
| 386 | thread->thread_id = next_thread_id++; | 330 | thread->thread_id = next_thread_id++; |
| @@ -391,69 +335,18 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio | |||
| 391 | thread->initial_priority = thread->current_priority = priority; | 335 | thread->initial_priority = thread->current_priority = priority; |
| 392 | thread->processor_id = processor_id; | 336 | thread->processor_id = processor_id; |
| 393 | thread->wait_type = WAITTYPE_NONE; | 337 | thread->wait_type = WAITTYPE_NONE; |
| 394 | thread->wait_handle = 0; | 338 | thread->wait_object = nullptr; |
| 395 | thread->wait_address = 0; | 339 | thread->wait_address = 0; |
| 396 | thread->name = name; | 340 | thread->name = name; |
| 397 | 341 | ||
| 398 | return thread; | ||
| 399 | } | ||
| 400 | |||
| 401 | /// Creates a new thread - wrapper for external user | ||
| 402 | Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, | ||
| 403 | u32 stack_top, int stack_size) { | ||
| 404 | |||
| 405 | if (name == nullptr) { | ||
| 406 | LOG_ERROR(Kernel_SVC, "nullptr name"); | ||
| 407 | return -1; | ||
| 408 | } | ||
| 409 | if ((u32)stack_size < 0x200) { | ||
| 410 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid stack_size=0x%08X", name, | ||
| 411 | stack_size); | ||
| 412 | return -1; | ||
| 413 | } | ||
| 414 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | ||
| 415 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | ||
| 416 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", | ||
| 417 | name, priority, new_priority); | ||
| 418 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | ||
| 419 | // validity of this | ||
| 420 | priority = new_priority; | ||
| 421 | } | ||
| 422 | if (!Memory::GetPointer(entry_point)) { | ||
| 423 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name, entry_point); | ||
| 424 | return -1; | ||
| 425 | } | ||
| 426 | Handle handle; | ||
| 427 | Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, | ||
| 428 | stack_size); | ||
| 429 | |||
| 430 | ResetThread(thread, arg, 0); | 342 | ResetThread(thread, arg, 0); |
| 431 | CallThread(thread); | 343 | CallThread(thread); |
| 432 | 344 | ||
| 433 | return handle; | 345 | return MakeResult<Thread*>(thread); |
| 434 | } | ||
| 435 | |||
| 436 | /// Get the priority of the thread specified by handle | ||
| 437 | ResultVal<u32> GetThreadPriority(const Handle handle) { | ||
| 438 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 439 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 440 | |||
| 441 | return MakeResult<u32>(thread->current_priority); | ||
| 442 | } | 346 | } |
| 443 | 347 | ||
| 444 | /// Set the priority of the thread specified by handle | 348 | /// Set the priority of the thread specified by handle |
| 445 | ResultCode SetThreadPriority(Handle handle, s32 priority) { | 349 | void Thread::SetPriority(s32 priority) { |
| 446 | Thread* thread = nullptr; | ||
| 447 | if (!handle) { | ||
| 448 | thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? | ||
| 449 | } else { | ||
| 450 | thread = g_handle_table.Get<Thread>(handle); | ||
| 451 | if (thread == nullptr) { | ||
| 452 | return InvalidHandle(ErrorModule::Kernel); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||
| 456 | |||
| 457 | // If priority is invalid, clamp to valid range | 350 | // If priority is invalid, clamp to valid range |
| 458 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | 351 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { |
| 459 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | 352 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); |
| @@ -464,38 +357,39 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) { | |||
| 464 | } | 357 | } |
| 465 | 358 | ||
| 466 | // Change thread priority | 359 | // Change thread priority |
| 467 | s32 old = thread->current_priority; | 360 | s32 old = current_priority; |
| 468 | thread_ready_queue.remove(old, handle); | 361 | thread_ready_queue.remove(old, this); |
| 469 | thread->current_priority = priority; | 362 | current_priority = priority; |
| 470 | thread_ready_queue.prepare(thread->current_priority); | 363 | thread_ready_queue.prepare(current_priority); |
| 471 | 364 | ||
| 472 | // Change thread status to "ready" and push to ready queue | 365 | // Change thread status to "ready" and push to ready queue |
| 473 | if (thread->IsRunning()) { | 366 | if (IsRunning()) { |
| 474 | thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; | 367 | status = (status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; |
| 475 | } | 368 | } |
| 476 | if (thread->IsReady()) { | 369 | if (IsReady()) { |
| 477 | thread_ready_queue.push_back(thread->current_priority, handle); | 370 | thread_ready_queue.push_back(current_priority, this); |
| 478 | } | 371 | } |
| 479 | |||
| 480 | return RESULT_SUCCESS; | ||
| 481 | } | 372 | } |
| 482 | 373 | ||
| 483 | Handle SetupIdleThread() { | 374 | Handle SetupIdleThread() { |
| 484 | Handle handle; | 375 | // We need to pass a few valid values to get around parameter checking in Thread::Create. |
| 485 | Thread* thread = CreateThread(handle, "idle", 0, THREADPRIO_LOWEST, THREADPROCESSORID_0, 0, 0); | 376 | auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, |
| 377 | THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE); | ||
| 378 | _dbg_assert_(Kernel, thread_res.Succeeded()); | ||
| 379 | Thread* thread = *thread_res; | ||
| 380 | |||
| 486 | thread->idle = true; | 381 | thread->idle = true; |
| 487 | CallThread(thread); | 382 | CallThread(thread); |
| 488 | return handle; | 383 | return thread->GetHandle(); |
| 489 | } | 384 | } |
| 490 | 385 | ||
| 491 | Handle SetupMainThread(s32 priority, int stack_size) { | 386 | Thread* SetupMainThread(s32 priority, int stack_size) { |
| 492 | Handle handle; | ||
| 493 | |||
| 494 | // Initialize new "main" thread | 387 | // Initialize new "main" thread |
| 495 | Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, | 388 | ResultVal<Thread*> thread_res = Thread::Create("main", Core::g_app_core->GetPC(), priority, 0, |
| 496 | THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); | 389 | THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); |
| 497 | 390 | // TODO(yuriks): Propagate error | |
| 498 | ResetThread(thread, 0, 0); | 391 | _dbg_assert_(Kernel, thread_res.Succeeded()); |
| 392 | Thread* thread = *thread_res; | ||
| 499 | 393 | ||
| 500 | // If running another thread already, set it to "ready" state | 394 | // If running another thread already, set it to "ready" state |
| 501 | Thread* cur = GetCurrentThread(); | 395 | Thread* cur = GetCurrentThread(); |
| @@ -504,11 +398,11 @@ Handle SetupMainThread(s32 priority, int stack_size) { | |||
| 504 | } | 398 | } |
| 505 | 399 | ||
| 506 | // Run new "main" thread | 400 | // Run new "main" thread |
| 507 | SetCurrentThread(thread); | 401 | current_thread = thread; |
| 508 | thread->status = THREADSTATUS_RUNNING; | 402 | thread->status = THREADSTATUS_RUNNING; |
| 509 | LoadContext(thread->context); | 403 | Core::g_app_core->LoadContext(thread->context); |
| 510 | 404 | ||
| 511 | return handle; | 405 | return thread; |
| 512 | } | 406 | } |
| 513 | 407 | ||
| 514 | 408 | ||
| @@ -524,34 +418,14 @@ void Reschedule() { | |||
| 524 | } else { | 418 | } else { |
| 525 | LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); | 419 | LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); |
| 526 | 420 | ||
| 527 | for (Handle handle : thread_queue) { | 421 | for (Thread* thread : thread_list) { |
| 528 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 529 | LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", | 422 | LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", |
| 530 | thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); | 423 | thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, |
| 424 | (thread->wait_object ? thread->wait_object->GetHandle() : INVALID_HANDLE)); | ||
| 531 | } | 425 | } |
| 532 | } | 426 | } |
| 533 | } | 427 | } |
| 534 | 428 | ||
| 535 | bool IsIdleThread(Handle handle) { | ||
| 536 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 537 | if (!thread) { | ||
| 538 | LOG_ERROR(Kernel, "Thread not found %u", handle); | ||
| 539 | return false; | ||
| 540 | } | ||
| 541 | return thread->IsIdle(); | ||
| 542 | } | ||
| 543 | |||
| 544 | ResultCode GetThreadId(u32* thread_id, Handle handle) { | ||
| 545 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 546 | if (thread == nullptr) | ||
| 547 | return ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS, | ||
| 548 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 549 | |||
| 550 | *thread_id = thread->thread_id; | ||
| 551 | |||
| 552 | return RESULT_SUCCESS; | ||
| 553 | } | ||
| 554 | |||
| 555 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 429 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 556 | 430 | ||
| 557 | void ThreadingInit() { | 431 | void ThreadingInit() { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 58bd85ac6..24450379c 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -4,8 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 12 | #include "core/core.h" | ||
| 9 | #include "core/mem_map.h" | 13 | #include "core/mem_map.h" |
| 10 | 14 | ||
| 11 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| @@ -48,69 +52,102 @@ enum WaitType { | |||
| 48 | 52 | ||
| 49 | namespace Kernel { | 53 | namespace Kernel { |
| 50 | 54 | ||
| 51 | /// Creates a new thread - wrapper for external user | 55 | class Thread : public Kernel::Object { |
| 52 | Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, | 56 | public: |
| 53 | u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE); | 57 | static ResultVal<Thread*> Create(const char* name, u32 entry_point, s32 priority, u32 arg, |
| 58 | s32 processor_id, u32 stack_top, int stack_size = Kernel::DEFAULT_STACK_SIZE); | ||
| 54 | 59 | ||
| 55 | /// Sets up the primary application thread | 60 | std::string GetName() const override { return name; } |
| 56 | Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); | 61 | std::string GetTypeName() const override { return "Thread"; } |
| 57 | 62 | ||
| 58 | /// Reschedules to the next available thread (call after current thread is suspended) | 63 | static const HandleType HANDLE_TYPE = HandleType::Thread; |
| 59 | void Reschedule(); | 64 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 60 | 65 | ||
| 61 | /// Stops the current thread | 66 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } |
| 62 | ResultCode StopThread(Handle thread, const char* reason); | 67 | inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } |
| 68 | inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; } | ||
| 69 | inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } | ||
| 70 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | ||
| 71 | inline bool IsIdle() const { return idle; } | ||
| 63 | 72 | ||
| 64 | /** | 73 | ResultVal<bool> WaitSynchronization() override; |
| 65 | * Retrieves the ID of the specified thread handle | 74 | |
| 66 | * @param thread_id Will contain the output thread id | 75 | s32 GetPriority() const { return current_priority; } |
| 67 | * @param handle Handle to the thread we want | 76 | void SetPriority(s32 priority); |
| 68 | * @return Whether the function was successful or not | 77 | |
| 69 | */ | 78 | u32 GetThreadId() const { return thread_id; } |
| 70 | ResultCode GetThreadId(u32* thread_id, Handle handle); | 79 | |
| 80 | void Stop(const char* reason); | ||
| 81 | /// Resumes a thread from waiting by marking it as "ready". | ||
| 82 | void ResumeFromWait(); | ||
| 83 | |||
| 84 | Core::ThreadContext context; | ||
| 85 | |||
| 86 | u32 thread_id; | ||
| 87 | |||
| 88 | u32 status; | ||
| 89 | u32 entry_point; | ||
| 90 | u32 stack_top; | ||
| 91 | u32 stack_size; | ||
| 92 | |||
| 93 | s32 initial_priority; | ||
| 94 | s32 current_priority; | ||
| 95 | |||
| 96 | s32 processor_id; | ||
| 71 | 97 | ||
| 72 | /// Resumes a thread from waiting by marking it as "ready" | 98 | WaitType wait_type; |
| 73 | void ResumeThreadFromWait(Handle handle); | 99 | Object* wait_object; |
| 100 | VAddr wait_address; | ||
| 101 | |||
| 102 | std::vector<Thread*> waiting_threads; // TODO(yuriks): Owned | ||
| 103 | |||
| 104 | std::string name; | ||
| 105 | |||
| 106 | /// Whether this thread is intended to never actually be executed, i.e. always idle | ||
| 107 | bool idle = false; | ||
| 108 | |||
| 109 | private: | ||
| 110 | Thread() = default; | ||
| 111 | }; | ||
| 112 | |||
| 113 | /// Sets up the primary application thread | ||
| 114 | Thread* SetupMainThread(s32 priority, int stack_size = Kernel::DEFAULT_STACK_SIZE); | ||
| 115 | |||
| 116 | /// Reschedules to the next available thread (call after current thread is suspended) | ||
| 117 | void Reschedule(); | ||
| 74 | 118 | ||
| 75 | /// Arbitrate the highest priority thread that is waiting | 119 | /// Arbitrate the highest priority thread that is waiting |
| 76 | Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address); | 120 | Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address); |
| 77 | 121 | ||
| 78 | /// Arbitrate all threads currently waiting... | 122 | /// Arbitrate all threads currently waiting... |
| 79 | void ArbitrateAllThreads(u32 arbiter, u32 address); | 123 | void ArbitrateAllThreads(Object* arbiter, u32 address); |
| 80 | 124 | ||
| 81 | /// Gets the current thread handle | 125 | /// Gets the current thread |
| 82 | Handle GetCurrentThreadHandle(); | 126 | Thread* GetCurrentThread(); |
| 83 | 127 | ||
| 84 | /** | 128 | /** |
| 85 | * Puts the current thread in the wait state for the given type | 129 | * Puts the current thread in the wait state for the given type |
| 86 | * @param wait_type Type of wait | 130 | * @param wait_type Type of wait |
| 87 | * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread | 131 | * @param wait_object Kernel object that we are waiting on, defaults to current thread |
| 88 | */ | 132 | */ |
| 89 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle()); | 133 | void WaitCurrentThread(WaitType wait_type, Object* wait_object = GetCurrentThread()); |
| 90 | 134 | ||
| 91 | /** | 135 | /** |
| 92 | * Schedules an event to wake up the specified thread after the specified delay. | 136 | * Schedules an event to wake up the specified thread after the specified delay. |
| 93 | * @param handle The thread handle. | 137 | * @param handle The thread handle. |
| 94 | * @param nanoseconds The time this thread will be allowed to sleep for. | 138 | * @param nanoseconds The time this thread will be allowed to sleep for. |
| 95 | */ | 139 | */ |
| 96 | void WakeThreadAfterDelay(Handle handle, s64 nanoseconds); | 140 | void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); |
| 97 | 141 | ||
| 98 | /** | 142 | /** |
| 99 | * Puts the current thread in the wait state for the given type | 143 | * Puts the current thread in the wait state for the given type |
| 100 | * @param wait_type Type of wait | 144 | * @param wait_type Type of wait |
| 101 | * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread | 145 | * @param wait_object Kernel object that we are waiting on |
| 102 | * @param wait_address Arbitration address used to resume from wait | 146 | * @param wait_address Arbitration address used to resume from wait |
| 103 | */ | 147 | */ |
| 104 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address); | 148 | void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address); |
| 105 | 149 | ||
| 106 | /// Put current thread in a wait state - on WaitSynchronization | ||
| 107 | void WaitThread_Synchronization(); | ||
| 108 | 150 | ||
| 109 | /// Get the priority of the thread specified by handle | ||
| 110 | ResultVal<u32> GetThreadPriority(const Handle handle); | ||
| 111 | |||
| 112 | /// Set the priority of the thread specified by handle | ||
| 113 | ResultCode SetThreadPriority(Handle handle, s32 priority); | ||
| 114 | 151 | ||
| 115 | /** | 152 | /** |
| 116 | * Sets up the idle thread, this is a thread that is intended to never execute instructions, | 153 | * Sets up the idle thread, this is a thread that is intended to never execute instructions, |
| @@ -119,10 +156,6 @@ ResultCode SetThreadPriority(Handle handle, s32 priority); | |||
| 119 | * @returns The handle of the idle thread | 156 | * @returns The handle of the idle thread |
| 120 | */ | 157 | */ |
| 121 | Handle SetupIdleThread(); | 158 | Handle SetupIdleThread(); |
| 122 | |||
| 123 | /// Whether the current thread is an idle thread | ||
| 124 | bool IsIdleThread(Handle thread); | ||
| 125 | |||
| 126 | /// Initialize threading | 159 | /// Initialize threading |
| 127 | void ThreadingInit(); | 160 | void ThreadingInit(); |
| 128 | 161 | ||
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 7ac669e31..685a202c0 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -33,8 +33,8 @@ public: | |||
| 33 | ResultVal<bool> WaitSynchronization() override { | 33 | ResultVal<bool> WaitSynchronization() override { |
| 34 | bool wait = !signaled; | 34 | bool wait = !signaled; |
| 35 | if (wait) { | 35 | if (wait) { |
| 36 | waiting_threads.insert(GetCurrentThreadHandle()); | 36 | waiting_threads.insert(GetCurrentThread()->GetHandle()); |
| 37 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, GetHandle()); | 37 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); |
| 38 | } | 38 | } |
| 39 | return MakeResult<bool>(wait); | 39 | return MakeResult<bool>(wait); |
| 40 | } | 40 | } |
| @@ -92,8 +92,10 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 92 | timer->signaled = true; | 92 | timer->signaled = true; |
| 93 | 93 | ||
| 94 | // Resume all waiting threads | 94 | // Resume all waiting threads |
| 95 | for (Handle thread : timer->waiting_threads) | 95 | for (Handle thread_handle : timer->waiting_threads) { |
| 96 | ResumeThreadFromWait(thread); | 96 | if (Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle)) |
| 97 | thread->ResumeFromWait(); | ||
| 98 | } | ||
| 97 | 99 | ||
| 98 | timer->waiting_threads.clear(); | 100 | timer->waiting_threads.clear(); |
| 99 | 101 | ||
diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp index 99b0ea5a0..8ef9af9d2 100644 --- a/src/core/hle/service/hid_user.cpp +++ b/src/core/hle/service/hid_user.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/log.h" | 5 | #include "common/log.h" |
| 6 | 6 | ||
| 7 | #include "core/arm/arm_interface.h" | ||
| 7 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 8 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| 9 | #include "core/hle/kernel/shared_memory.h" | 10 | #include "core/hle/kernel/shared_memory.h" |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 051f2d2c6..8ac1c7350 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/string_util.h" | 7 | #include "common/string_util.h" |
| 8 | #include "common/symbols.h" | 8 | #include "common/symbols.h" |
| 9 | 9 | ||
| 10 | #include "core/arm/arm_interface.h" | ||
| 10 | #include "core/mem_map.h" | 11 | #include "core/mem_map.h" |
| 11 | 12 | ||
| 12 | #include "core/hle/kernel/address_arbiter.h" | 13 | #include "core/hle/kernel/address_arbiter.h" |
| @@ -230,14 +231,17 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top | |||
| 230 | name = Common::StringFromFormat("unknown-%08x", entry_point); | 231 | name = Common::StringFromFormat("unknown-%08x", entry_point); |
| 231 | } | 232 | } |
| 232 | 233 | ||
| 233 | Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, | 234 | ResultVal<Kernel::Thread*> thread_res = Kernel::Thread::Create(name.c_str(), entry_point, priority, arg, |
| 234 | stack_top); | 235 | processor_id, stack_top); |
| 236 | if (thread_res.Failed()) | ||
| 237 | return thread_res.Code().raw; | ||
| 238 | Kernel::Thread* thread = *thread_res; | ||
| 235 | 239 | ||
| 236 | Core::g_app_core->SetReg(1, thread); | 240 | Core::g_app_core->SetReg(1, thread->GetHandle()); |
| 237 | 241 | ||
| 238 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | 242 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |
| 239 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, | 243 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, |
| 240 | name.c_str(), arg, stack_top, priority, processor_id, thread); | 244 | name.c_str(), arg, stack_top, priority, processor_id, thread->GetHandle()); |
| 241 | 245 | ||
| 242 | if (THREADPROCESSORID_1 == processor_id) { | 246 | if (THREADPROCESSORID_1 == processor_id) { |
| 243 | LOG_WARNING(Kernel_SVC, | 247 | LOG_WARNING(Kernel_SVC, |
| @@ -248,28 +252,31 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top | |||
| 248 | } | 252 | } |
| 249 | 253 | ||
| 250 | /// Called when a thread exits | 254 | /// Called when a thread exits |
| 251 | static u32 ExitThread() { | 255 | static void ExitThread() { |
| 252 | Handle thread = Kernel::GetCurrentThreadHandle(); | 256 | LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); |
| 253 | 257 | ||
| 254 | LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C | 258 | Kernel::GetCurrentThread()->Stop(__func__); |
| 255 | |||
| 256 | Kernel::StopThread(thread, __func__); | ||
| 257 | HLE::Reschedule(__func__); | 259 | HLE::Reschedule(__func__); |
| 258 | return 0; | ||
| 259 | } | 260 | } |
| 260 | 261 | ||
| 261 | /// Gets the priority for the specified thread | 262 | /// Gets the priority for the specified thread |
| 262 | static Result GetThreadPriority(s32* priority, Handle handle) { | 263 | static Result GetThreadPriority(s32* priority, Handle handle) { |
| 263 | ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle); | 264 | const Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 264 | if (priority_result.Succeeded()) { | 265 | if (thread == nullptr) |
| 265 | *priority = *priority_result; | 266 | return InvalidHandle(ErrorModule::Kernel).raw; |
| 266 | } | 267 | |
| 267 | return priority_result.Code().raw; | 268 | *priority = thread->GetPriority(); |
| 269 | return RESULT_SUCCESS.raw; | ||
| 268 | } | 270 | } |
| 269 | 271 | ||
| 270 | /// Sets the priority for the specified thread | 272 | /// Sets the priority for the specified thread |
| 271 | static Result SetThreadPriority(Handle handle, s32 priority) { | 273 | static Result SetThreadPriority(Handle handle, s32 priority) { |
| 272 | return Kernel::SetThreadPriority(handle, priority).raw; | 274 | Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 275 | if (thread == nullptr) | ||
| 276 | return InvalidHandle(ErrorModule::Kernel).raw; | ||
| 277 | |||
| 278 | thread->SetPriority(priority); | ||
| 279 | return RESULT_SUCCESS.raw; | ||
| 273 | } | 280 | } |
| 274 | 281 | ||
| 275 | /// Create a mutex | 282 | /// Create a mutex |
| @@ -290,8 +297,13 @@ static Result ReleaseMutex(Handle handle) { | |||
| 290 | /// Get the ID for the specified thread. | 297 | /// Get the ID for the specified thread. |
| 291 | static Result GetThreadId(u32* thread_id, Handle handle) { | 298 | static Result GetThreadId(u32* thread_id, Handle handle) { |
| 292 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); | 299 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); |
| 293 | ResultCode result = Kernel::GetThreadId(thread_id, handle); | 300 | |
| 294 | return result.raw; | 301 | const Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 302 | if (thread == nullptr) | ||
| 303 | return InvalidHandle(ErrorModule::Kernel).raw; | ||
| 304 | |||
| 305 | *thread_id = thread->GetThreadId(); | ||
| 306 | return RESULT_SUCCESS.raw; | ||
| 295 | } | 307 | } |
| 296 | 308 | ||
| 297 | /// Creates a semaphore | 309 | /// Creates a semaphore |
| @@ -379,7 +391,7 @@ static void SleepThread(s64 nanoseconds) { | |||
| 379 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); | 391 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); |
| 380 | 392 | ||
| 381 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 393 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 382 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThreadHandle(), nanoseconds); | 394 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds); |
| 383 | 395 | ||
| 384 | HLE::Reschedule(__func__); | 396 | HLE::Reschedule(__func__); |
| 385 | } | 397 | } |
| @@ -411,7 +423,7 @@ const HLE::FunctionDef SVC_Table[] = { | |||
| 411 | {0x06, nullptr, "GetProcessIdealProcessor"}, | 423 | {0x06, nullptr, "GetProcessIdealProcessor"}, |
| 412 | {0x07, nullptr, "SetProcessIdealProcessor"}, | 424 | {0x07, nullptr, "SetProcessIdealProcessor"}, |
| 413 | {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, | 425 | {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, |
| 414 | {0x09, HLE::Wrap<ExitThread>, "ExitThread"}, | 426 | {0x09, ExitThread, "ExitThread"}, |
| 415 | {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, | 427 | {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, |
| 416 | {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, | 428 | {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, |
| 417 | {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, | 429 | {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, |
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h index ad780818e..5d020a5ba 100644 --- a/src/core/hle/svc.h +++ b/src/core/hle/svc.h | |||
| @@ -20,21 +20,6 @@ struct PageInfo { | |||
| 20 | u32 flags; | 20 | u32 flags; |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | struct ThreadContext { | ||
| 24 | u32 cpu_registers[13]; | ||
| 25 | u32 sp; | ||
| 26 | u32 lr; | ||
| 27 | u32 pc; | ||
| 28 | u32 cpsr; | ||
| 29 | u32 fpu_registers[32]; | ||
| 30 | u32 fpscr; | ||
| 31 | u32 fpexc; | ||
| 32 | |||
| 33 | // These are not part of native ThreadContext, but needed by emu | ||
| 34 | u32 reg_15; | ||
| 35 | u32 mode; | ||
| 36 | }; | ||
| 37 | |||
| 38 | enum ResetType { | 23 | enum ResetType { |
| 39 | RESETTYPE_ONESHOT, | 24 | RESETTYPE_ONESHOT, |
| 40 | RESETTYPE_STICKY, | 25 | RESETTYPE_STICKY, |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index e346e0ad6..3b730a0de 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | 6 | ||
| 7 | #include "core/arm/arm_interface.h" | ||
| 8 | |||
| 7 | #include "core/settings.h" | 9 | #include "core/settings.h" |
| 8 | #include "core/core.h" | 10 | #include "core/core.h" |
| 9 | #include "core/mem_map.h" | 11 | #include "core/mem_map.h" |