From 535e49a38d0988c3618197ac3017c0985786af21 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 18 Oct 2019 20:31:15 -0700 Subject: [PATCH] strat: statically allocate additional threads --- stratosphere/creport/source/creport_main.cpp | 1 + .../dmnt/source/cheat/impl/dmnt_cheat_api.cpp | 15 ++++-- .../impl/dmnt_cheat_debug_events_manager.cpp | 8 ++- stratosphere/dmnt/source/dmnt_main.cpp | 23 ++++---- stratosphere/fatal/source/fatal_main.cpp | 3 +- stratosphere/fatal/source/fatal_task.cpp | 2 +- stratosphere/fatal/source/fatal_task.hpp | 24 +++++++-- .../fatal/source/fatal_task_clock.cpp | 2 +- .../fatal/source/fatal_task_error_report.cpp | 2 +- .../fatal/source/fatal_task_power.cpp | 6 +-- .../fatal/source/fatal_task_screen.cpp | 7 +-- .../fatal/source/fatal_task_sound.cpp | 2 +- .../include/stratosphere/os/os_thread.hpp | 54 +++++++++++++++++-- stratosphere/loader/source/ldr_main.cpp | 1 + .../pm/source/impl/pm_process_manager.cpp | 8 +-- stratosphere/pm/source/pm_main.cpp | 5 +- stratosphere/ro/source/ro_main.cpp | 2 + 17 files changed, 123 insertions(+), 42 deletions(-) diff --git a/stratosphere/creport/source/creport_main.cpp b/stratosphere/creport/source/creport_main.cpp index ed3ea9b8c..037fe520a 100644 --- a/stratosphere/creport/source/creport_main.cpp +++ b/stratosphere/creport/source/creport_main.cpp @@ -30,6 +30,7 @@ extern "C" { u32 __nx_applet_type = AppletType_None; u32 __nx_fs_num_sessions = 1; + u32 __nx_fsdev_direntry_cache_size = 1; #define INNER_HEAP_SIZE 0x4000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; diff --git a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp index b1374f8f3..4db3129b7 100644 --- a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp +++ b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp @@ -30,6 +30,11 @@ namespace sts::dmnt::cheat::impl { /* Manager class. */ class CheatProcessManager { + private: + static constexpr size_t ThreadStackSize = 0x4000; + static constexpr int DetectThreadPriority = 39; + static constexpr int VirtualMachineThreadPriority = 48; + static constexpr int DebugEventsThreadPriority = 24; private: os::Mutex cheat_lock; os::Event debug_events_event; /* Autoclear. */ @@ -47,6 +52,10 @@ namespace sts::dmnt::cheat::impl { bool should_save_cheat_toggles = false; CheatEntry cheat_entries[MaxCheatCount] = {}; std::map frozen_addresses_map; + + alignas(0x1000) u8 detect_thread_stack[ThreadStackSize] = {}; + alignas(0x1000) u8 debug_events_thread_stack[ThreadStackSize] = {}; + alignas(0x1000) u8 vm_thread_stack[ThreadStackSize] = {}; private: static void DetectLaunchThread(void *_this); static void VirtualMachineThread(void *_this); @@ -200,9 +209,9 @@ namespace sts::dmnt::cheat::impl { } /* Spawn application detection thread, spawn cheat vm thread. */ - R_ASSERT(this->detect_thread.Initialize(&CheatProcessManager::DetectLaunchThread, this, 0x4000, 39)); - R_ASSERT(this->vm_thread.Initialize(&CheatProcessManager::VirtualMachineThread, this, 0x4000, 48)); - R_ASSERT(this->debug_events_thread.Initialize(&CheatProcessManager::DebugEventsThread, this, 0x4000, 24)); + R_ASSERT(this->detect_thread.Initialize(&CheatProcessManager::DetectLaunchThread, this, this->detect_thread_stack, ThreadStackSize, DetectThreadPriority)); + R_ASSERT(this->vm_thread.Initialize(&CheatProcessManager::VirtualMachineThread, this, this->vm_thread_stack, ThreadStackSize, VirtualMachineThreadPriority)); + R_ASSERT(this->debug_events_thread.Initialize(&CheatProcessManager::DebugEventsThread, this, this->debug_events_thread_stack, ThreadStackSize, DebugEventsThreadPriority)); /* Start threads. */ R_ASSERT(this->detect_thread.Start()); diff --git a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_debug_events_manager.cpp b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_debug_events_manager.cpp index 4230e862d..a36c90d21 100644 --- a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_debug_events_manager.cpp +++ b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_debug_events_manager.cpp @@ -25,10 +25,14 @@ namespace sts::dmnt::cheat::impl { class DebugEventsManager { public: static constexpr size_t NumCores = 4; + static constexpr size_t ThreadStackSize = 0x1000; + static constexpr size_t ThreadPriority = 24; private: std::array message_queues; std::array threads; os::Event continued_event; + + alignas(0x1000) u8 thread_stacks[NumCores][ThreadStackSize]; private: static void PerCoreThreadFunction(void *_this) { /* This thread will wait on the appropriate message queue. */ @@ -88,10 +92,10 @@ namespace sts::dmnt::cheat::impl { } public: - DebugEventsManager() : message_queues{os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1)} { + DebugEventsManager() : message_queues{os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1)}, thread_stacks{} { for (size_t i = 0; i < NumCores; i++) { /* Create thread. */ - R_ASSERT(this->threads[i].Initialize(&DebugEventsManager::PerCoreThreadFunction, reinterpret_cast(this), 0x1000, 24, i)); + R_ASSERT(this->threads[i].Initialize(&DebugEventsManager::PerCoreThreadFunction, reinterpret_cast(this), this->thread_stacks[i], ThreadStackSize, ThreadPriority, i)); /* Set core mask. */ R_ASSERT(svcSetThreadCoreMask(this->threads[i].GetHandle(), i, (1u << i))); diff --git a/stratosphere/dmnt/source/dmnt_main.cpp b/stratosphere/dmnt/source/dmnt_main.cpp index 98dfa6f3c..4e643592d 100644 --- a/stratosphere/dmnt/source/dmnt_main.cpp +++ b/stratosphere/dmnt/source/dmnt_main.cpp @@ -31,9 +31,10 @@ extern "C" { u32 __nx_applet_type = AppletType_None; u32 __nx_fs_num_sessions = 1; + u32 __nx_fsdev_direntry_cache_size = 1; /* TODO: Evaluate how much this can be reduced by. */ - #define INNER_HEAP_SIZE 0xC0000 + #define INNER_HEAP_SIZE 0x20000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; @@ -118,6 +119,14 @@ namespace { g_server_manager.LoopProcess(); } + constexpr size_t TotalThreads = DebugMonitorMaxSessions + 1; + static_assert(TotalThreads >= 1, "TotalThreads"); + constexpr size_t NumExtraThreads = TotalThreads - 1; + constexpr size_t ThreadStackSize = 0x4000; + alignas(0x1000) u8 g_extra_thread_stacks[NumExtraThreads][ThreadStackSize]; + + os::Thread g_extra_threads[NumExtraThreads]; + } int main(int argc, char **argv) @@ -130,25 +139,19 @@ int main(int argc, char **argv) /* Loop forever, servicing our services. */ /* Nintendo loops four threads processing on the manager -- we'll loop an extra fifth for our cheat service. */ { - constexpr size_t TotalThreads = DebugMonitorMaxSessions + 1; - constexpr size_t NumExtraThreads = TotalThreads - 1; - static_assert(TotalThreads >= 1, "TotalThreads"); - - os::Thread extra_threads[NumExtraThreads]; /* Initialize threads. */ if constexpr (NumExtraThreads > 0) { - constexpr size_t ThreadStackSize = 0x4000; const u32 priority = os::GetCurrentThreadPriority(); for (size_t i = 0; i < NumExtraThreads; i++) { - R_ASSERT(extra_threads[i].Initialize(LoopServerThread, nullptr, ThreadStackSize, priority)); + R_ASSERT(g_extra_threads[i].Initialize(LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority)); } } /* Start extra threads. */ if constexpr (NumExtraThreads > 0) { for (size_t i = 0; i < NumExtraThreads; i++) { - R_ASSERT(extra_threads[i].Start()); + R_ASSERT(g_extra_threads[i].Start()); } } @@ -158,7 +161,7 @@ int main(int argc, char **argv) /* Wait for extra threads to finish. */ if constexpr (NumExtraThreads > 0) { for (size_t i = 0; i < NumExtraThreads; i++) { - R_ASSERT(extra_threads[i].Join()); + R_ASSERT(g_extra_threads[i].Join()); } } } diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index b8ac7f0f7..aa3d393c6 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -32,8 +32,9 @@ extern "C" { u32 __nx_applet_type = AppletType_None; u32 __nx_fs_num_sessions = 1; + u32 __nx_fsdev_direntry_cache_size = 1; - #define INNER_HEAP_SIZE 0x2A0000 + #define INNER_HEAP_SIZE 0x240000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index d412d4684..d67fdf6e1 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -45,7 +45,7 @@ namespace sts::fatal::srv { public: TaskThread() { /* ... */ } void StartTask(ITask *task) { - R_ASSERT(this->thread.Initialize(&RunTaskImpl, task, task->GetStackSize(), TaskThreadPriority)); + R_ASSERT(this->thread.Initialize(&RunTaskImpl, task, task->GetStack(), task->GetStackSize(), TaskThreadPriority)); R_ASSERT(this->thread.Start()); } }; diff --git a/stratosphere/fatal/source/fatal_task.hpp b/stratosphere/fatal/source/fatal_task.hpp index 599990fa0..b0ad228d9 100644 --- a/stratosphere/fatal/source/fatal_task.hpp +++ b/stratosphere/fatal/source/fatal_task.hpp @@ -22,8 +22,6 @@ namespace sts::fatal::srv { class ITask { - public: - static constexpr size_t DefaultStackSize = 0x1000; protected: const ThrowContext *context = nullptr; public: @@ -32,14 +30,30 @@ namespace sts::fatal::srv { } virtual Result Run() = 0; - virtual const char *GetName() const = 0; + virtual u8 *GetStack() = 0; + virtual size_t GetStackSize() const = 0; + }; - virtual size_t GetStackSize() const { - return DefaultStackSize; + template + class ITaskWithStack : public ITask { + public: + static constexpr size_t StackSize = _StackSize; + static_assert(util::IsAligned(StackSize, 0x1000), "StackSize alignment"); + protected: + alignas(0x1000) u8 stack_mem[StackSize] = {}; + public: + virtual u8 *GetStack() override final { + return this->stack_mem; + } + + virtual size_t GetStackSize() const override final { + return StackSize; } }; + using ITaskWithDefaultStack = ITaskWithStack<0x2000>; + void RunTasks(const ThrowContext *ctx); } \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_clock.cpp b/stratosphere/fatal/source/fatal_task_clock.cpp index 674e5ebde..ce56dda35 100644 --- a/stratosphere/fatal/source/fatal_task_clock.cpp +++ b/stratosphere/fatal/source/fatal_task_clock.cpp @@ -22,7 +22,7 @@ namespace sts::fatal::srv { namespace { /* Task definition. */ - class AdjustClockTask : public ITask { + class AdjustClockTask : public ITaskWithDefaultStack { private: Result AdjustClockForModule(PcvModule module, u32 hz); Result AdjustClock(); diff --git a/stratosphere/fatal/source/fatal_task_error_report.cpp b/stratosphere/fatal/source/fatal_task_error_report.cpp index 3b4ec6fe6..4c55d5f1e 100644 --- a/stratosphere/fatal/source/fatal_task_error_report.cpp +++ b/stratosphere/fatal/source/fatal_task_error_report.cpp @@ -53,7 +53,7 @@ namespace sts::fatal::srv { } /* Task definition. */ - class ErrorReportTask : public ITask { + class ErrorReportTask : public ITaskWithDefaultStack { private: void SaveReportToSdCard(); public: diff --git a/stratosphere/fatal/source/fatal_task_power.cpp b/stratosphere/fatal/source/fatal_task_power.cpp index 20e1840fb..93d74bc05 100644 --- a/stratosphere/fatal/source/fatal_task_power.cpp +++ b/stratosphere/fatal/source/fatal_task_power.cpp @@ -22,7 +22,7 @@ namespace sts::fatal::srv { namespace { /* Task types. */ - class PowerControlTask : public ITask { + class PowerControlTask : public ITaskWithDefaultStack { private: bool TryShutdown(); void MonitorBatteryState(); @@ -33,7 +33,7 @@ namespace sts::fatal::srv { } }; - class PowerButtonObserveTask : public ITask { + class PowerButtonObserveTask : public ITaskWithDefaultStack { private: void WaitForPowerButton(); public: @@ -43,7 +43,7 @@ namespace sts::fatal::srv { } }; - class StateTransitionStopTask : public ITask { + class StateTransitionStopTask : public ITaskWithDefaultStack { public: virtual Result Run() override; virtual const char *GetName() const override { diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 187d1832b..9dc638057 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -53,7 +53,7 @@ namespace sts::fatal::srv { } /* Task definitions. */ - class ShowFatalTask : public ITask { + class ShowFatalTask : public ITaskWithStack<0x8000> { private: ViDisplay display; ViLayer layer; @@ -69,12 +69,9 @@ namespace sts::fatal::srv { virtual const char *GetName() const override { return "ShowFatal"; } - virtual size_t GetStackSize() const override { - return 0x8000; - } }; - class BacklightControlTask : public ITask { + class BacklightControlTask : public ITaskWithDefaultStack { private: void TurnOnBacklight(); public: diff --git a/stratosphere/fatal/source/fatal_task_sound.cpp b/stratosphere/fatal/source/fatal_task_sound.cpp index a8ac6365a..45bae8b4b 100644 --- a/stratosphere/fatal/source/fatal_task_sound.cpp +++ b/stratosphere/fatal/source/fatal_task_sound.cpp @@ -21,7 +21,7 @@ namespace sts::fatal::srv { namespace { /* Task definition. */ - class StopSoundTask : public ITask { + class StopSoundTask : public ITaskWithDefaultStack { private: void StopSound(); public: diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp index 3d2b7f3ca..a866d66f0 100644 --- a/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp @@ -20,13 +20,61 @@ namespace sts::os { class Thread { + NON_COPYABLE(Thread); + NON_MOVEABLE(Thread); private: - ::Thread thr = {}; + ::Thread thr; public: - Thread() {} + constexpr Thread() : thr{} { /* ... */ } + + Result Initialize(ThreadFunc entry, void *arg, void *stack_mem, size_t stack_sz, int prio, int cpuid = -2) { + return threadCreate(&this->thr, entry, arg, stack_mem, stack_sz, prio, cpuid); + } Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) { - return threadCreate(&this->thr, entry, arg, stack_sz, prio, cpuid); + return threadCreate(&this->thr, entry, arg, nullptr, stack_sz, prio, cpuid); + } + + Handle GetHandle() const { + return this->thr.handle; + } + + Result Start() { + return threadStart(&this->thr); + } + + Result Wait() { + return threadWaitForExit(&this->thr); + } + + Result Join() { + R_TRY(threadWaitForExit(&this->thr)); + R_TRY(threadClose(&this->thr)); + return ResultSuccess; + } + + Result CancelSynchronization() { + return svcCancelSynchronization(this->thr.handle); + } + }; + + template + class StaticThread { + NON_COPYABLE(StaticThread); + NON_MOVEABLE(StaticThread); + static_assert(util::IsAligned(StackSize, 0x1000), "StaticThread must have aligned resource size"); + private: + alignas(0x1000) u8 stack_mem[StackSize]; + ::Thread thr; + public: + constexpr StaticThread() : stack_mem{}, thr{} { /* ... */ } + + constexpr StaticThread(ThreadFunc entry, void *arg, int prio, int cpuid = -2) : StaticThread() { + R_ASSERT(this->Initialize(entry, arg, prio, cpuid)); + } + + Result Initialize(ThreadFunc entry, void *arg, int prio, int cpuid = -2) { + return threadCreate(&this->thr, entry, arg, this->stack_mem, StackSize, prio, cpuid); } Handle GetHandle() const { diff --git a/stratosphere/loader/source/ldr_main.cpp b/stratosphere/loader/source/ldr_main.cpp index 5ea866631..323866174 100644 --- a/stratosphere/loader/source/ldr_main.cpp +++ b/stratosphere/loader/source/ldr_main.cpp @@ -32,6 +32,7 @@ extern "C" { u32 __nx_applet_type = AppletType_None; u32 __nx_fs_num_sessions = 1; + u32 __nx_fsdev_direntry_cache_size = 1; #define INNER_HEAP_SIZE 0x4000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 4eaf20e77..85e75a53c 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -182,7 +182,11 @@ namespace sts::pm::impl { }; /* Process Tracking globals. */ - os::Thread g_process_track_thread; + void ProcessTrackingMain(void *arg); + + constexpr size_t ProcessTrackThreadStackSize = 0x4000; + constexpr int ProcessTrackThreadPriority = 0x15; + os::StaticThread g_process_track_thread(&ProcessTrackingMain, nullptr, ProcessTrackThreadPriority); /* Process lists. */ ProcessList g_process_list; @@ -468,8 +472,6 @@ namespace sts::pm::impl { R_TRY(resource::InitializeResourceManager()); /* Start thread. */ - /* TODO: Allocate thread stack resources statically, will require PR to libnx. */ - R_ASSERT(g_process_track_thread.Initialize(&ProcessTrackingMain, nullptr, 0x4000, 0x15)); R_ASSERT(g_process_track_thread.Start()); return ResultSuccess; diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp index 854933f90..8b2442901 100644 --- a/stratosphere/pm/source/pm_main.cpp +++ b/stratosphere/pm/source/pm_main.cpp @@ -36,10 +36,9 @@ extern "C" { u32 __nx_applet_type = AppletType_None; u32 __nx_fs_num_sessions = 1; + u32 __nx_fsdev_direntry_cache_size = 1; - /* TODO: Statically allocate PM resource thread stack, reduce this. */ - /* TODO: Determine what the minimum consistent value for this is (dump heap at runtime). */ - #define INNER_HEAP_SIZE 0xC000 + #define INNER_HEAP_SIZE 0x4000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; diff --git a/stratosphere/ro/source/ro_main.cpp b/stratosphere/ro/source/ro_main.cpp index b7180ba19..f3f156814 100644 --- a/stratosphere/ro/source/ro_main.cpp +++ b/stratosphere/ro/source/ro_main.cpp @@ -32,6 +32,8 @@ extern "C" { extern u32 __start__; u32 __nx_applet_type = AppletType_None; + u32 __nx_fs_num_sessions = 1; + u32 __nx_fsdev_direntry_cache_size = 1; #define INNER_HEAP_SIZE 0x4000 size_t nx_inner_heap_size = INNER_HEAP_SIZE;