diff options
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 30 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 34 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 207 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 69 | ||||
| -rw-r--r-- | src/core/hle/kernel/service_thread.cpp | 206 | ||||
| -rw-r--r-- | src/core/hle/kernel/service_thread.h | 29 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc/svc_info.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc/svc_port.cpp | 51 |
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 | ||
| 27 | namespace Kernel { | 26 | namespace Kernel { |
| 28 | 27 | ||
| 29 | SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_, | 28 | SessionRequestHandler::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 | ||
| 35 | SessionRequestHandler::~SessionRequestHandler() { | 31 | SessionRequestHandler::~SessionRequestHandler() = default; |
| 36 | kernel.ReleaseServiceThread(service_thread); | ||
| 37 | } | ||
| 38 | |||
| 39 | void 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 | |||
| 46 | void 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 | ||
| 53 | SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {} | 33 | SessionRequestManager::SessionRequestManager(KernelCore& kernel_, |
| 34 | Service::ServerManager& server_manager_) | ||
| 35 | : kernel{kernel_}, server_manager{server_manager_} {} | ||
| 54 | 36 | ||
| 55 | SessionRequestManager::~SessionRequestManager() = default; | 37 | SessionRequestManager::~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 | ||
| 32 | namespace Service { | 32 | namespace Service { |
| 33 | class ServiceFrameworkBase; | 33 | class ServiceFrameworkBase; |
| 34 | } | 34 | class ServerManager; |
| 35 | 35 | } // namespace Service | |
| 36 | enum class ServiceThreadType { | ||
| 37 | Default, | ||
| 38 | CreateNew, | ||
| 39 | }; | ||
| 40 | 36 | ||
| 41 | namespace Kernel { | 37 | namespace Kernel { |
| 42 | 38 | ||
| @@ -53,9 +49,6 @@ class KThread; | |||
| 53 | class KReadableEvent; | 49 | class KReadableEvent; |
| 54 | class KSession; | 50 | class KSession; |
| 55 | class SessionRequestManager; | 51 | class SessionRequestManager; |
| 56 | class ServiceThread; | ||
| 57 | |||
| 58 | enum 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 | */ |
| 65 | class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { | 58 | class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { |
| 66 | public: | 59 | public: |
| 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 | |||
| 90 | protected: | 74 | protected: |
| 91 | KernelCore& kernel; | 75 | KernelCore& kernel; |
| 92 | ServiceThread& service_thread; | ||
| 93 | }; | 76 | }; |
| 94 | 77 | ||
| 95 | using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>; | 78 | using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>; |
| @@ -102,7 +85,7 @@ using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; | |||
| 102 | */ | 85 | */ |
| 103 | class SessionRequestManager final { | 86 | class SessionRequestManager final { |
| 104 | public: | 87 | public: |
| 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 | |||
| 167 | private: | 150 | private: |
| 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 | ||
| 173 | private: | 156 | private: |
| 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 | ||
| 302 | Result 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 | |||
| 301 | void KThread::PostDestroy(uintptr_t arg) { | 321 | void 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 | |||
| 437 | public: | 441 | public: |
| 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 | ||
| 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 | } |
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; | |||
| 24 | struct EventType; | 26 | struct EventType; |
| 25 | } // namespace Core::Timing | 27 | } // namespace Core::Timing |
| 26 | 28 | ||
| 29 | namespace Service { | ||
| 30 | class ServerManager; | ||
| 31 | } | ||
| 32 | |||
| 27 | namespace Service::SM { | 33 | namespace Service::SM { |
| 28 | class ServiceManager; | 34 | class ServiceManager; |
| 29 | } | 35 | } |
| @@ -65,13 +71,6 @@ class KTransferMemory; | |||
| 65 | class KWorkerTaskManager; | 71 | class KWorkerTaskManager; |
| 66 | class KCodeMemory; | 72 | class KCodeMemory; |
| 67 | class PhysicalCore; | 73 | class PhysicalCore; |
| 68 | class ServiceThread; | ||
| 69 | class Synchronization; | ||
| 70 | |||
| 71 | using ServiceInterfaceFactory = | ||
| 72 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; | ||
| 73 | |||
| 74 | using ServiceInterfaceHandlerFn = std::function<void(Service::SM::ServiceManager&, KServerPort*)>; | ||
| 75 | 74 | ||
| 76 | namespace Init { | 75 | namespace Init { |
| 77 | struct KSlabResourceCounts; | 76 | struct KSlabResourceCounts; |
| @@ -80,15 +79,8 @@ struct KSlabResourceCounts; | |||
| 80 | template <typename T> | 79 | template <typename T> |
| 81 | class KSlabHeap; | 80 | class KSlabHeap; |
| 82 | 81 | ||
| 83 | using EmuThreadHandle = uintptr_t; | ||
| 84 | constexpr EmuThreadHandle EmuThreadHandleInvalid{}; | ||
| 85 | constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63}; | ||
| 86 | |||
| 87 | /// Represents a single instance of the kernel. | 82 | /// Represents a single instance of the kernel. |
| 88 | class KernelCore { | 83 | class KernelCore { |
| 89 | private: | ||
| 90 | using NamedPortTable = std::unordered_map<std::string, KClientPort*>; | ||
| 91 | |||
| 92 | public: | 84 | public: |
| 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 | |||
| 22 | namespace Kernel { | ||
| 23 | |||
| 24 | class ServiceThread::Impl final { | ||
| 25 | public: | ||
| 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 | |||
| 37 | private: | ||
| 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 | |||
| 49 | void 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 | |||
| 119 | void 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 | |||
| 133 | void 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 | |||
| 143 | void 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 | |||
| 160 | ServiceThread::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 | |||
| 182 | ServiceThread::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 | |||
| 196 | ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name) | ||
| 197 | : impl{std::make_unique<Impl>(kernel, name)} {} | ||
| 198 | |||
| 199 | ServiceThread::~ServiceThread() = default; | ||
| 200 | |||
| 201 | void 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 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | class HLERequestContext; | ||
| 12 | class KernelCore; | ||
| 13 | class KSession; | ||
| 14 | class SessionRequestManager; | ||
| 15 | |||
| 16 | class ServiceThread final { | ||
| 17 | public: | ||
| 18 | explicit ServiceThread(KernelCore& kernel, const std::string& name); | ||
| 19 | ~ServiceThread(); | ||
| 20 | |||
| 21 | void RegisterServerSession(KServerSession* session, | ||
| 22 | std::shared_ptr<SessionRequestManager> manager); | ||
| 23 | |||
| 24 | private: | ||
| 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 | ||
| 13 | namespace Kernel::Svc { | 13 | namespace Kernel::Svc { |
| 14 | 14 | ||
| 15 | /// Connect to an OS service given the port name, returns the handle to the port to out | 15 | Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr user_name) { |
| 16 | Result 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 | ||
| 67 | Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, | 51 | Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, |
| @@ -78,8 +62,11 @@ Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { | |||
| 78 | Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, | 62 | Result 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); |