Merge pull request #6414 from bunnei/fix-service-threads

hle: kernel: Refactor to allocate a ServiceThread per service handler.
master
bunnei 2021-06-06 22:52:07 +07:00 committed by GitHub
commit 28eb8c83d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 101 additions and 87 deletions

@ -30,9 +30,16 @@
namespace Kernel {
SessionRequestHandler::SessionRequestHandler() = default;
SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_)
: kernel{kernel_}, service_thread{kernel.CreateServiceThread(service_name_)} {}
SessionRequestHandler::~SessionRequestHandler() = default;
SessionRequestHandler::~SessionRequestHandler() {
kernel.ReleaseServiceThread(service_thread);
}
SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {}
SessionRequestManager::~SessionRequestManager() = default;
void SessionRequestHandler::ClientConnected(KServerSession* session) {
session->SetSessionHandler(shared_from_this());

@ -46,6 +46,7 @@ class KThread;
class KReadableEvent;
class KSession;
class KWritableEvent;
class ServiceThread;
enum class ThreadWakeupReason;
@ -56,7 +57,7 @@ enum class ThreadWakeupReason;
*/
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
public:
SessionRequestHandler();
SessionRequestHandler(KernelCore& kernel, const char* service_name_);
virtual ~SessionRequestHandler();
/**
@ -83,6 +84,14 @@ public:
* @param server_session ServerSession associated with the connection.
*/
void ClientDisconnected(KServerSession* session);
std::shared_ptr<ServiceThread> GetServiceThread() const {
return service_thread.lock();
}
protected:
KernelCore& kernel;
std::weak_ptr<ServiceThread> service_thread;
};
using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
@ -94,7 +103,8 @@ using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
*/
class SessionRequestManager final {
public:
SessionRequestManager() = default;
explicit SessionRequestManager(KernelCore& kernel);
~SessionRequestManager();
bool IsDomain() const {
return is_domain;
@ -142,10 +152,18 @@ public:
session_handler = std::move(handler);
}
std::shared_ptr<ServiceThread> GetServiceThread() const {
return session_handler->GetServiceThread();
}
private:
bool is_domain{};
SessionRequestHandlerPtr session_handler;
std::vector<SessionRequestHandlerPtr> domain_handlers;
private:
KernelCore& kernel;
std::weak_ptr<ServiceThread> service_thread;
};
/**

@ -7,10 +7,11 @@
#include <atomic>
#include <string>
#include <boost/intrusive/rbtree.hpp>
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
#include "core/hle/kernel/k_class_token.h"
namespace Kernel {
@ -175,7 +176,7 @@ private:
class KAutoObjectWithListContainer;
class KAutoObjectWithList : public KAutoObject {
class KAutoObjectWithList : public KAutoObject, public boost::intrusive::set_base_hook<> {
public:
explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {}
@ -192,6 +193,10 @@ public:
}
}
friend bool operator<(const KAutoObjectWithList& left, const KAutoObjectWithList& right) {
return &left < &right;
}
public:
virtual u64 GetId() const {
return reinterpret_cast<u64>(this);
@ -203,8 +208,6 @@ public:
private:
friend class KAutoObjectWithListContainer;
Common::IntrusiveRedBlackTreeNode list_node;
};
template <typename T>

@ -9,13 +9,13 @@ namespace Kernel {
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
KScopedLightLock lk(m_lock);
m_object_list.insert(*obj);
m_object_list.insert_unique(*obj);
}
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
KScopedLightLock lk(m_lock);
m_object_list.erase(m_object_list.iterator_to(*obj));
m_object_list.erase(*obj);
}
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {

@ -6,6 +6,8 @@
#include <atomic>
#include <boost/intrusive/rbtree.hpp>
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
@ -23,8 +25,7 @@ class KAutoObjectWithListContainer {
YUZU_NON_MOVEABLE(KAutoObjectWithListContainer);
public:
using ListType = Common::IntrusiveRedBlackTreeMemberTraits<
&KAutoObjectWithList::list_node>::TreeType<KAutoObjectWithList>;
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
public:
class ListAccessor : public KScopedLightLock {

@ -16,11 +16,11 @@ namespace Kernel {
KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KClientPort::~KClientPort() = default;
void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) {
void KClientPort::Initialize(KPort* parent_port_, s32 max_sessions_, std::string&& name_) {
// Set member variables.
num_sessions = 0;
peak_sessions = 0;
parent = parent_;
parent = parent_port_;
max_sessions = max_sessions_;
name = std::move(name_);
}
@ -56,7 +56,8 @@ bool KClientPort::IsSignaled() const {
return num_sessions < max_sessions;
}
ResultCode KClientPort::CreateSession(KClientSession** out) {
ResultCode KClientPort::CreateSession(KClientSession** out,
std::shared_ptr<SessionRequestManager> session_manager) {
// Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
LimitableResource::Sessions);
@ -101,7 +102,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) {
}
// Initialize the session.
session->Initialize(this, parent->GetName());
session->Initialize(this, parent->GetName(), session_manager);
// Commit the session reservation.
session_reservation.Commit();

@ -16,6 +16,7 @@ namespace Kernel {
class KClientSession;
class KernelCore;
class KPort;
class SessionRequestManager;
class KClientPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
@ -52,7 +53,8 @@ public:
void Destroy() override;
bool IsSignaled() const override;
ResultCode CreateSession(KClientSession** out);
ResultCode CreateSession(KClientSession** out,
std::shared_ptr<SessionRequestManager> session_manager = nullptr);
private:
std::atomic<s32> num_sessions{};

@ -36,9 +36,9 @@ public:
explicit KClientSession(KernelCore& kernel_);
~KClientSession() override;
void Initialize(KSession* parent_, std::string&& name_) {
void Initialize(KSession* parent_session_, std::string&& name_) {
// Set member variables.
parent = parent_;
parent = parent_session_;
name = std::move(name_);
}

@ -21,9 +21,9 @@ public:
explicit KReadableEvent(KernelCore& kernel_);
~KReadableEvent() override;
void Initialize(KEvent* parent_, std::string&& name_) {
void Initialize(KEvent* parent_event_, std::string&& name_) {
is_signaled = false;
parent = parent_;
parent = parent_event_;
name = std::move(name_);
}

@ -17,9 +17,9 @@ namespace Kernel {
KServerPort::KServerPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KServerPort::~KServerPort() = default;
void KServerPort::Initialize(KPort* parent_, std::string&& name_) {
void KServerPort::Initialize(KPort* parent_port_, std::string&& name_) {
// Set member variables.
parent = parent_;
parent = parent_port_;
name = std::move(name_);
}

@ -29,7 +29,7 @@ public:
explicit KServerPort(KernelCore& kernel_);
~KServerPort() override;
void Initialize(KPort* parent_, std::string&& name_);
void Initialize(KPort* parent_port_, std::string&& name_);
/// Whether or not this server port has an HLE handler available.
bool HasSessionRequestHandler() const {

@ -13,8 +13,10 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_server_port.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_thread.h"
@ -23,18 +25,21 @@
namespace Kernel {
KServerSession::KServerSession(KernelCore& kernel_)
: KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {}
KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
KServerSession::~KServerSession() {
kernel.ReleaseServiceThread(service_thread);
}
KServerSession::~KServerSession() {}
void KServerSession::Initialize(KSession* parent_, std::string&& name_) {
void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
std::shared_ptr<SessionRequestManager> manager_) {
// Set member variables.
parent = parent_;
parent = parent_session_;
name = std::move(name_);
service_thread = kernel.CreateServiceThread(name);
if (manager_) {
manager = manager_;
} else {
manager = std::make_shared<SessionRequestManager>(kernel);
}
}
void KServerSession::Destroy() {
@ -114,9 +119,11 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
if (auto strong_ptr = service_thread.lock()) {
if (auto strong_ptr = manager->GetServiceThread(); strong_ptr) {
strong_ptr->QueueSyncRequest(*parent, std::move(context));
return ResultSuccess;
} else {
ASSERT_MSG(false, "strong_ptr was nullptr!");
}
return ResultSuccess;

@ -32,6 +32,7 @@ class HLERequestContext;
class KernelCore;
class KSession;
class SessionRequestHandler;
class SessionRequestManager;
class KThread;
class KServerSession final : public KSynchronizationObject,
@ -46,7 +47,8 @@ public:
void Destroy() override;
void Initialize(KSession* parent_, std::string&& name_);
void Initialize(KSession* parent_session_, std::string&& name_,
std::shared_ptr<SessionRequestManager> manager_);
KSession* GetParent() {
return parent;
@ -104,16 +106,6 @@ public:
return manager;
}
/// Gets the session request manager, which forwards requests to the underlying service
const std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() const {
return manager;
}
/// Sets the session request manager, which forwards requests to the underlying service
void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) {
manager = std::move(manager_);
}
private:
/// Queues a sync request from the emulated application.
ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
@ -131,9 +123,6 @@ private:
/// When set to True, converts the session to a domain at the end of the command
bool convert_to_domain{};
/// Thread to dispatch service requests
std::weak_ptr<ServiceThread> service_thread;
/// KSession that owns this KServerSession
KSession* parent{};
};

@ -15,7 +15,8 @@ KSession::KSession(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
KSession::~KSession() = default;
void KSession::Initialize(KClientPort* port_, const std::string& name_) {
void KSession::Initialize(KClientPort* port_, const std::string& name_,
std::shared_ptr<SessionRequestManager> manager_) {
// Increment reference count.
// Because reference count is one on creation, this will result
// in a reference count of two. Thus, when both server and client are closed
@ -27,7 +28,7 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_) {
KAutoObject::Create(std::addressof(client));
// Initialize our sub sessions.
server.Initialize(this, name_ + ":Server");
server.Initialize(this, name_ + ":Server", manager_);
client.Initialize(this, name_ + ":Client");
// Set state and name.

@ -13,6 +13,8 @@
namespace Kernel {
class SessionRequestManager;
class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> {
KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
@ -20,7 +22,8 @@ public:
explicit KSession(KernelCore& kernel_);
~KSession() override;
void Initialize(KClientPort* port_, const std::string& name_);
void Initialize(KClientPort* port_, const std::string& name_,
std::shared_ptr<SessionRequestManager> manager_ = nullptr);
void Finalize() override;

@ -13,8 +13,8 @@ KWritableEvent::KWritableEvent(KernelCore& kernel_)
KWritableEvent::~KWritableEvent() = default;
void KWritableEvent::Initialize(KEvent* parent_, std::string&& name_) {
parent = parent_;
void KWritableEvent::Initialize(KEvent* parent_event_, std::string&& name_) {
parent = parent_event_;
name = std::move(name_);
parent->GetReadableEvent().Open();
}

@ -254,8 +254,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
// Create shared font memory object
auto& kernel = system.Kernel();
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(),
impl->shared_font->size());

@ -93,8 +93,8 @@ namespace Service {
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
u32 max_sessions_, InvokerFn* handler_invoker_)
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
handler_invoker{handler_invoker_} {}
: SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
ServiceFrameworkBase::~ServiceFrameworkBase() {
// Wait for other threads to release access before destroying
@ -111,7 +111,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
port_installed = true;
}
Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
const auto guard = LockService();
ASSERT(!port_installed);

@ -23,6 +23,7 @@ namespace Kernel {
class HLERequestContext;
class KClientPort;
class KServerSession;
class ServiceThread;
} // namespace Kernel
namespace Service {
@ -41,7 +42,7 @@ class ServiceManager;
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
/// Arbitrary default number of maximum connections to an HLE service.
static const u32 DefaultMaxSessions = 10;
static const u32 DefaultMaxSessions = 64;
/**
* This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it
@ -74,7 +75,7 @@ public:
void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
/// Creates a port pair and registers it on the kernel's global port registry.
Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel);
Kernel::KClientPort& CreatePort();
/// Handles a synchronization request for the service.
ResultCode HandleSyncRequest(Kernel::KServerSession& session,

@ -28,42 +28,25 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
}
void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
// and that we probably want to actually make an entirely new Session, but we still need to
// verify this on hardware.
LOG_DEBUG(Service, "called");
auto& kernel = system.Kernel();
auto* session = ctx.Session()->GetParent();
auto* port = session->GetParent()->GetParent();
auto& parent_session = *ctx.Session()->GetParent();
auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort();
auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager();
// Reserve a new session from the process resource limit.
Kernel::KScopedResourceReservation session_reservation(
kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
if (!session_reservation.Succeeded()) {
// Create a session.
Kernel::KClientSession* session{};
const ResultCode result = parent_port.CreateSession(std::addressof(session), session_manager);
if (result.IsError()) {
LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(Kernel::ResultLimitReached);
rb.Push(result);
}
// Create a new session.
auto* clone = Kernel::KSession::Create(kernel);
clone->Initialize(&port->GetClientPort(), session->GetName());
// Commit the session reservation.
session_reservation.Commit();
// Enqueue the session with the named port.
port->EnqueueSession(&clone->GetServerSession());
// Set the session request manager.
clone->GetServerSession().SetSessionRequestManager(
session->GetServerSession().GetSessionRequestManager());
// We succeeded.
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(ResultSuccess);
rb.PushMoveObjects(clone->GetClientSession());
rb.PushMoveObjects(session);
}
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {

@ -46,7 +46,7 @@ Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core
self.sm_interface = sm;
self.controller_interface = std::make_unique<Controller>(system);
return sm->CreatePort(system.Kernel());
return sm->CreatePort();
}
ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,