summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp30
-rw-r--r--src/core/hle/kernel/hle_ipc.h34
-rw-r--r--src/core/hle/kernel/k_process.cpp4
-rw-r--r--src/core/hle/kernel/k_thread.cpp20
-rw-r--r--src/core/hle/kernel/k_thread.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp207
-rw-r--r--src/core/hle/kernel/kernel.h69
-rw-r--r--src/core/hle/kernel/service_thread.cpp206
-rw-r--r--src/core/hle/kernel/service_thread.h29
-rw-r--r--src/core/hle/kernel/svc/svc_info.cpp5
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp51
11 files changed, 180 insertions, 479 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 494151eef..876fbbe53 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -21,36 +21,18 @@
21#include "core/hle/kernel/k_server_session.h" 21#include "core/hle/kernel/k_server_session.h"
22#include "core/hle/kernel/k_thread.h" 22#include "core/hle/kernel/k_thread.h"
23#include "core/hle/kernel/kernel.h" 23#include "core/hle/kernel/kernel.h"
24#include "core/hle/kernel/service_thread.h"
25#include "core/memory.h" 24#include "core/memory.h"
26 25
27namespace Kernel { 26namespace Kernel {
28 27
29SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_, 28SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_)
30 ServiceThreadType thread_type) 29 : kernel{kernel_} {}
31 : kernel{kernel_}, service_thread{thread_type == ServiceThreadType::CreateNew
32 ? kernel.CreateServiceThread(service_name_)
33 : kernel.GetDefaultServiceThread()} {}
34 30
35SessionRequestHandler::~SessionRequestHandler() { 31SessionRequestHandler::~SessionRequestHandler() = default;
36 kernel.ReleaseServiceThread(service_thread);
37}
38
39void SessionRequestHandler::AcceptSession(KServerPort* server_port) {
40 auto* server_session = server_port->AcceptSession();
41 ASSERT(server_session != nullptr);
42
43 RegisterSession(server_session, std::make_shared<SessionRequestManager>(kernel));
44}
45
46void SessionRequestHandler::RegisterSession(KServerSession* server_session,
47 std::shared_ptr<SessionRequestManager> manager) {
48 manager->SetSessionHandler(shared_from_this());
49 service_thread.RegisterServerSession(server_session, manager);
50 server_session->Close();
51}
52 32
53SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {} 33SessionRequestManager::SessionRequestManager(KernelCore& kernel_,
34 Service::ServerManager& server_manager_)
35 : kernel{kernel_}, server_manager{server_manager_} {}
54 36
55SessionRequestManager::~SessionRequestManager() = default; 37SessionRequestManager::~SessionRequestManager() = default;
56 38
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 5bf4f171b..059b21991 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -31,12 +31,8 @@ class ResponseBuilder;
31 31
32namespace Service { 32namespace Service {
33class ServiceFrameworkBase; 33class ServiceFrameworkBase;
34} 34class ServerManager;
35 35} // namespace Service
36enum class ServiceThreadType {
37 Default,
38 CreateNew,
39};
40 36
41namespace Kernel { 37namespace Kernel {
42 38
@@ -53,9 +49,6 @@ class KThread;
53class KReadableEvent; 49class KReadableEvent;
54class KSession; 50class KSession;
55class SessionRequestManager; 51class SessionRequestManager;
56class ServiceThread;
57
58enum class ThreadWakeupReason;
59 52
60/** 53/**
61 * Interface implemented by HLE Session handlers. 54 * Interface implemented by HLE Session handlers.
@@ -64,8 +57,7 @@ enum class ThreadWakeupReason;
64 */ 57 */
65class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { 58class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
66public: 59public:
67 SessionRequestHandler(KernelCore& kernel_, const char* service_name_, 60 SessionRequestHandler(KernelCore& kernel_, const char* service_name_);
68 ServiceThreadType thread_type);
69 virtual ~SessionRequestHandler(); 61 virtual ~SessionRequestHandler();
70 62
71 /** 63 /**
@@ -79,17 +71,8 @@ public:
79 virtual Result HandleSyncRequest(Kernel::KServerSession& session, 71 virtual Result HandleSyncRequest(Kernel::KServerSession& session,
80 Kernel::HLERequestContext& context) = 0; 72 Kernel::HLERequestContext& context) = 0;
81 73
82 void AcceptSession(KServerPort* server_port);
83 void RegisterSession(KServerSession* server_session,
84 std::shared_ptr<SessionRequestManager> manager);
85
86 ServiceThread& GetServiceThread() const {
87 return service_thread;
88 }
89
90protected: 74protected:
91 KernelCore& kernel; 75 KernelCore& kernel;
92 ServiceThread& service_thread;
93}; 76};
94 77
95using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>; 78using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>;
@@ -102,7 +85,7 @@ using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
102 */ 85 */
103class SessionRequestManager final { 86class SessionRequestManager final {
104public: 87public:
105 explicit SessionRequestManager(KernelCore& kernel); 88 explicit SessionRequestManager(KernelCore& kernel, Service::ServerManager& server_manager);
106 ~SessionRequestManager(); 89 ~SessionRequestManager();
107 90
108 bool IsDomain() const { 91 bool IsDomain() const {
@@ -155,15 +138,15 @@ public:
155 session_handler = std::move(handler); 138 session_handler = std::move(handler);
156 } 139 }
157 140
158 ServiceThread& GetServiceThread() const {
159 return session_handler->GetServiceThread();
160 }
161
162 bool HasSessionRequestHandler(const HLERequestContext& context) const; 141 bool HasSessionRequestHandler(const HLERequestContext& context) const;
163 142
164 Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context); 143 Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context);
165 Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context); 144 Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context);
166 145
146 Service::ServerManager& GetServerManager() {
147 return server_manager;
148 }
149
167private: 150private:
168 bool convert_to_domain{}; 151 bool convert_to_domain{};
169 bool is_domain{}; 152 bool is_domain{};
@@ -172,6 +155,7 @@ private:
172 155
173private: 156private:
174 KernelCore& kernel; 157 KernelCore& kernel;
158 Service::ServerManager& server_manager;
175}; 159};
176 160
177/** 161/**
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 0e4283a0c..d9c1a0eb3 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -119,7 +119,6 @@ void KProcess::DecrementRunningThreadCount() {
119 119
120 if (const auto prev = num_running_threads--; prev == 1) { 120 if (const auto prev = num_running_threads--; prev == 1) {
121 // TODO(bunnei): Process termination to be implemented when multiprocess is supported. 121 // TODO(bunnei): Process termination to be implemented when multiprocess is supported.
122 UNIMPLEMENTED_MSG("KProcess termination is not implemennted!");
123 } 122 }
124} 123}
125 124
@@ -357,9 +356,6 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
357 system_resource_size = metadata.GetSystemResourceSize(); 356 system_resource_size = metadata.GetSystemResourceSize();
358 image_size = code_size; 357 image_size = code_size;
359 358
360 // We currently do not support process-specific system resource
361 UNIMPLEMENTED_IF(system_resource_size != 0);
362
363 KScopedResourceReservation memory_reservation( 359 KScopedResourceReservation memory_reservation(
364 resource_limit, LimitableResource::PhysicalMemoryMax, code_size + system_resource_size); 360 resource_limit, LimitableResource::PhysicalMemoryMax, code_size + system_resource_size);
365 if (!memory_reservation.Succeeded()) { 361 if (!memory_reservation.Succeeded()) {
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 2d3da9d66..599d05947 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -29,6 +29,7 @@
29#include "core/hle/kernel/k_thread_queue.h" 29#include "core/hle/kernel/k_thread_queue.h"
30#include "core/hle/kernel/k_worker_task_manager.h" 30#include "core/hle/kernel/k_worker_task_manager.h"
31#include "core/hle/kernel/kernel.h" 31#include "core/hle/kernel/kernel.h"
32#include "core/hle/kernel/svc.h"
32#include "core/hle/kernel/svc_results.h" 33#include "core/hle/kernel/svc_results.h"
33#include "core/hle/kernel/svc_types.h" 34#include "core/hle/kernel/svc_types.h"
34#include "core/hle/result.h" 35#include "core/hle/result.h"
@@ -298,6 +299,25 @@ Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThr
298 ThreadType::User, system.GetCpuManager().GetGuestThreadFunc())); 299 ThreadType::User, system.GetCpuManager().GetGuestThreadFunc()));
299} 300}
300 301
302Result KThread::InitializeServiceThread(Core::System& system, KThread* thread,
303 std::function<void()>&& func, s32 prio, s32 virt_core,
304 KProcess* owner) {
305 system.Kernel().GlobalSchedulerContext().AddThread(thread);
306 std::function<void()> func2{[&system, func{std::move(func)}] {
307 // Similar to UserModeThreadStarter.
308 system.Kernel().CurrentScheduler()->OnThreadStart();
309
310 // Run the guest function.
311 func();
312
313 // Exit.
314 Svc::ExitThread(system);
315 }};
316
317 R_RETURN(InitializeThread(thread, {}, {}, {}, prio, virt_core, owner, ThreadType::HighPriority,
318 std::move(func2)));
319}
320
301void KThread::PostDestroy(uintptr_t arg) { 321void KThread::PostDestroy(uintptr_t arg) {
302 KProcess* owner = reinterpret_cast<KProcess*>(arg & ~1ULL); 322 KProcess* owner = reinterpret_cast<KProcess*>(arg & ~1ULL);
303 const bool resource_limit_release_hint = (arg & 1); 323 const bool resource_limit_release_hint = (arg & 1);
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index ca82ce3b6..a04de21bc 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -434,6 +434,10 @@ public:
434 VAddr user_stack_top, s32 prio, s32 virt_core, 434 VAddr user_stack_top, s32 prio, s32 virt_core,
435 KProcess* owner); 435 KProcess* owner);
436 436
437 [[nodiscard]] static Result InitializeServiceThread(Core::System& system, KThread* thread,
438 std::function<void()>&& thread_func,
439 s32 prio, s32 virt_core, KProcess* owner);
440
437public: 441public:
438 struct StackParameters { 442 struct StackParameters {
439 u8 svc_permission[0x10]; 443 u8 svc_permission[0x10];
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
1053void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) {
1054 impl->service_interface_factory.emplace(std::move(name), factory);
1055}
1056
1057void KernelCore::RegisterInterfaceForNamedService(std::string name,
1058 ServiceInterfaceHandlerFn&& handler) {
1059 impl->service_interface_handlers.emplace(std::move(name), handler);
1060}
1061
1062KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
1063 return impl->CreateNamedServicePort(std::move(name));
1064}
1065
1066void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
1067 impl->RegisterNamedServiceHandler(std::move(name), server_port);
1068}
1069
1070void KernelCore::RegisterKernelObject(KAutoObject* object) { 989void 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
1090bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { 1009void 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
1094u32 KernelCore::CreateNewObjectID() { 1024u32 KernelCore::CreateNewObjectID() {
@@ -1127,6 +1057,87 @@ void KernelCore::RegisterHostThread(KThread* existing_thread) {
1127 } 1057 }
1128} 1058}
1129 1059
1060static 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
1090std::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
1104std::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
1113void 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
1130u32 KernelCore::GetCurrentHostThreadID() const { 1141u32 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
1274Kernel::ServiceThread& KernelCore::CreateServiceThread(const std::string& name) {
1275 return impl->CreateServiceThread(*this, name);
1276}
1277
1278Kernel::ServiceThread& KernelCore::GetDefaultServiceThread() const {
1279 return *impl->default_service_thread;
1280}
1281
1282void KernelCore::ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
1283 impl->ReleaseServiceThread(service_thread);
1284}
1285
1286Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { 1285Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {
1287 return impl->slab_resource_counts; 1286 return impl->slab_resource_counts;
1288} 1287}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 6e0668f7f..4449f6949 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -9,6 +9,8 @@
9#include <string> 9#include <string>
10#include <unordered_map> 10#include <unordered_map>
11#include <vector> 11#include <vector>
12
13#include "common/polyfill_thread.h"
12#include "core/hardware_properties.h" 14#include "core/hardware_properties.h"
13#include "core/hle/kernel/k_auto_object.h" 15#include "core/hle/kernel/k_auto_object.h"
14#include "core/hle/kernel/k_slab_heap.h" 16#include "core/hle/kernel/k_slab_heap.h"
@@ -24,6 +26,10 @@ class CoreTiming;
24struct EventType; 26struct EventType;
25} // namespace Core::Timing 27} // namespace Core::Timing
26 28
29namespace Service {
30class ServerManager;
31}
32
27namespace Service::SM { 33namespace Service::SM {
28class ServiceManager; 34class ServiceManager;
29} 35}
@@ -65,13 +71,6 @@ class KTransferMemory;
65class KWorkerTaskManager; 71class KWorkerTaskManager;
66class KCodeMemory; 72class KCodeMemory;
67class PhysicalCore; 73class PhysicalCore;
68class ServiceThread;
69class Synchronization;
70
71using ServiceInterfaceFactory =
72 std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
73
74using ServiceInterfaceHandlerFn = std::function<void(Service::SM::ServiceManager&, KServerPort*)>;
75 74
76namespace Init { 75namespace Init {
77struct KSlabResourceCounts; 76struct KSlabResourceCounts;
@@ -80,15 +79,8 @@ struct KSlabResourceCounts;
80template <typename T> 79template <typename T>
81class KSlabHeap; 80class KSlabHeap;
82 81
83using EmuThreadHandle = uintptr_t;
84constexpr EmuThreadHandle EmuThreadHandleInvalid{};
85constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
86
87/// Represents a single instance of the kernel. 82/// Represents a single instance of the kernel.
88class KernelCore { 83class KernelCore {
89private:
90 using NamedPortTable = std::unordered_map<std::string, KClientPort*>;
91
92public: 84public:
93 /// Constructs an instance of the kernel using the given System 85 /// Constructs an instance of the kernel using the given System
94 /// instance as a context for any necessary system-related state, 86 /// instance as a context for any necessary system-related state,
@@ -196,18 +188,6 @@ public:
196 188
197 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); 189 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
198 190
199 /// Registers a named HLE service, passing a factory used to open a port to that service.
200 void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
201
202 /// Registers a setup function for the named HLE service.
203 void RegisterInterfaceForNamedService(std::string name, ServiceInterfaceHandlerFn&& handler);
204
205 /// Opens a port to a service previously registered with RegisterNamedService.
206 KClientPort* CreateNamedServicePort(std::string name);
207
208 /// Accepts a session on a port created by CreateNamedServicePort.
209 void RegisterNamedServiceHandler(std::string name, KServerPort* server_port);
210
211 /// Registers all kernel objects with the global emulation state, this is purely for tracking 191 /// Registers all kernel objects with the global emulation state, this is purely for tracking
212 /// leaks after emulation has been shutdown. 192 /// leaks after emulation has been shutdown.
213 void RegisterKernelObject(KAutoObject* object); 193 void RegisterKernelObject(KAutoObject* object);
@@ -224,8 +204,8 @@ public:
224 /// destroyed during the current emulation session. 204 /// destroyed during the current emulation session.
225 void UnregisterInUseObject(KAutoObject* object); 205 void UnregisterInUseObject(KAutoObject* object);
226 206
227 /// Determines whether or not the given port is a valid named port. 207 // Runs the given server manager until shutdown.
228 bool IsValidNamedPort(NamedPortTable::const_iterator port) const; 208 void RunServer(std::unique_ptr<Service::ServerManager>&& server_manager);
229 209
230 /// Gets the current host_thread/guest_thread pointer. 210 /// Gets the current host_thread/guest_thread pointer.
231 KThread* GetCurrentEmuThread() const; 211 KThread* GetCurrentEmuThread() const;
@@ -242,6 +222,12 @@ public:
242 /// Register the current thread as a non CPU core thread. 222 /// Register the current thread as a non CPU core thread.
243 void RegisterHostThread(KThread* existing_thread = nullptr); 223 void RegisterHostThread(KThread* existing_thread = nullptr);
244 224
225 void RunOnGuestCoreProcess(std::string&& process_name, std::function<void()> func);
226
227 std::jthread RunOnHostCoreProcess(std::string&& process_name, std::function<void()> func);
228
229 std::jthread RunOnHostCoreThread(std::string&& thread_name, std::function<void()> func);
230
245 /// Gets global data for KObjectName. 231 /// Gets global data for KObjectName.
246 KObjectNameGlobalData& ObjectNameGlobalData(); 232 KObjectNameGlobalData& ObjectNameGlobalData();
247 233
@@ -310,33 +296,6 @@ public:
310 296
311 void ExitSVCProfile(); 297 void ExitSVCProfile();
312 298
313 /**
314 * Creates a host thread to execute HLE service requests, which are used to execute service
315 * routines asynchronously. While these are allocated per ServerSession, these need to be owned
316 * and managed outside of ServerSession to avoid a circular dependency. In general, most
317 * services can just use the default service thread, and not need their own host service thread.
318 * See GetDefaultServiceThread.
319 * @param name String name for the ServerSession creating this thread, used for debug
320 * purposes.
321 * @returns A reference to the newly created service thread.
322 */
323 Kernel::ServiceThread& CreateServiceThread(const std::string& name);
324
325 /**
326 * Gets the default host service thread, which executes HLE service requests. Unless service
327 * requests need to block on the host, the default service thread should be used in favor of
328 * creating a new service thread.
329 * @returns A reference to the default service thread.
330 */
331 Kernel::ServiceThread& GetDefaultServiceThread() const;
332
333 /**
334 * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
335 * the ServerSession associated with the thread is destroyed.
336 * @param service_thread Service thread to release.
337 */
338 void ReleaseServiceThread(Kernel::ServiceThread& service_thread);
339
340 /// Workaround for single-core mode when preempting threads while idle. 299 /// Workaround for single-core mode when preempting threads while idle.
341 bool IsPhantomModeForSingleCore() const; 300 bool IsPhantomModeForSingleCore() const;
342 void SetIsPhantomModeForSingleCore(bool value); 301 void SetIsPhantomModeForSingleCore(bool value);
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
deleted file mode 100644
index 38afa720b..000000000
--- a/src/core/hle/kernel/service_thread.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <functional>
5#include <map>
6#include <mutex>
7#include <thread>
8#include <vector>
9
10#include "common/polyfill_thread.h"
11#include "common/scope_exit.h"
12#include "common/thread.h"
13#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/hle_ipc.h"
15#include "core/hle/kernel/k_event.h"
16#include "core/hle/kernel/k_scoped_resource_reservation.h"
17#include "core/hle/kernel/k_session.h"
18#include "core/hle/kernel/k_thread.h"
19#include "core/hle/kernel/kernel.h"
20#include "core/hle/kernel/service_thread.h"
21
22namespace Kernel {
23
24class ServiceThread::Impl final {
25public:
26 explicit Impl(KernelCore& kernel, const std::string& service_name);
27 ~Impl();
28
29 void WaitAndProcessImpl();
30 void SessionClosed(KServerSession* server_session,
31 std::shared_ptr<SessionRequestManager> manager);
32 void LoopProcess();
33
34 void RegisterServerSession(KServerSession* session,
35 std::shared_ptr<SessionRequestManager> manager);
36
37private:
38 KernelCore& kernel;
39 const std::string m_service_name;
40
41 std::jthread m_host_thread{};
42 std::mutex m_session_mutex{};
43 std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{};
44 KEvent* m_wakeup_event{};
45 KThread* m_thread{};
46 std::atomic<bool> m_shutdown_requested{};
47};
48
49void ServiceThread::Impl::WaitAndProcessImpl() {
50 // Create local list of waitable sessions.
51 std::vector<KSynchronizationObject*> objs;
52 std::vector<std::shared_ptr<SessionRequestManager>> managers;
53
54 {
55 // Lock to get the set.
56 std::scoped_lock lk{m_session_mutex};
57
58 // Reserve the needed quantity.
59 objs.reserve(m_sessions.size() + 1);
60 managers.reserve(m_sessions.size());
61
62 // Copy to our local list.
63 for (const auto& [session, manager] : m_sessions) {
64 objs.push_back(session);
65 managers.push_back(manager);
66 }
67
68 // Insert the wakeup event at the end.
69 objs.push_back(&m_wakeup_event->GetReadableEvent());
70 }
71
72 // Wait on the list of sessions.
73 s32 index{-1};
74 Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(),
75 static_cast<s32>(objs.size()), -1);
76 ASSERT(!rc.IsFailure());
77
78 // If this was the wakeup event, clear it and finish.
79 if (index >= static_cast<s64>(objs.size() - 1)) {
80 m_wakeup_event->Clear();
81 return;
82 }
83
84 // This event is from a server session.
85 auto* server_session = static_cast<KServerSession*>(objs[index]);
86 auto& manager = managers[index];
87
88 // Fetch the HLE request context.
89 std::shared_ptr<HLERequestContext> context;
90 rc = server_session->ReceiveRequest(&context, manager);
91
92 // If the session was closed, handle that.
93 if (rc == ResultSessionClosed) {
94 SessionClosed(server_session, manager);
95
96 // Finish.
97 return;
98 }
99
100 // TODO: handle other cases
101 ASSERT(rc == ResultSuccess);
102
103 // Perform the request.
104 Result service_rc = manager->CompleteSyncRequest(server_session, *context);
105
106 // Reply to the client.
107 rc = server_session->SendReplyHLE();
108
109 if (rc == ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) {
110 SessionClosed(server_session, manager);
111 return;
112 }
113
114 // TODO: handle other cases
115 ASSERT(rc == ResultSuccess);
116 ASSERT(service_rc == ResultSuccess);
117}
118
119void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
120 std::shared_ptr<SessionRequestManager> manager) {
121 {
122 // Lock to get the set.
123 std::scoped_lock lk{m_session_mutex};
124
125 // Erase the session.
126 ASSERT(m_sessions.erase(server_session) == 1);
127 }
128
129 // Close our reference to the server session.
130 server_session->Close();
131}
132
133void ServiceThread::Impl::LoopProcess() {
134 Common::SetCurrentThreadName(m_service_name.c_str());
135
136 kernel.RegisterHostThread(m_thread);
137
138 while (!m_shutdown_requested.load()) {
139 WaitAndProcessImpl();
140 }
141}
142
143void ServiceThread::Impl::RegisterServerSession(KServerSession* server_session,
144 std::shared_ptr<SessionRequestManager> manager) {
145 // Open the server session.
146 server_session->Open();
147
148 {
149 // Lock to get the set.
150 std::scoped_lock lk{m_session_mutex};
151
152 // Insert the session and manager.
153 m_sessions[server_session] = manager;
154 }
155
156 // Signal the wakeup event.
157 m_wakeup_event->Signal();
158}
159
160ServiceThread::Impl::~Impl() {
161 // Shut down the processing thread.
162 m_shutdown_requested.store(true);
163 m_wakeup_event->Signal();
164 m_host_thread.join();
165
166 // Close all remaining sessions.
167 for (const auto& [server_session, manager] : m_sessions) {
168 server_session->Close();
169 }
170
171 // Destroy remaining managers.
172 m_sessions.clear();
173
174 // Close event.
175 m_wakeup_event->GetReadableEvent().Close();
176 m_wakeup_event->Close();
177
178 // Close thread.
179 m_thread->Close();
180}
181
182ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
183 : kernel{kernel_}, m_service_name{service_name} {
184 // Initialize event.
185 m_wakeup_event = KEvent::Create(kernel);
186 m_wakeup_event->Initialize(nullptr);
187
188 // Initialize thread.
189 m_thread = KThread::Create(kernel);
190 ASSERT(KThread::InitializeDummyThread(m_thread, nullptr).IsSuccess());
191
192 // Start thread.
193 m_host_thread = std::jthread([this] { LoopProcess(); });
194}
195
196ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)
197 : impl{std::make_unique<Impl>(kernel, name)} {}
198
199ServiceThread::~ServiceThread() = default;
200
201void ServiceThread::RegisterServerSession(KServerSession* session,
202 std::shared_ptr<SessionRequestManager> manager) {
203 impl->RegisterServerSession(session, manager);
204}
205
206} // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h
deleted file mode 100644
index fb4325531..000000000
--- a/src/core/hle/kernel/service_thread.h
+++ /dev/null
@@ -1,29 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <string>
8
9namespace Kernel {
10
11class HLERequestContext;
12class KernelCore;
13class KSession;
14class SessionRequestManager;
15
16class ServiceThread final {
17public:
18 explicit ServiceThread(KernelCore& kernel, const std::string& name);
19 ~ServiceThread();
20
21 void RegisterServerSession(KServerSession* session,
22 std::shared_ptr<SessionRequestManager> manager);
23
24private:
25 class Impl;
26 std::unique_ptr<Impl> impl;
27};
28
29} // namespace Kernel
diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp
index 58dc47508..cbed4dc8c 100644
--- a/src/core/hle/kernel/svc/svc_info.cpp
+++ b/src/core/hle/kernel/svc/svc_info.cpp
@@ -126,6 +126,11 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
126 *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource(); 126 *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource();
127 return ResultSuccess; 127 return ResultSuccess;
128 128
129 case InfoType::IsApplication:
130 LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application");
131 *result = true;
132 return ResultSuccess;
133
129 case InfoType::FreeThreadCount: 134 case InfoType::FreeThreadCount:
130 *result = process->GetFreeThreadCount(); 135 *result = process->GetFreeThreadCount();
131 return ResultSuccess; 136 return ResultSuccess;
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
index 2f9bfcb52..ac095b338 100644
--- a/src/core/hle/kernel/svc/svc_port.cpp
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -12,56 +12,40 @@
12 12
13namespace Kernel::Svc { 13namespace Kernel::Svc {
14 14
15/// Connect to an OS service given the port name, returns the handle to the port to out 15Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr user_name) {
16Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { 16 // Copy the provided name from user memory to kernel memory.
17 auto& memory = system.Memory(); 17 auto string_name = system.Memory().ReadCString(user_name, KObjectName::NameLengthMax);
18 if (!memory.IsValidVirtualAddress(port_name_address)) {
19 LOG_ERROR(Kernel_SVC,
20 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
21 port_name_address);
22 return ResultNotFound;
23 }
24 18
25 static constexpr std::size_t PortNameMaxLength = 11; 19 std::array<char, KObjectName::NameLengthMax> name{};
26 // Read 1 char beyond the max allowed port name to detect names that are too long. 20 std::strncpy(name.data(), string_name.c_str(), KObjectName::NameLengthMax - 1);
27 const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
28 if (port_name.size() > PortNameMaxLength) {
29 LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
30 port_name.size());
31 return ResultOutOfRange;
32 }
33 21
34 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); 22 // Validate that the name is valid.
23 R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange);
35 24
36 // Get the current handle table. 25 // Get the current handle table.
37 auto& kernel = system.Kernel(); 26 auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
38 auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
39 27
40 // Find the client port. 28 // Find the client port.
41 auto port = kernel.CreateNamedServicePort(port_name); 29 auto port = KObjectName::Find<KClientPort>(system.Kernel(), name.data());
42 if (!port) { 30 R_UNLESS(port.IsNotNull(), ResultNotFound);
43 LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
44 return ResultNotFound;
45 }
46 31
47 // Reserve a handle for the port. 32 // Reserve a handle for the port.
48 // NOTE: Nintendo really does write directly to the output handle here. 33 // NOTE: Nintendo really does write directly to the output handle here.
49 R_TRY(handle_table.Reserve(out)); 34 R_TRY(handle_table.Reserve(out));
50 auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); }); 35 ON_RESULT_FAILURE {
36 handle_table.Unreserve(*out);
37 };
51 38
52 // Create a session. 39 // Create a session.
53 KClientSession* session{}; 40 KClientSession* session;
54 R_TRY(port->CreateSession(std::addressof(session))); 41 R_TRY(port->CreateSession(std::addressof(session)));
55 42
56 kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
57
58 // Register the session in the table, close the extra reference. 43 // Register the session in the table, close the extra reference.
59 handle_table.Register(*out, session); 44 handle_table.Register(*out, session);
60 session->Close(); 45 session->Close();
61 46
62 // We succeeded. 47 // We succeeded.
63 handle_guard.Cancel(); 48 R_SUCCEED();
64 return ResultSuccess;
65} 49}
66 50
67Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, 51Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
@@ -78,8 +62,11 @@ Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) {
78Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, 62Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name,
79 int32_t max_sessions) { 63 int32_t max_sessions) {
80 // Copy the provided name from user memory to kernel memory. 64 // Copy the provided name from user memory to kernel memory.
65 auto string_name = system.Memory().ReadCString(user_name, KObjectName::NameLengthMax);
66
67 // Copy the provided name from user memory to kernel memory.
81 std::array<char, KObjectName::NameLengthMax> name{}; 68 std::array<char, KObjectName::NameLengthMax> name{};
82 system.Memory().ReadBlock(user_name, name.data(), sizeof(name)); 69 std::strncpy(name.data(), string_name.c_str(), KObjectName::NameLengthMax - 1);
83 70
84 // Validate that sessions and name are valid. 71 // Validate that sessions and name are valid.
85 R_UNLESS(max_sessions >= 0, ResultOutOfRange); 72 R_UNLESS(max_sessions >= 0, ResultOutOfRange);