diff options
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 207 |
1 files changed, 103 insertions, 104 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 2ff253183..ce94d3605 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -34,14 +34,15 @@ | |||
| 34 | #include "core/hle/kernel/k_process.h" | 34 | #include "core/hle/kernel/k_process.h" |
| 35 | #include "core/hle/kernel/k_resource_limit.h" | 35 | #include "core/hle/kernel/k_resource_limit.h" |
| 36 | #include "core/hle/kernel/k_scheduler.h" | 36 | #include "core/hle/kernel/k_scheduler.h" |
| 37 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 37 | #include "core/hle/kernel/k_shared_memory.h" | 38 | #include "core/hle/kernel/k_shared_memory.h" |
| 38 | #include "core/hle/kernel/k_system_resource.h" | 39 | #include "core/hle/kernel/k_system_resource.h" |
| 39 | #include "core/hle/kernel/k_thread.h" | 40 | #include "core/hle/kernel/k_thread.h" |
| 40 | #include "core/hle/kernel/k_worker_task_manager.h" | 41 | #include "core/hle/kernel/k_worker_task_manager.h" |
| 41 | #include "core/hle/kernel/kernel.h" | 42 | #include "core/hle/kernel/kernel.h" |
| 42 | #include "core/hle/kernel/physical_core.h" | 43 | #include "core/hle/kernel/physical_core.h" |
| 43 | #include "core/hle/kernel/service_thread.h" | ||
| 44 | #include "core/hle/result.h" | 44 | #include "core/hle/result.h" |
| 45 | #include "core/hle/service/server_manager.h" | ||
| 45 | #include "core/hle/service/sm/sm.h" | 46 | #include "core/hle/service/sm/sm.h" |
| 46 | #include "core/memory.h" | 47 | #include "core/memory.h" |
| 47 | 48 | ||
| @@ -55,9 +56,7 @@ struct KernelCore::Impl { | |||
| 55 | static constexpr size_t BlockInfoSlabHeapSize = 4000; | 56 | static constexpr size_t BlockInfoSlabHeapSize = 4000; |
| 56 | static constexpr size_t ReservedDynamicPageCount = 64; | 57 | static constexpr size_t ReservedDynamicPageCount = 64; |
| 57 | 58 | ||
| 58 | explicit Impl(Core::System& system_, KernelCore& kernel_) | 59 | explicit Impl(Core::System& system_, KernelCore& kernel_) : system{system_} {} |
| 59 | : service_threads_manager{1, "ServiceThreadsManager"}, | ||
| 60 | service_thread_barrier{2}, system{system_} {} | ||
| 61 | 60 | ||
| 62 | void SetMulticore(bool is_multi) { | 61 | void SetMulticore(bool is_multi) { |
| 63 | is_multicore = is_multi; | 62 | is_multicore = is_multi; |
| @@ -98,8 +97,6 @@ struct KernelCore::Impl { | |||
| 98 | 97 | ||
| 99 | InitializeHackSharedMemory(); | 98 | InitializeHackSharedMemory(); |
| 100 | RegisterHostThread(nullptr); | 99 | RegisterHostThread(nullptr); |
| 101 | |||
| 102 | default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread"); | ||
| 103 | } | 100 | } |
| 104 | 101 | ||
| 105 | void InitializeCores() { | 102 | void InitializeCores() { |
| @@ -140,11 +137,6 @@ struct KernelCore::Impl { | |||
| 140 | 137 | ||
| 141 | preemption_event = nullptr; | 138 | preemption_event = nullptr; |
| 142 | 139 | ||
| 143 | for (auto& iter : named_ports) { | ||
| 144 | iter.second->Close(); | ||
| 145 | } | ||
| 146 | named_ports.clear(); | ||
| 147 | |||
| 148 | exclusive_monitor.reset(); | 140 | exclusive_monitor.reset(); |
| 149 | 141 | ||
| 150 | // Cleanup persistent kernel objects | 142 | // Cleanup persistent kernel objects |
| @@ -207,8 +199,9 @@ struct KernelCore::Impl { | |||
| 207 | } | 199 | } |
| 208 | 200 | ||
| 209 | void CloseServices() { | 201 | void CloseServices() { |
| 210 | // Ensures all service threads gracefully shutdown. | 202 | // Ensures all servers gracefully shutdown. |
| 211 | ClearServiceThreads(); | 203 | std::scoped_lock lk{server_lock}; |
| 204 | server_managers.clear(); | ||
| 212 | } | 205 | } |
| 213 | 206 | ||
| 214 | void InitializePhysicalCores() { | 207 | void InitializePhysicalCores() { |
| @@ -761,55 +754,6 @@ struct KernelCore::Impl { | |||
| 761 | "HidBus:SharedMemory"); | 754 | "HidBus:SharedMemory"); |
| 762 | } | 755 | } |
| 763 | 756 | ||
| 764 | KClientPort* CreateNamedServicePort(std::string name) { | ||
| 765 | auto search = service_interface_factory.find(name); | ||
| 766 | if (search == service_interface_factory.end()) { | ||
| 767 | UNIMPLEMENTED(); | ||
| 768 | return {}; | ||
| 769 | } | ||
| 770 | |||
| 771 | return &search->second(system.ServiceManager(), system); | ||
| 772 | } | ||
| 773 | |||
| 774 | void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) { | ||
| 775 | auto search = service_interface_handlers.find(name); | ||
| 776 | if (search == service_interface_handlers.end()) { | ||
| 777 | return; | ||
| 778 | } | ||
| 779 | |||
| 780 | search->second(system.ServiceManager(), server_port); | ||
| 781 | } | ||
| 782 | |||
| 783 | Kernel::ServiceThread& CreateServiceThread(KernelCore& kernel, const std::string& name) { | ||
| 784 | auto* ptr = new ServiceThread(kernel, name); | ||
| 785 | |||
| 786 | service_threads_manager.QueueWork( | ||
| 787 | [this, ptr]() { service_threads.emplace(ptr, std::unique_ptr<ServiceThread>(ptr)); }); | ||
| 788 | |||
| 789 | return *ptr; | ||
| 790 | } | ||
| 791 | |||
| 792 | void ReleaseServiceThread(Kernel::ServiceThread& service_thread) { | ||
| 793 | auto* ptr = &service_thread; | ||
| 794 | |||
| 795 | if (ptr == default_service_thread) { | ||
| 796 | // Nothing to do here, the service is using default_service_thread, which will be | ||
| 797 | // released on shutdown. | ||
| 798 | return; | ||
| 799 | } | ||
| 800 | |||
| 801 | service_threads_manager.QueueWork([this, ptr]() { service_threads.erase(ptr); }); | ||
| 802 | } | ||
| 803 | |||
| 804 | void ClearServiceThreads() { | ||
| 805 | service_threads_manager.QueueWork([this] { | ||
| 806 | service_threads.clear(); | ||
| 807 | default_service_thread = nullptr; | ||
| 808 | service_thread_barrier.Sync(); | ||
| 809 | }); | ||
| 810 | service_thread_barrier.Sync(); | ||
| 811 | } | ||
| 812 | |||
| 813 | std::mutex registered_objects_lock; | 757 | std::mutex registered_objects_lock; |
| 814 | std::mutex registered_in_use_objects_lock; | 758 | std::mutex registered_in_use_objects_lock; |
| 815 | 759 | ||
| @@ -839,14 +783,12 @@ struct KernelCore::Impl { | |||
| 839 | 783 | ||
| 840 | std::unique_ptr<KObjectNameGlobalData> object_name_global_data; | 784 | std::unique_ptr<KObjectNameGlobalData> object_name_global_data; |
| 841 | 785 | ||
| 842 | /// Map of named ports managed by the kernel, which can be retrieved using | ||
| 843 | /// the ConnectToPort SVC. | ||
| 844 | std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; | ||
| 845 | std::unordered_map<std::string, ServiceInterfaceHandlerFn> service_interface_handlers; | ||
| 846 | NamedPortTable named_ports; | ||
| 847 | std::unordered_set<KAutoObject*> registered_objects; | 786 | std::unordered_set<KAutoObject*> registered_objects; |
| 848 | std::unordered_set<KAutoObject*> registered_in_use_objects; | 787 | std::unordered_set<KAutoObject*> registered_in_use_objects; |
| 849 | 788 | ||
| 789 | std::mutex server_lock; | ||
| 790 | std::vector<std::unique_ptr<Service::ServerManager>> server_managers; | ||
| 791 | |||
| 850 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | 792 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; |
| 851 | std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; | 793 | std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; |
| 852 | 794 | ||
| @@ -881,12 +823,6 @@ struct KernelCore::Impl { | |||
| 881 | // Memory layout | 823 | // Memory layout |
| 882 | std::unique_ptr<KMemoryLayout> memory_layout; | 824 | std::unique_ptr<KMemoryLayout> memory_layout; |
| 883 | 825 | ||
| 884 | // Threads used for services | ||
| 885 | std::unordered_map<ServiceThread*, std::unique_ptr<ServiceThread>> service_threads; | ||
| 886 | ServiceThread* default_service_thread{}; | ||
| 887 | Common::ThreadWorker service_threads_manager; | ||
| 888 | Common::Barrier service_thread_barrier; | ||
| 889 | |||
| 890 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads{}; | 826 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads{}; |
| 891 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 827 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| 892 | 828 | ||
| @@ -1050,23 +986,6 @@ void KernelCore::PrepareReschedule(std::size_t id) { | |||
| 1050 | // TODO: Reimplement, this | 986 | // TODO: Reimplement, this |
| 1051 | } | 987 | } |
| 1052 | 988 | ||
| 1053 | void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) { | ||
| 1054 | impl->service_interface_factory.emplace(std::move(name), factory); | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | void KernelCore::RegisterInterfaceForNamedService(std::string name, | ||
| 1058 | ServiceInterfaceHandlerFn&& handler) { | ||
| 1059 | impl->service_interface_handlers.emplace(std::move(name), handler); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | KClientPort* KernelCore::CreateNamedServicePort(std::string name) { | ||
| 1063 | return impl->CreateNamedServicePort(std::move(name)); | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) { | ||
| 1067 | impl->RegisterNamedServiceHandler(std::move(name), server_port); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | void KernelCore::RegisterKernelObject(KAutoObject* object) { | 989 | void KernelCore::RegisterKernelObject(KAutoObject* object) { |
| 1071 | std::scoped_lock lk{impl->registered_objects_lock}; | 990 | std::scoped_lock lk{impl->registered_objects_lock}; |
| 1072 | impl->registered_objects.insert(object); | 991 | impl->registered_objects.insert(object); |
| @@ -1087,8 +1006,19 @@ void KernelCore::UnregisterInUseObject(KAutoObject* object) { | |||
| 1087 | impl->registered_in_use_objects.erase(object); | 1006 | impl->registered_in_use_objects.erase(object); |
| 1088 | } | 1007 | } |
| 1089 | 1008 | ||
| 1090 | bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { | 1009 | void KernelCore::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) { |
| 1091 | return port != impl->named_ports.cend(); | 1010 | auto* manager = server_manager.get(); |
| 1011 | |||
| 1012 | { | ||
| 1013 | std::scoped_lock lk{impl->server_lock}; | ||
| 1014 | if (impl->is_shutting_down) { | ||
| 1015 | return; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | impl->server_managers.emplace_back(std::move(server_manager)); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | manager->LoopProcess(); | ||
| 1092 | } | 1022 | } |
| 1093 | 1023 | ||
| 1094 | u32 KernelCore::CreateNewObjectID() { | 1024 | u32 KernelCore::CreateNewObjectID() { |
| @@ -1127,6 +1057,87 @@ void KernelCore::RegisterHostThread(KThread* existing_thread) { | |||
| 1127 | } | 1057 | } |
| 1128 | } | 1058 | } |
| 1129 | 1059 | ||
| 1060 | static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process, | ||
| 1061 | std::string&& thread_name, std::function<void()>&& func) { | ||
| 1062 | // Reserve a new thread from the process resource limit. | ||
| 1063 | KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax); | ||
| 1064 | ASSERT(thread_reservation.Succeeded()); | ||
| 1065 | |||
| 1066 | // Initialize the thread. | ||
| 1067 | KThread* thread = KThread::Create(kernel); | ||
| 1068 | ASSERT(R_SUCCEEDED(KThread::InitializeDummyThread(thread, process))); | ||
| 1069 | |||
| 1070 | // Commit the thread reservation. | ||
| 1071 | thread_reservation.Commit(); | ||
| 1072 | |||
| 1073 | return std::jthread( | ||
| 1074 | [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] { | ||
| 1075 | // Set the thread name. | ||
| 1076 | Common::SetCurrentThreadName(thread_name.c_str()); | ||
| 1077 | |||
| 1078 | // Register the thread. | ||
| 1079 | kernel.RegisterHostThread(thread); | ||
| 1080 | |||
| 1081 | // Run the callback. | ||
| 1082 | func(); | ||
| 1083 | |||
| 1084 | // Close the thread. | ||
| 1085 | // This will free the process if it is the last reference. | ||
| 1086 | thread->Close(); | ||
| 1087 | }); | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name, | ||
| 1091 | std::function<void()> func) { | ||
| 1092 | // Make a new process. | ||
| 1093 | KProcess* process = KProcess::Create(*this); | ||
| 1094 | ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland, | ||
| 1095 | GetSystemResourceLimit()))); | ||
| 1096 | |||
| 1097 | // Ensure that we don't hold onto any extra references. | ||
| 1098 | SCOPE_EXIT({ process->Close(); }); | ||
| 1099 | |||
| 1100 | // Run the host thread. | ||
| 1101 | return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func)); | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | std::jthread KernelCore::RunOnHostCoreThread(std::string&& thread_name, | ||
| 1105 | std::function<void()> func) { | ||
| 1106 | // Get the current process. | ||
| 1107 | KProcess* process = GetCurrentProcessPointer(*this); | ||
| 1108 | |||
| 1109 | // Run the host thread. | ||
| 1110 | return RunHostThreadFunc(*this, process, std::move(thread_name), std::move(func)); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function<void()> func) { | ||
| 1114 | constexpr s32 ServiceThreadPriority = 16; | ||
| 1115 | constexpr s32 ServiceThreadCore = 3; | ||
| 1116 | |||
| 1117 | // Make a new process. | ||
| 1118 | KProcess* process = KProcess::Create(*this); | ||
| 1119 | ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland, | ||
| 1120 | GetSystemResourceLimit()))); | ||
| 1121 | |||
| 1122 | // Ensure that we don't hold onto any extra references. | ||
| 1123 | SCOPE_EXIT({ process->Close(); }); | ||
| 1124 | |||
| 1125 | // Reserve a new thread from the process resource limit. | ||
| 1126 | KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax); | ||
| 1127 | ASSERT(thread_reservation.Succeeded()); | ||
| 1128 | |||
| 1129 | // Initialize the thread. | ||
| 1130 | KThread* thread = KThread::Create(*this); | ||
| 1131 | ASSERT(R_SUCCEEDED(KThread::InitializeServiceThread( | ||
| 1132 | System(), thread, std::move(func), ServiceThreadPriority, ServiceThreadCore, process))); | ||
| 1133 | |||
| 1134 | // Commit the thread reservation. | ||
| 1135 | thread_reservation.Commit(); | ||
| 1136 | |||
| 1137 | // Begin running the thread. | ||
| 1138 | ASSERT(R_SUCCEEDED(thread->Run())); | ||
| 1139 | } | ||
| 1140 | |||
| 1130 | u32 KernelCore::GetCurrentHostThreadID() const { | 1141 | u32 KernelCore::GetCurrentHostThreadID() const { |
| 1131 | return impl->GetCurrentHostThreadID(); | 1142 | return impl->GetCurrentHostThreadID(); |
| 1132 | } | 1143 | } |
| @@ -1271,18 +1282,6 @@ void KernelCore::ExitSVCProfile() { | |||
| 1271 | MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]); | 1282 | MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]); |
| 1272 | } | 1283 | } |
| 1273 | 1284 | ||
| 1274 | Kernel::ServiceThread& KernelCore::CreateServiceThread(const std::string& name) { | ||
| 1275 | return impl->CreateServiceThread(*this, name); | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | Kernel::ServiceThread& KernelCore::GetDefaultServiceThread() const { | ||
| 1279 | return *impl->default_service_thread; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | void KernelCore::ReleaseServiceThread(Kernel::ServiceThread& service_thread) { | ||
| 1283 | impl->ReleaseServiceThread(service_thread); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { | 1285 | Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { |
| 1287 | return impl->slab_resource_counts; | 1286 | return impl->slab_resource_counts; |
| 1288 | } | 1287 | } |