mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-07-04 23:31:19 +01:00
hle: kernel: Refactor to allocate a ServiceThread per service handler.
- Previously, we would allocate a thread per session, which adds new threads on CloneCurrentObject. - This results in race conditions with N sessions queuing requests to the same service interface. - Fixes Pokken Tournament DX crashes/softlocks, which were regressed by #6347.
This commit is contained in:
parent
c8b3d92836
commit
27ce97fd42
13 changed files with 75 additions and 67 deletions
|
@ -30,9 +30,16 @@
|
||||||
|
|
||||||
namespace Kernel {
|
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() {}
|
||||||
|
|
||||||
void SessionRequestHandler::ClientConnected(KServerSession* session) {
|
void SessionRequestHandler::ClientConnected(KServerSession* session) {
|
||||||
session->SetSessionHandler(shared_from_this());
|
session->SetSessionHandler(shared_from_this());
|
||||||
|
|
|
@ -46,6 +46,7 @@ class KThread;
|
||||||
class KReadableEvent;
|
class KReadableEvent;
|
||||||
class KSession;
|
class KSession;
|
||||||
class KWritableEvent;
|
class KWritableEvent;
|
||||||
|
class ServiceThread;
|
||||||
|
|
||||||
enum class ThreadWakeupReason;
|
enum class ThreadWakeupReason;
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ enum class ThreadWakeupReason;
|
||||||
*/
|
*/
|
||||||
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
||||||
public:
|
public:
|
||||||
SessionRequestHandler();
|
SessionRequestHandler(KernelCore& kernel, const char* service_name_);
|
||||||
virtual ~SessionRequestHandler();
|
virtual ~SessionRequestHandler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,6 +84,14 @@ public:
|
||||||
* @param server_session ServerSession associated with the connection.
|
* @param server_session ServerSession associated with the connection.
|
||||||
*/
|
*/
|
||||||
void ClientDisconnected(KServerSession* session);
|
void ClientDisconnected(KServerSession* session);
|
||||||
|
|
||||||
|
std::weak_ptr<ServiceThread> GetServiceThread() const {
|
||||||
|
return service_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
KernelCore& kernel;
|
||||||
|
std::weak_ptr<ServiceThread> service_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
|
using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
|
||||||
|
@ -94,7 +103,8 @@ using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
|
||||||
*/
|
*/
|
||||||
class SessionRequestManager final {
|
class SessionRequestManager final {
|
||||||
public:
|
public:
|
||||||
SessionRequestManager() = default;
|
explicit SessionRequestManager(KernelCore& kernel);
|
||||||
|
~SessionRequestManager();
|
||||||
|
|
||||||
bool IsDomain() const {
|
bool IsDomain() const {
|
||||||
return is_domain;
|
return is_domain;
|
||||||
|
@ -142,10 +152,18 @@ public:
|
||||||
session_handler = std::move(handler);
|
session_handler = std::move(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<ServiceThread> GetServiceThread() const {
|
||||||
|
return session_handler->GetServiceThread();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_domain{};
|
bool is_domain{};
|
||||||
SessionRequestHandlerPtr session_handler;
|
SessionRequestHandlerPtr session_handler;
|
||||||
std::vector<SessionRequestHandlerPtr> domain_handlers;
|
std::vector<SessionRequestHandlerPtr> domain_handlers;
|
||||||
|
|
||||||
|
private:
|
||||||
|
KernelCore& kernel;
|
||||||
|
std::weak_ptr<ServiceThread> service_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -56,7 +56,8 @@ bool KClientPort::IsSignaled() const {
|
||||||
return num_sessions < max_sessions;
|
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.
|
// Reserve a new session from the resource limit.
|
||||||
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
|
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
|
||||||
LimitableResource::Sessions);
|
LimitableResource::Sessions);
|
||||||
|
@ -101,7 +102,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the session.
|
// Initialize the session.
|
||||||
session->Initialize(this, parent->GetName());
|
session->Initialize(this, parent->GetName(), session_manager);
|
||||||
|
|
||||||
// Commit the session reservation.
|
// Commit the session reservation.
|
||||||
session_reservation.Commit();
|
session_reservation.Commit();
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace Kernel {
|
||||||
class KClientSession;
|
class KClientSession;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class KPort;
|
class KPort;
|
||||||
|
class SessionRequestManager;
|
||||||
|
|
||||||
class KClientPort final : public KSynchronizationObject {
|
class KClientPort final : public KSynchronizationObject {
|
||||||
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
|
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
|
||||||
|
@ -52,7 +53,8 @@ public:
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
ResultCode CreateSession(KClientSession** out);
|
ResultCode CreateSession(KClientSession** out,
|
||||||
|
std::shared_ptr<SessionRequestManager> session_manager = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<s32> num_sessions{};
|
std::atomic<s32> num_sessions{};
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/k_client_port.h"
|
#include "core/hle/kernel/k_client_port.h"
|
||||||
#include "core/hle/kernel/k_handle_table.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_process.h"
|
||||||
#include "core/hle/kernel/k_scheduler.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_server_session.h"
|
||||||
#include "core/hle/kernel/k_session.h"
|
#include "core/hle/kernel/k_session.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
|
@ -23,18 +25,21 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
KServerSession::KServerSession(KernelCore& kernel_)
|
KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
|
||||||
: KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {}
|
|
||||||
|
|
||||||
KServerSession::~KServerSession() {
|
KServerSession::~KServerSession() {}
|
||||||
kernel.ReleaseServiceThread(service_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KServerSession::Initialize(KSession* parent_, std::string&& name_) {
|
void KServerSession::Initialize(KSession* parent_, std::string&& name_,
|
||||||
|
std::shared_ptr<SessionRequestManager> manager_) {
|
||||||
// Set member variables.
|
// Set member variables.
|
||||||
parent = parent_;
|
parent = parent_;
|
||||||
name = std::move(name_);
|
name = std::move(name_);
|
||||||
service_thread = kernel.CreateServiceThread(name);
|
|
||||||
|
if (manager_) {
|
||||||
|
manager = manager_;
|
||||||
|
} else {
|
||||||
|
manager = std::make_shared<SessionRequestManager>(kernel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KServerSession::Destroy() {
|
void KServerSession::Destroy() {
|
||||||
|
@ -114,7 +119,7 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor
|
||||||
|
|
||||||
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
||||||
|
|
||||||
if (auto strong_ptr = service_thread.lock()) {
|
if (auto strong_ptr = manager->GetServiceThread().lock()) {
|
||||||
strong_ptr->QueueSyncRequest(*parent, std::move(context));
|
strong_ptr->QueueSyncRequest(*parent, std::move(context));
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ class HLERequestContext;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class KSession;
|
class KSession;
|
||||||
class SessionRequestHandler;
|
class SessionRequestHandler;
|
||||||
|
class SessionRequestManager;
|
||||||
class KThread;
|
class KThread;
|
||||||
|
|
||||||
class KServerSession final : public KSynchronizationObject,
|
class KServerSession final : public KSynchronizationObject,
|
||||||
|
@ -46,7 +47,8 @@ public:
|
||||||
|
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
|
|
||||||
void Initialize(KSession* parent_, std::string&& name_);
|
void Initialize(KSession* parent_, std::string&& name_,
|
||||||
|
std::shared_ptr<SessionRequestManager> manager_);
|
||||||
|
|
||||||
KSession* GetParent() {
|
KSession* GetParent() {
|
||||||
return parent;
|
return parent;
|
||||||
|
@ -104,16 +106,6 @@ public:
|
||||||
return manager;
|
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:
|
private:
|
||||||
/// Queues a sync request from the emulated application.
|
/// Queues a sync request from the emulated application.
|
||||||
ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
|
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
|
/// When set to True, converts the session to a domain at the end of the command
|
||||||
bool convert_to_domain{};
|
bool convert_to_domain{};
|
||||||
|
|
||||||
/// Thread to dispatch service requests
|
|
||||||
std::weak_ptr<ServiceThread> service_thread;
|
|
||||||
|
|
||||||
/// KSession that owns this KServerSession
|
/// KSession that owns this KServerSession
|
||||||
KSession* parent{};
|
KSession* parent{};
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,8 @@ KSession::KSession(KernelCore& kernel_)
|
||||||
: KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
|
: KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
|
||||||
KSession::~KSession() = default;
|
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.
|
// Increment reference count.
|
||||||
// Because reference count is one on creation, this will result
|
// Because reference count is one on creation, this will result
|
||||||
// in a reference count of two. Thus, when both server and client are closed
|
// 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));
|
KAutoObject::Create(std::addressof(client));
|
||||||
|
|
||||||
// Initialize our sub sessions.
|
// Initialize our sub sessions.
|
||||||
server.Initialize(this, name_ + ":Server");
|
server.Initialize(this, name_ + ":Server", manager_);
|
||||||
client.Initialize(this, name_ + ":Client");
|
client.Initialize(this, name_ + ":Client");
|
||||||
|
|
||||||
// Set state and name.
|
// Set state and name.
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class SessionRequestManager;
|
||||||
|
|
||||||
class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> {
|
class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> {
|
||||||
KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
|
KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
|
||||||
|
|
||||||
|
@ -20,7 +22,8 @@ public:
|
||||||
explicit KSession(KernelCore& kernel_);
|
explicit KSession(KernelCore& kernel_);
|
||||||
~KSession() override;
|
~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;
|
void Finalize() override;
|
||||||
|
|
||||||
|
|
|
@ -254,8 +254,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NS, "called");
|
LOG_DEBUG(Service_NS, "called");
|
||||||
|
|
||||||
// Create shared font memory object
|
// Create shared font memory object
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
|
|
||||||
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(),
|
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(),
|
||||||
impl->shared_font->size());
|
impl->shared_font->size());
|
||||||
|
|
||||||
|
|
|
@ -93,8 +93,8 @@ 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_)
|
u32 max_sessions_, InvokerFn* handler_invoker_)
|
||||||
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
: SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
|
||||||
handler_invoker{handler_invoker_} {}
|
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
|
||||||
|
|
||||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||||
// Wait for other threads to release access before destroying
|
// Wait for other threads to release access before destroying
|
||||||
|
@ -111,7 +111,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
|
||||||
port_installed = true;
|
port_installed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
|
Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
|
||||||
const auto guard = LockService();
|
const auto guard = LockService();
|
||||||
|
|
||||||
ASSERT(!port_installed);
|
ASSERT(!port_installed);
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Kernel {
|
||||||
class HLERequestContext;
|
class HLERequestContext;
|
||||||
class KClientPort;
|
class KClientPort;
|
||||||
class KServerSession;
|
class KServerSession;
|
||||||
|
class ServiceThread;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
@ -41,7 +42,7 @@ class ServiceManager;
|
||||||
|
|
||||||
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
|
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
|
||||||
/// Arbitrary default number of maximum connections to an HLE service.
|
/// 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
|
* 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);
|
void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/// Creates a port pair and registers it on the kernel's global port registry.
|
/// 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.
|
/// Handles a synchronization request for the service.
|
||||||
ResultCode HandleSyncRequest(Kernel::KServerSession& session,
|
ResultCode HandleSyncRequest(Kernel::KServerSession& session,
|
||||||
|
|
|
@ -28,42 +28,25 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::CloneCurrentObject(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");
|
LOG_DEBUG(Service, "called");
|
||||||
|
|
||||||
auto& kernel = system.Kernel();
|
auto& parent_session = *ctx.Session()->GetParent();
|
||||||
auto* session = ctx.Session()->GetParent();
|
auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort();
|
||||||
auto* port = session->GetParent()->GetParent();
|
auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager();
|
||||||
|
|
||||||
// Reserve a new session from the process resource limit.
|
// Create a session.
|
||||||
Kernel::KScopedResourceReservation session_reservation(
|
Kernel::KClientSession* session{};
|
||||||
kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
|
const ResultCode result = parent_port.CreateSession(std::addressof(session), session_manager);
|
||||||
if (!session_reservation.Succeeded()) {
|
if (result.IsError()) {
|
||||||
|
LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
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.
|
// We succeeded.
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushMoveObjects(clone->GetClientSession());
|
rb.PushMoveObjects(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
|
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core
|
||||||
self.sm_interface = sm;
|
self.sm_interface = sm;
|
||||||
self.controller_interface = std::make_unique<Controller>(system);
|
self.controller_interface = std::make_unique<Controller>(system);
|
||||||
|
|
||||||
return sm->CreatePort(system.Kernel());
|
return sm->CreatePort();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
|
ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
|
||||||
|
|
Loading…
Reference in a new issue