From f2331a804a2fa300d9a7dc0d012e3242b7accdaf Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Apr 2019 13:25:54 -0400 Subject: core/cpu_core_manager: Create threads separately from initialization. Our initialization process is a little wonky than one would expect when it comes to code flow. We initialize the CPU last, as opposed to hardware, where the CPU obviously needs to be first, otherwise nothing else would work, and we have code that adds checks to get around this. For example, in the page table setting code, we check to see if the system is turned on before we even notify the CPU instances of a page table switch. This results in dead code (at the moment), because the only time a page table switch will occur is when the system is *not* running, preventing the emulated CPU instances from being notified of a page table switch in a convenient manner (technically the code path could be taken, but we don't emulate the process creation svc handlers yet). This moves the threads creation into its own member function of the core manager and restores a little order (and predictability) to our initialization process. Previously, in the multi-threaded cases, we'd kick off several threads before even the main kernel process was created and ready to execute (gross!). Now the initialization process is like so: Initialization: 1. Timers 2. CPU 3. Kernel 4. Filesystem stuff (kind of gross, but can be amended trivially) 5. Applet stuff (ditto in terms of being kind of gross) 6. Main process (will be moved into the loading step in a following change) 7. Telemetry (this should be initialized last in the future). 8. Services (4 and 5 should ideally be alongside this). 9. GDB (gross. Uses namespace scope state. Needs to be refactored into a class or booted altogether). 10. Renderer 11. GPU (will also have its threads created in a separate step in a following change). Which... isn't *ideal* per-se, however getting rid of the wonky intertwining of CPU state initialization out of this mix gets rid of most of the footguns when it comes to our initialization process. --- src/core/core.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index bc9e887b6..2b8ec3ca7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -81,7 +81,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, return vfs->OpenFile(path, FileSys::Mode::Read); } struct System::Impl { - explicit Impl(System& system) : kernel{system} {} + explicit Impl(System& system) : kernel{system}, cpu_core_manager{system} {} Cpu& CurrentCpuCore() { return cpu_core_manager.GetCurrentCore(); @@ -99,6 +99,7 @@ struct System::Impl { LOG_DEBUG(HW_Memory, "initialized OK"); core_timing.Initialize(); + cpu_core_manager.Initialize(); kernel.Initialize(); const auto current_time = std::chrono::duration_cast( @@ -142,8 +143,6 @@ struct System::Impl { gpu_core = std::make_unique(system, *renderer); } - cpu_core_manager.Initialize(system); - LOG_DEBUG(Core, "Initialized OK"); // Reset counters and set time origin to current frame @@ -188,6 +187,10 @@ struct System::Impl { static_cast(load_result)); } + // Main process has been loaded and been made current. + // Begin CPU execution. + cpu_core_manager.StartThreads(); + status = ResultStatus::Success; return status; } -- cgit v1.2.3 From 6d0551196d90af7f1233c655fd3b979811a14708 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Apr 2019 14:02:00 -0400 Subject: video_core/gpu: Create threads separately from initialization Like with CPU emulation, we generally don't want to fire off the threads immediately after the relevant classes are initialized, we want to do this after all necessary data is done loading first. This splits the thread creation into its own interface member function to allow controlling when these threads in particular get created. --- src/core/core.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 2b8ec3ca7..eb300eef7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -3,9 +3,7 @@ // Refer to the license.txt file included. #include -#include #include -#include #include #include "common/file_util.h" @@ -38,8 +36,6 @@ #include "frontend/applets/software_keyboard.h" #include "frontend/applets/web_browser.h" #include "video_core/debug_utils/debug_utils.h" -#include "video_core/gpu_asynch.h" -#include "video_core/gpu_synch.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" @@ -135,13 +131,9 @@ struct System::Impl { return ResultStatus::ErrorVideoCore; } - is_powered_on = true; + gpu_core = VideoCore::CreateGPU(system); - if (Settings::values.use_asynchronous_gpu_emulation) { - gpu_core = std::make_unique(system, *renderer); - } else { - gpu_core = std::make_unique(system, *renderer); - } + is_powered_on = true; LOG_DEBUG(Core, "Initialized OK"); @@ -188,7 +180,8 @@ struct System::Impl { } // Main process has been loaded and been made current. - // Begin CPU execution. + // Begin GPU and CPU execution. + gpu_core->Start(); cpu_core_manager.StartThreads(); status = ResultStatus::Success; -- cgit v1.2.3 From a4b0a8559c9d137682e1b77332a42841c9e640bd Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Apr 2019 15:27:44 -0400 Subject: core/core: Move main process creation into Load() Now that we have dependencies on the initialization order, we can move the creation of the main process to a more sensible area: where we actually load in the executable data. This allows localizing the creation and loading of the process in one location, making the initialization of the process much nicer to trace. --- src/core/core.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index eb300eef7..265ac2835 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -117,9 +117,6 @@ struct System::Impl { if (web_browser == nullptr) web_browser = std::make_unique(); - auto main_process = Kernel::Process::Create(system, "main"); - kernel.MakeCurrentProcess(main_process.get()); - telemetry_session = std::make_unique(); service_manager = std::make_shared(); @@ -170,7 +167,8 @@ struct System::Impl { return init_result; } - const Loader::ResultStatus load_result{app_loader->Load(*kernel.CurrentProcess())}; + auto main_process = Kernel::Process::Create(system, "main"); + const Loader::ResultStatus load_result{app_loader->Load(*main_process)}; if (load_result != Loader::ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast(load_result)); Shutdown(); @@ -178,6 +176,7 @@ struct System::Impl { return static_cast(static_cast(ResultStatus::ErrorLoader) + static_cast(load_result)); } + kernel.MakeCurrentProcess(main_process.get()); // Main process has been loaded and been made current. // Begin GPU and CPU execution. -- cgit v1.2.3 From 612e1388df3bed64081488f2a99cce522c80c76d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Apr 2019 17:03:04 -0400 Subject: core/core: Move process execution start to System's Load() This gives us significantly more control over where in the initialization process we start execution of the main process. Previously we were running the main process before the CPU or GPU threads were initialized (not good). This amends execution to start after all of our threads are properly set up. --- src/core/core.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 265ac2835..175a5f2ea 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -168,7 +168,7 @@ struct System::Impl { } auto main_process = Kernel::Process::Create(system, "main"); - const Loader::ResultStatus load_result{app_loader->Load(*main_process)}; + const auto [load_result, load_parameters] = app_loader->Load(*main_process); if (load_result != Loader::ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast(load_result)); Shutdown(); @@ -183,6 +183,10 @@ struct System::Impl { gpu_core->Start(); cpu_core_manager.StartThreads(); + // All threads are started, begin main process execution, now that we're in the clear. + main_process->Run(load_parameters->main_thread_priority, + load_parameters->main_thread_stack_size); + status = ResultStatus::Success; return status; } -- cgit v1.2.3