Merge pull request #8122 from bunnei/improve-thread-usage
Improve usage of service host threads
This commit is contained in:
		| @@ -24,8 +24,15 @@ | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_) | ||||
|     : kernel{kernel_}, service_thread{kernel.CreateServiceThread(service_name_)} {} | ||||
| SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_, | ||||
|                                              ServiceThreadType thread_type) | ||||
|     : kernel{kernel_} { | ||||
|     if (thread_type == ServiceThreadType::CreateNew) { | ||||
|         service_thread = kernel.CreateServiceThread(service_name_); | ||||
|     } else { | ||||
|         service_thread = kernel.GetDefaultServiceThread(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| SessionRequestHandler::~SessionRequestHandler() { | ||||
|     kernel.ReleaseServiceThread(service_thread); | ||||
|   | ||||
| @@ -33,6 +33,11 @@ namespace Service { | ||||
| class ServiceFrameworkBase; | ||||
| } | ||||
|  | ||||
| enum class ServiceThreadType { | ||||
|     Default, | ||||
|     CreateNew, | ||||
| }; | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| class Domain; | ||||
| @@ -57,7 +62,8 @@ enum class ThreadWakeupReason; | ||||
|  */ | ||||
| class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { | ||||
| public: | ||||
|     SessionRequestHandler(KernelCore& kernel, const char* service_name_); | ||||
|     SessionRequestHandler(KernelCore& kernel_, const char* service_name_, | ||||
|                           ServiceThreadType thread_type); | ||||
|     virtual ~SessionRequestHandler(); | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -61,6 +61,7 @@ struct KernelCore::Impl { | ||||
|         global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | ||||
|         global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); | ||||
|         global_handle_table->Initialize(KHandleTable::MaxTableSize); | ||||
|         default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread"); | ||||
|  | ||||
|         is_phantom_mode_for_singlecore = false; | ||||
|  | ||||
| @@ -677,6 +678,12 @@ struct KernelCore::Impl { | ||||
|  | ||||
|     void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { | ||||
|         if (auto strong_ptr = service_thread.lock()) { | ||||
|             if (strong_ptr == default_service_thread.lock()) { | ||||
|                 // Nothing to do here, the service is using default_service_thread, which will be | ||||
|                 // released on shutdown. | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             service_threads_manager.QueueWork( | ||||
|                 [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); }); | ||||
|         } | ||||
| @@ -739,7 +746,8 @@ struct KernelCore::Impl { | ||||
|     std::unique_ptr<KMemoryLayout> memory_layout; | ||||
|  | ||||
|     // Threads used for services | ||||
|     std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; | ||||
|     std::unordered_set<std::shared_ptr<ServiceThread>> service_threads; | ||||
|     std::weak_ptr<ServiceThread> default_service_thread; | ||||
|     Common::ThreadWorker service_threads_manager; | ||||
|  | ||||
|     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; | ||||
| @@ -1065,6 +1073,10 @@ std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std:: | ||||
|     return impl->CreateServiceThread(*this, name); | ||||
| } | ||||
|  | ||||
| std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const { | ||||
|     return impl->default_service_thread; | ||||
| } | ||||
|  | ||||
| void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { | ||||
|     impl->ReleaseServiceThread(service_thread); | ||||
| } | ||||
|   | ||||
| @@ -271,15 +271,25 @@ public: | ||||
|     void ExitSVCProfile(); | ||||
|  | ||||
|     /** | ||||
|      * Creates an HLE service thread, which are used to execute service routines asynchronously. | ||||
|      * While these are allocated per ServerSession, these need to be owned and managed outside | ||||
|      * of ServerSession to avoid a circular dependency. | ||||
|      * Creates a host thread to execute HLE service requests, which are used to execute service | ||||
|      * routines asynchronously. While these are allocated per ServerSession, these need to be owned | ||||
|      * and managed outside of ServerSession to avoid a circular dependency. In general, most | ||||
|      * services can just use the default service thread, and not need their own host service thread. | ||||
|      * See GetDefaultServiceThread. | ||||
|      * @param name String name for the ServerSession creating this thread, used for debug | ||||
|      * purposes. | ||||
|      * @returns The a weak pointer newly created service thread. | ||||
|      */ | ||||
|     std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); | ||||
|  | ||||
|     /** | ||||
|      * Gets the default host service thread, which executes HLE service requests. Unless service | ||||
|      * requests need to block on the host, the default service thread should be used in favor of | ||||
|      * creating a new service thread. | ||||
|      * @returns The a weak pointer for the default service thread. | ||||
|      */ | ||||
|     std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const; | ||||
|  | ||||
|     /** | ||||
|      * Releases a HLE service thread, instructing KernelCore to free it. This should be called when | ||||
|      * the ServerSession associated with the thread is destroyed. | ||||
|   | ||||
| @@ -41,9 +41,10 @@ public: | ||||
|     explicit IAudioOut(Core::System& system_, AudoutParams audio_params_, | ||||
|                        AudioCore::AudioOut& audio_core_, std::string&& device_name_, | ||||
|                        std::string&& unique_name) | ||||
|         : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, | ||||
|           device_name{std::move(device_name_)}, audio_params{audio_params_}, | ||||
|           main_memory{system.Memory()}, service_context{system_, "IAudioOut"} { | ||||
|         : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew}, | ||||
|           audio_core{audio_core_}, device_name{std::move(device_name_)}, | ||||
|           audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_, | ||||
|                                                                                      "IAudioOut"} { | ||||
|         // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, | ||||
|   | ||||
| @@ -24,7 +24,8 @@ public: | ||||
|     explicit IAudioRenderer(Core::System& system_, | ||||
|                             const AudioCommon::AudioRendererParameter& audren_params, | ||||
|                             const std::size_t instance_number) | ||||
|         : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"} { | ||||
|         : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew}, | ||||
|           service_context{system_, "IAudioRenderer"} { | ||||
|         // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, | ||||
|   | ||||
| @@ -58,7 +58,8 @@ enum class FileSystemType : u8 { | ||||
| class IStorage final : public ServiceFramework<IStorage> { | ||||
| public: | ||||
|     explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) | ||||
|         : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { | ||||
|         : ServiceFramework{system_, "IStorage", ServiceThreadType::CreateNew}, | ||||
|           backend(std::move(backend_)) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IStorage::Read, "Read"}, | ||||
|             {1, nullptr, "Write"}, | ||||
| @@ -116,7 +117,8 @@ private: | ||||
| class IFile final : public ServiceFramework<IFile> { | ||||
| public: | ||||
|     explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) | ||||
|         : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { | ||||
|         : ServiceFramework{system_, "IFile", ServiceThreadType::CreateNew}, | ||||
|           backend(std::move(backend_)) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IFile::Read, "Read"}, | ||||
|             {1, &IFile::Write, "Write"}, | ||||
| @@ -252,7 +254,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec | ||||
| class IDirectory final : public ServiceFramework<IDirectory> { | ||||
| public: | ||||
|     explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_) | ||||
|         : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { | ||||
|         : ServiceFramework{system_, "IDirectory", ServiceThreadType::CreateNew}, | ||||
|           backend(std::move(backend_)) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IDirectory::Read, "Read"}, | ||||
|             {1, &IDirectory::GetEntryCount, "GetEntryCount"}, | ||||
| @@ -308,8 +311,8 @@ private: | ||||
| class IFileSystem final : public ServiceFramework<IFileSystem> { | ||||
| public: | ||||
|     explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) | ||||
|         : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( | ||||
|                                                                                       size_)} { | ||||
|         : ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew}, | ||||
|           backend{std::move(backend_)}, size{std::move(size_)} { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IFileSystem::CreateFile, "CreateFile"}, | ||||
|             {1, &IFileSystem::DeleteFile, "DeleteFile"}, | ||||
|   | ||||
| @@ -230,7 +230,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { | ||||
| } | ||||
|  | ||||
| NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name) | ||||
|     : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} { | ||||
|     : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, nvdrv{std::move(nvdrv_)} { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &NVDRV::Open, "Open"}, | ||||
|         {1, &NVDRV::Ioctl1, "Ioctl"}, | ||||
|   | ||||
| @@ -91,8 +91,9 @@ namespace Service { | ||||
| } | ||||
|  | ||||
| ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_, | ||||
|                                            u32 max_sessions_, InvokerFn* handler_invoker_) | ||||
|     : SessionRequestHandler(system_.Kernel(), service_name_), system{system_}, | ||||
|                                            ServiceThreadType thread_type, u32 max_sessions_, | ||||
|                                            InvokerFn* handler_invoker_) | ||||
|     : SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_}, | ||||
|       service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {} | ||||
|  | ||||
| ServiceFrameworkBase::~ServiceFrameworkBase() { | ||||
|   | ||||
| @@ -114,7 +114,8 @@ private: | ||||
|                            Kernel::HLERequestContext& ctx); | ||||
|  | ||||
|     explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_, | ||||
|                                   u32 max_sessions_, InvokerFn* handler_invoker_); | ||||
|                                   ServiceThreadType thread_type, u32 max_sessions_, | ||||
|                                   InvokerFn* handler_invoker_); | ||||
|     ~ServiceFrameworkBase() override; | ||||
|  | ||||
|     void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); | ||||
| @@ -176,14 +177,17 @@ protected: | ||||
|     /** | ||||
|      * Initializes the handler with no functions installed. | ||||
|      * | ||||
|      * @param system_       The system context to construct this service under. | ||||
|      * @param system_ The system context to construct this service under. | ||||
|      * @param service_name_ Name of the service. | ||||
|      * @param max_sessions_ Maximum number of sessions that can be | ||||
|      *                      connected to this service at the same time. | ||||
|      * @param thread_type Specifies the thread type for this service. If this is set to CreateNew, | ||||
|      *                    it creates a new thread for it, otherwise this uses the default thread. | ||||
|      * @param max_sessions_ Maximum number of sessions that can be connected to this service at the | ||||
|      * same time. | ||||
|      */ | ||||
|     explicit ServiceFramework(Core::System& system_, const char* service_name_, | ||||
|                               ServiceThreadType thread_type = ServiceThreadType::Default, | ||||
|                               u32 max_sessions_ = ServerSessionCountMax) | ||||
|         : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {} | ||||
|         : ServiceFrameworkBase(system_, service_name_, thread_type, max_sessions_, Invoker) {} | ||||
|  | ||||
|     /// Registers handlers in the service. | ||||
|     template <std::size_t N> | ||||
|   | ||||
| @@ -206,7 +206,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) { | ||||
| } | ||||
|  | ||||
| SM::SM(ServiceManager& service_manager_, Core::System& system_) | ||||
|     : ServiceFramework{system_, "sm:", 4}, | ||||
|     : ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4}, | ||||
|       service_manager{service_manager_}, kernel{system_.Kernel()} { | ||||
|     RegisterHandlers({ | ||||
|         {0, &SM::Initialize, "Initialize"}, | ||||
|   | ||||
| @@ -837,7 +837,8 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co | ||||
|     rb.PushEnum(bsd_errno); | ||||
| } | ||||
|  | ||||
| BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { | ||||
| BSD::BSD(Core::System& system_, const char* name) | ||||
|     : ServiceFramework{system_, name, ServiceThreadType::CreateNew} { | ||||
|     // clang-format off | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &BSD::RegisterClient, "RegisterClient"}, | ||||
|   | ||||
| @@ -77,7 +77,8 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size"); | ||||
| class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { | ||||
| public: | ||||
|     explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_) | ||||
|         : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) { | ||||
|         : ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew}, | ||||
|           server(server_) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, | ||||
|             {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei