Merge pull request #8122 from bunnei/improve-thread-usage

Improve usage of service host threads
This commit is contained in:
bunnei 2022-04-06 12:25:25 -07:00 committed by GitHub
commit eb8c8db899
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 74 additions and 27 deletions

View file

@ -24,8 +24,15 @@
namespace Kernel { namespace Kernel {
SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_) SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
: kernel{kernel_}, service_thread{kernel.CreateServiceThread(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() { SessionRequestHandler::~SessionRequestHandler() {
kernel.ReleaseServiceThread(service_thread); kernel.ReleaseServiceThread(service_thread);

View file

@ -33,6 +33,11 @@ namespace Service {
class ServiceFrameworkBase; class ServiceFrameworkBase;
} }
enum class ServiceThreadType {
Default,
CreateNew,
};
namespace Kernel { namespace Kernel {
class Domain; class Domain;
@ -57,7 +62,8 @@ enum class ThreadWakeupReason;
*/ */
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
public: public:
SessionRequestHandler(KernelCore& kernel, const char* service_name_); SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
ServiceThreadType thread_type);
virtual ~SessionRequestHandler(); virtual ~SessionRequestHandler();
/** /**

View file

@ -61,6 +61,7 @@ struct KernelCore::Impl {
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
global_handle_table->Initialize(KHandleTable::MaxTableSize); global_handle_table->Initialize(KHandleTable::MaxTableSize);
default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
is_phantom_mode_for_singlecore = false; is_phantom_mode_for_singlecore = false;
@ -677,6 +678,12 @@ struct KernelCore::Impl {
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
if (auto strong_ptr = service_thread.lock()) { 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( service_threads_manager.QueueWork(
[this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); }); [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; std::unique_ptr<KMemoryLayout> memory_layout;
// Threads used for services // 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; Common::ThreadWorker service_threads_manager;
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; 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); 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) { void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
impl->ReleaseServiceThread(service_thread); impl->ReleaseServiceThread(service_thread);
} }

View file

@ -271,15 +271,25 @@ public:
void ExitSVCProfile(); void ExitSVCProfile();
/** /**
* Creates an HLE service thread, which are used to execute service routines asynchronously. * Creates a host thread to execute HLE service requests, which are used to execute service
* While these are allocated per ServerSession, these need to be owned and managed outside * routines asynchronously. While these are allocated per ServerSession, these need to be owned
* of ServerSession to avoid a circular dependency. * 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 * @param name String name for the ServerSession creating this thread, used for debug
* purposes. * purposes.
* @returns The a weak pointer newly created service thread. * @returns The a weak pointer newly created service thread.
*/ */
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); 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 * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
* the ServerSession associated with the thread is destroyed. * the ServerSession associated with the thread is destroyed.

View file

@ -41,9 +41,10 @@ public:
explicit IAudioOut(Core::System& system_, AudoutParams audio_params_, explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,
AudioCore::AudioOut& audio_core_, std::string&& device_name_, AudioCore::AudioOut& audio_core_, std::string&& device_name_,
std::string&& unique_name) std::string&& unique_name)
: ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
device_name{std::move(device_name_)}, audio_params{audio_params_}, audio_core{audio_core_}, device_name{std::move(device_name_)},
main_memory{system.Memory()}, service_context{system_, "IAudioOut"} { audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_,
"IAudioOut"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},

View file

@ -24,7 +24,8 @@ public:
explicit IAudioRenderer(Core::System& system_, explicit IAudioRenderer(Core::System& system_,
const AudioCommon::AudioRendererParameter& audren_params, const AudioCommon::AudioRendererParameter& audren_params,
const std::size_t instance_number) 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 // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},

View file

@ -58,7 +58,8 @@ enum class FileSystemType : u8 {
class IStorage final : public ServiceFramework<IStorage> { class IStorage final : public ServiceFramework<IStorage> {
public: public:
explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) 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[] = { static const FunctionInfo functions[] = {
{0, &IStorage::Read, "Read"}, {0, &IStorage::Read, "Read"},
{1, nullptr, "Write"}, {1, nullptr, "Write"},
@ -116,7 +117,8 @@ private:
class IFile final : public ServiceFramework<IFile> { class IFile final : public ServiceFramework<IFile> {
public: public:
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) 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[] = { static const FunctionInfo functions[] = {
{0, &IFile::Read, "Read"}, {0, &IFile::Read, "Read"},
{1, &IFile::Write, "Write"}, {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> { class IDirectory final : public ServiceFramework<IDirectory> {
public: public:
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_) 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[] = { static const FunctionInfo functions[] = {
{0, &IDirectory::Read, "Read"}, {0, &IDirectory::Read, "Read"},
{1, &IDirectory::GetEntryCount, "GetEntryCount"}, {1, &IDirectory::GetEntryCount, "GetEntryCount"},
@ -308,8 +311,8 @@ private:
class IFileSystem final : public ServiceFramework<IFileSystem> { class IFileSystem final : public ServiceFramework<IFileSystem> {
public: public:
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
: ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( : ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew},
size_)} { backend{std::move(backend_)}, size{std::move(size_)} {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"}, {0, &IFileSystem::CreateFile, "CreateFile"},
{1, &IFileSystem::DeleteFile, "DeleteFile"}, {1, &IFileSystem::DeleteFile, "DeleteFile"},

View file

@ -230,7 +230,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
} }
NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name) 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[] = { static const FunctionInfo functions[] = {
{0, &NVDRV::Open, "Open"}, {0, &NVDRV::Open, "Open"},
{1, &NVDRV::Ioctl1, "Ioctl"}, {1, &NVDRV::Ioctl1, "Ioctl"},

View file

@ -91,8 +91,9 @@ namespace Service {
} }
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_, ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
u32 max_sessions_, InvokerFn* handler_invoker_) ServiceThreadType thread_type, u32 max_sessions_,
: SessionRequestHandler(system_.Kernel(), service_name_), system{system_}, InvokerFn* handler_invoker_)
: SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_},
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {} service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
ServiceFrameworkBase::~ServiceFrameworkBase() { ServiceFrameworkBase::~ServiceFrameworkBase() {

View file

@ -114,7 +114,8 @@ private:
Kernel::HLERequestContext& ctx); Kernel::HLERequestContext& ctx);
explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_, 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; ~ServiceFrameworkBase() override;
void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
@ -176,14 +177,17 @@ protected:
/** /**
* Initializes the handler with no functions installed. * 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 service_name_ Name of the service.
* @param max_sessions_ Maximum number of sessions that can be * @param thread_type Specifies the thread type for this service. If this is set to CreateNew,
* connected to this service at the same time. * 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_, explicit ServiceFramework(Core::System& system_, const char* service_name_,
ServiceThreadType thread_type = ServiceThreadType::Default,
u32 max_sessions_ = ServerSessionCountMax) 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. /// Registers handlers in the service.
template <std::size_t N> template <std::size_t N>

View file

@ -206,7 +206,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
} }
SM::SM(ServiceManager& service_manager_, Core::System& system_) 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()} { service_manager{service_manager_}, kernel{system_.Kernel()} {
RegisterHandlers({ RegisterHandlers({
{0, &SM::Initialize, "Initialize"}, {0, &SM::Initialize, "Initialize"},

View file

@ -837,7 +837,8 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
rb.PushEnum(bsd_errno); 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 // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &BSD::RegisterClient, "RegisterClient"}, {0, &BSD::RegisterClient, "RegisterClient"},

View file

@ -77,7 +77,8 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
public: public:
explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_) explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
: ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) { : ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew},
server(server_) {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
{1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},