early-access version 3059
This commit is contained in:
parent
6e35cb128e
commit
ac60707093
25 changed files with 293 additions and 445 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3058.
|
This is the source code for early-access 3059.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -450,7 +450,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::S
|
||||||
// Frame records are two words long:
|
// Frame records are two words long:
|
||||||
// fp+0 : pointer to previous frame record
|
// fp+0 : pointer to previous frame record
|
||||||
// fp+4 : value of lr for frame
|
// fp+4 : value of lr for frame
|
||||||
while (true) {
|
for (size_t i = 0; i < 256; i++) {
|
||||||
out.push_back({"", 0, lr, 0, ""});
|
out.push_back({"", 0, lr, 0, ""});
|
||||||
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
|
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -517,7 +517,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S
|
||||||
// Frame records are two words long:
|
// Frame records are two words long:
|
||||||
// fp+0 : pointer to previous frame record
|
// fp+0 : pointer to previous frame record
|
||||||
// fp+8 : value of lr for frame
|
// fp+8 : value of lr for frame
|
||||||
while (true) {
|
for (size_t i = 0; i < 256; i++) {
|
||||||
out.push_back({"", 0, lr, 0, ""});
|
out.push_back({"", 0, lr, 0, ""});
|
||||||
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
|
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -86,13 +86,13 @@ public:
|
||||||
u32 num_domain_objects{};
|
u32 num_domain_objects{};
|
||||||
const bool always_move_handles{
|
const bool always_move_handles{
|
||||||
(static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
|
(static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
|
||||||
if (!ctx.GetManager()->IsDomain() || always_move_handles) {
|
if (!ctx.Session()->GetSessionRequestManager()->IsDomain() || always_move_handles) {
|
||||||
num_handles_to_move = num_objects_to_move;
|
num_handles_to_move = num_objects_to_move;
|
||||||
} else {
|
} else {
|
||||||
num_domain_objects = num_objects_to_move;
|
num_domain_objects = num_objects_to_move;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.GetManager()->IsDomain()) {
|
if (ctx.Session()->GetSessionRequestManager()->IsDomain()) {
|
||||||
raw_data_size +=
|
raw_data_size +=
|
||||||
static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
|
static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
|
||||||
ctx.write_size += num_domain_objects;
|
ctx.write_size += num_domain_objects;
|
||||||
|
@ -125,7 +125,8 @@ public:
|
||||||
if (!ctx.IsTipc()) {
|
if (!ctx.IsTipc()) {
|
||||||
AlignWithPadding();
|
AlignWithPadding();
|
||||||
|
|
||||||
if (ctx.GetManager()->IsDomain() && ctx.HasDomainMessageHeader()) {
|
if (ctx.Session()->GetSessionRequestManager()->IsDomain() &&
|
||||||
|
ctx.HasDomainMessageHeader()) {
|
||||||
IPC::DomainMessageHeader domain_header{};
|
IPC::DomainMessageHeader domain_header{};
|
||||||
domain_header.num_objects = num_domain_objects;
|
domain_header.num_objects = num_domain_objects;
|
||||||
PushRaw(domain_header);
|
PushRaw(domain_header);
|
||||||
|
@ -145,18 +146,18 @@ public:
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void PushIpcInterface(std::shared_ptr<T> iface) {
|
void PushIpcInterface(std::shared_ptr<T> iface) {
|
||||||
if (context->GetManager()->IsDomain()) {
|
if (context->Session()->GetSessionRequestManager()->IsDomain()) {
|
||||||
context->AddDomainObject(std::move(iface));
|
context->AddDomainObject(std::move(iface));
|
||||||
} else {
|
} else {
|
||||||
kernel.CurrentProcess()->GetResourceLimit()->Reserve(
|
kernel.CurrentProcess()->GetResourceLimit()->Reserve(
|
||||||
Kernel::LimitableResource::Sessions, 1);
|
Kernel::LimitableResource::Sessions, 1);
|
||||||
|
|
||||||
auto* session = Kernel::KSession::Create(kernel);
|
auto* session = Kernel::KSession::Create(kernel);
|
||||||
session->Initialize(nullptr, iface->GetServiceName());
|
session->Initialize(nullptr, iface->GetServiceName(),
|
||||||
iface->RegisterSession(&session->GetServerSession(),
|
|
||||||
std::make_shared<Kernel::SessionRequestManager>(kernel));
|
std::make_shared<Kernel::SessionRequestManager>(kernel));
|
||||||
|
|
||||||
context->AddMoveObject(&session->GetClientSession());
|
context->AddMoveObject(&session->GetClientSession());
|
||||||
|
iface->ClientConnected(&session->GetServerSession());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +387,7 @@ public:
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::weak_ptr<T> PopIpcInterface() {
|
std::weak_ptr<T> PopIpcInterface() {
|
||||||
ASSERT(context->GetManager()->IsDomain());
|
ASSERT(context->Session()->GetSessionRequestManager()->IsDomain());
|
||||||
ASSERT(context->GetDomainMessageHeader().input_object_count > 0);
|
ASSERT(context->GetDomainMessageHeader().input_object_count > 0);
|
||||||
return context->GetDomainHandler<T>(Pop<u32>() - 1);
|
return context->GetDomainHandler<T>(Pop<u32>() - 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
#include "core/hle/kernel/k_handle_table.h"
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.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_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
@ -36,21 +35,7 @@ SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* se
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionRequestHandler::~SessionRequestHandler() {
|
SessionRequestHandler::~SessionRequestHandler() {
|
||||||
kernel.ReleaseServiceThread(service_thread.lock());
|
kernel.ReleaseServiceThread(service_thread);
|
||||||
}
|
|
||||||
|
|
||||||
void SessionRequestHandler::AcceptSession(KServerPort* server_port) {
|
|
||||||
auto* server_session = server_port->AcceptSession();
|
|
||||||
ASSERT(server_session != nullptr);
|
|
||||||
|
|
||||||
RegisterSession(server_session, std::make_shared<SessionRequestManager>(kernel));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SessionRequestHandler::RegisterSession(KServerSession* server_session,
|
|
||||||
std::shared_ptr<SessionRequestManager> manager) {
|
|
||||||
manager->SetSessionHandler(shared_from_this());
|
|
||||||
service_thread.lock()->RegisterServerSession(server_session, manager);
|
|
||||||
server_session->Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {}
|
SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {}
|
||||||
|
@ -107,7 +92,7 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
|
// Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
|
||||||
ASSERT(context.GetManager().get() == this);
|
context.SetSessionRequestManager(server_session->GetSessionRequestManager());
|
||||||
|
|
||||||
// If there is a DomainMessageHeader, then this is CommandType "Request"
|
// If there is a DomainMessageHeader, then this is CommandType "Request"
|
||||||
const auto& domain_message_header = context.GetDomainMessageHeader();
|
const auto& domain_message_header = context.GetDomainMessageHeader();
|
||||||
|
@ -145,6 +130,31 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result SessionRequestManager::QueueSyncRequest(KSession* parent,
|
||||||
|
std::shared_ptr<HLERequestContext>&& context) {
|
||||||
|
// Ensure we have a session request handler
|
||||||
|
if (this->HasSessionRequestHandler(*context)) {
|
||||||
|
if (auto strong_ptr = this->GetServiceThread().lock()) {
|
||||||
|
strong_ptr->QueueSyncRequest(*parent, std::move(context));
|
||||||
|
} else {
|
||||||
|
ASSERT_MSG(false, "strong_ptr is nullptr!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ASSERT_MSG(false, "handler is invalid!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionRequestHandler::ClientConnected(KServerSession* session) {
|
||||||
|
session->GetSessionRequestManager()->SetSessionHandler(shared_from_this());
|
||||||
|
|
||||||
|
// Ensure our server session is tracked globally.
|
||||||
|
kernel.RegisterServerObject(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionRequestHandler::ClientDisconnected(KServerSession* session) {}
|
||||||
|
|
||||||
HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
|
HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
|
||||||
KServerSession* server_session_, KThread* thread_)
|
KServerSession* server_session_, KThread* thread_)
|
||||||
: server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
|
: server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
|
||||||
|
@ -204,7 +214,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
|
||||||
// Padding to align to 16 bytes
|
// Padding to align to 16 bytes
|
||||||
rp.AlignWithPadding();
|
rp.AlignWithPadding();
|
||||||
|
|
||||||
if (GetManager()->IsDomain() &&
|
if (Session()->GetSessionRequestManager()->IsDomain() &&
|
||||||
((command_header->type == IPC::CommandType::Request ||
|
((command_header->type == IPC::CommandType::Request ||
|
||||||
command_header->type == IPC::CommandType::RequestWithContext) ||
|
command_header->type == IPC::CommandType::RequestWithContext) ||
|
||||||
!incoming)) {
|
!incoming)) {
|
||||||
|
@ -213,7 +223,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
|
||||||
if (incoming || domain_message_header) {
|
if (incoming || domain_message_header) {
|
||||||
domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
|
domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
|
||||||
} else {
|
} else {
|
||||||
if (GetManager()->IsDomain()) {
|
if (Session()->GetSessionRequestManager()->IsDomain()) {
|
||||||
LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
|
LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,11 +316,12 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
|
||||||
// Write the domain objects to the command buffer, these go after the raw untranslated data.
|
// Write the domain objects to the command buffer, these go after the raw untranslated data.
|
||||||
// TODO(Subv): This completely ignores C buffers.
|
// TODO(Subv): This completely ignores C buffers.
|
||||||
|
|
||||||
if (GetManager()->IsDomain()) {
|
if (server_session->GetSessionRequestManager()->IsDomain()) {
|
||||||
current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
|
current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
|
||||||
for (auto& object : outgoing_domain_objects) {
|
for (auto& object : outgoing_domain_objects) {
|
||||||
GetManager()->AppendDomainHandler(std::move(object));
|
server_session->GetSessionRequestManager()->AppendDomainHandler(std::move(object));
|
||||||
cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount());
|
cmd_buf[current_offset++] = static_cast<u32_le>(
|
||||||
|
server_session->GetSessionRequestManager()->DomainHandlerCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,13 +45,11 @@ class KAutoObject;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class KEvent;
|
class KEvent;
|
||||||
class KHandleTable;
|
class KHandleTable;
|
||||||
class KServerPort;
|
|
||||||
class KProcess;
|
class KProcess;
|
||||||
class KServerSession;
|
class KServerSession;
|
||||||
class KThread;
|
class KThread;
|
||||||
class KReadableEvent;
|
class KReadableEvent;
|
||||||
class KSession;
|
class KSession;
|
||||||
class SessionRequestManager;
|
|
||||||
class ServiceThread;
|
class ServiceThread;
|
||||||
|
|
||||||
enum class ThreadWakeupReason;
|
enum class ThreadWakeupReason;
|
||||||
|
@ -78,9 +76,19 @@ public:
|
||||||
virtual Result HandleSyncRequest(Kernel::KServerSession& session,
|
virtual Result HandleSyncRequest(Kernel::KServerSession& session,
|
||||||
Kernel::HLERequestContext& context) = 0;
|
Kernel::HLERequestContext& context) = 0;
|
||||||
|
|
||||||
void AcceptSession(KServerPort* server_port);
|
/**
|
||||||
void RegisterSession(KServerSession* server_session,
|
* Signals that a client has just connected to this HLE handler and keeps the
|
||||||
std::shared_ptr<SessionRequestManager> manager);
|
* associated ServerSession alive for the duration of the connection.
|
||||||
|
* @param server_session Owning pointer to the ServerSession associated with the connection.
|
||||||
|
*/
|
||||||
|
void ClientConnected(KServerSession* session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that a client has just disconnected from this HLE handler and releases the
|
||||||
|
* associated ServerSession.
|
||||||
|
* @param server_session ServerSession associated with the connection.
|
||||||
|
*/
|
||||||
|
void ClientDisconnected(KServerSession* session);
|
||||||
|
|
||||||
std::weak_ptr<ServiceThread> GetServiceThread() const {
|
std::weak_ptr<ServiceThread> GetServiceThread() const {
|
||||||
return service_thread;
|
return service_thread;
|
||||||
|
@ -162,6 +170,7 @@ public:
|
||||||
|
|
||||||
Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context);
|
Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context);
|
||||||
Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context);
|
Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context);
|
||||||
|
Result QueueSyncRequest(KSession* parent, std::shared_ptr<HLERequestContext>&& context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool convert_to_domain{};
|
bool convert_to_domain{};
|
||||||
|
@ -341,11 +350,11 @@ public:
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::shared_ptr<T> GetDomainHandler(std::size_t index) const {
|
std::shared_ptr<T> GetDomainHandler(std::size_t index) const {
|
||||||
return std::static_pointer_cast<T>(GetManager()->DomainHandler(index).lock());
|
return std::static_pointer_cast<T>(manager.lock()->DomainHandler(index).lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) {
|
void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) {
|
||||||
manager = manager_;
|
manager = std::move(manager_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Description() const;
|
std::string Description() const;
|
||||||
|
@ -354,10 +363,6 @@ public:
|
||||||
return *thread;
|
return *thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SessionRequestManager> GetManager() const {
|
|
||||||
return manager.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class IPC::ResponseBuilder;
|
friend class IPC::ResponseBuilder;
|
||||||
|
|
||||||
|
@ -391,7 +396,7 @@ private:
|
||||||
u32 handles_offset{};
|
u32 handles_offset{};
|
||||||
u32 domain_offset{};
|
u32 domain_offset{};
|
||||||
|
|
||||||
std::weak_ptr<SessionRequestManager> manager{};
|
std::weak_ptr<SessionRequestManager> manager;
|
||||||
|
|
||||||
KernelCore& kernel;
|
KernelCore& kernel;
|
||||||
Core::Memory::Memory& memory;
|
Core::Memory::Memory& memory;
|
||||||
|
|
|
@ -58,7 +58,8 @@ bool KClientPort::IsSignaled() const {
|
||||||
return num_sessions < max_sessions;
|
return num_sessions < max_sessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KClientPort::CreateSession(KClientSession** out) {
|
Result 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);
|
||||||
|
@ -103,7 +104,7 @@ Result 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();
|
||||||
|
|
|
@ -52,7 +52,8 @@ public:
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
Result CreateSession(KClientSession** out);
|
Result CreateSession(KClientSession** out,
|
||||||
|
std::shared_ptr<SessionRequestManager> session_manager = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<s32> num_sessions{};
|
std::atomic<s32> num_sessions{};
|
||||||
|
|
|
@ -57,6 +57,12 @@ Result KPort::EnqueueSession(KServerSession* session) {
|
||||||
|
|
||||||
server.EnqueueSession(session);
|
server.EnqueueSession(session);
|
||||||
|
|
||||||
|
if (auto session_ptr = server.GetSessionRequestHandler().lock()) {
|
||||||
|
session_ptr->ClientConnected(server.AcceptSession());
|
||||||
|
} else {
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,6 @@ void KServerPort::Initialize(KPort* parent_port_, std::string&& name_) {
|
||||||
// Set member variables.
|
// Set member variables.
|
||||||
parent = parent_port_;
|
parent = parent_port_;
|
||||||
name = std::move(name_);
|
name = std::move(name_);
|
||||||
|
|
||||||
kernel.RegisterServerObject(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KServerPort::IsLight() const {
|
bool KServerPort::IsLight() const {
|
||||||
|
@ -64,6 +62,9 @@ void KServerPort::Destroy() {
|
||||||
// Close our reference to our parent.
|
// Close our reference to our parent.
|
||||||
parent->Close();
|
parent->Close();
|
||||||
|
|
||||||
|
// Release host emulation members.
|
||||||
|
session_handler.reset();
|
||||||
|
|
||||||
// Ensure that the global list tracking server objects does not hold on to a reference.
|
// Ensure that the global list tracking server objects does not hold on to a reference.
|
||||||
kernel.UnregisterServerObject(this);
|
kernel.UnregisterServerObject(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,24 @@ public:
|
||||||
|
|
||||||
void Initialize(KPort* parent_port_, 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 {
|
||||||
|
return !session_handler.expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the HLE handler for this port.
|
||||||
|
SessionRequestHandlerWeakPtr GetSessionRequestHandler() const {
|
||||||
|
return session_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
|
||||||
|
* will inherit a reference to this handler.
|
||||||
|
*/
|
||||||
|
void SetSessionHandler(SessionRequestHandlerWeakPtr&& handler) {
|
||||||
|
session_handler = std::move(handler);
|
||||||
|
}
|
||||||
|
|
||||||
void EnqueueSession(KServerSession* pending_session);
|
void EnqueueSession(KServerSession* pending_session);
|
||||||
|
|
||||||
KServerSession* AcceptSession();
|
KServerSession* AcceptSession();
|
||||||
|
@ -47,6 +65,7 @@ private:
|
||||||
void CleanupSessions();
|
void CleanupSessions();
|
||||||
|
|
||||||
SessionList session_list;
|
SessionList session_list;
|
||||||
|
SessionRequestHandlerWeakPtr session_handler;
|
||||||
KPort* parent{};
|
KPort* parent{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
@ -33,10 +33,12 @@ KServerSession::KServerSession(KernelCore& kernel_)
|
||||||
|
|
||||||
KServerSession::~KServerSession() = default;
|
KServerSession::~KServerSession() = default;
|
||||||
|
|
||||||
void KServerSession::Initialize(KSession* parent_session_, std::string&& name_) {
|
void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
|
||||||
|
std::shared_ptr<SessionRequestManager> manager_) {
|
||||||
// Set member variables.
|
// Set member variables.
|
||||||
parent = parent_session_;
|
parent = parent_session_;
|
||||||
name = std::move(name_);
|
name = std::move(name_);
|
||||||
|
manager = manager_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KServerSession::Destroy() {
|
void KServerSession::Destroy() {
|
||||||
|
@ -45,99 +47,18 @@ void KServerSession::Destroy() {
|
||||||
this->CleanupRequests();
|
this->CleanupRequests();
|
||||||
|
|
||||||
parent->Close();
|
parent->Close();
|
||||||
|
|
||||||
|
// Release host emulation members.
|
||||||
|
manager.reset();
|
||||||
|
|
||||||
|
// Ensure that the global list tracking server objects does not hold on to a reference.
|
||||||
|
kernel.UnregisterServerObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KServerSession::OnClientClosed() {
|
void KServerSession::OnClientClosed() {
|
||||||
KScopedLightLock lk{m_lock};
|
if (manager && manager->HasSessionHandler()) {
|
||||||
|
manager->SessionHandler().ClientDisconnected(this);
|
||||||
// Handle any pending requests.
|
|
||||||
KSessionRequest* prev_request = nullptr;
|
|
||||||
while (true) {
|
|
||||||
// Declare variables for processing the request.
|
|
||||||
KSessionRequest* request = nullptr;
|
|
||||||
KEvent* event = nullptr;
|
|
||||||
KThread* thread = nullptr;
|
|
||||||
bool cur_request = false;
|
|
||||||
bool terminate = false;
|
|
||||||
|
|
||||||
// Get the next request.
|
|
||||||
{
|
|
||||||
KScopedSchedulerLock sl{kernel};
|
|
||||||
|
|
||||||
if (m_current_request != nullptr && m_current_request != prev_request) {
|
|
||||||
// Set the request, open a reference as we process it.
|
|
||||||
request = m_current_request;
|
|
||||||
request->Open();
|
|
||||||
cur_request = true;
|
|
||||||
|
|
||||||
// Get thread and event for the request.
|
|
||||||
thread = request->GetThread();
|
|
||||||
event = request->GetEvent();
|
|
||||||
|
|
||||||
// If the thread is terminating, handle that.
|
|
||||||
if (thread->IsTerminationRequested()) {
|
|
||||||
request->ClearThread();
|
|
||||||
request->ClearEvent();
|
|
||||||
terminate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_request = request;
|
|
||||||
} else if (!m_request_list.empty()) {
|
|
||||||
// Pop the request from the front of the list.
|
|
||||||
request = std::addressof(m_request_list.front());
|
|
||||||
m_request_list.pop_front();
|
|
||||||
|
|
||||||
// Get thread and event for the request.
|
|
||||||
thread = request->GetThread();
|
|
||||||
event = request->GetEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are no requests, we're done.
|
|
||||||
if (request == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All requests must have threads.
|
|
||||||
ASSERT(thread != nullptr);
|
|
||||||
|
|
||||||
// Ensure that we close the request when done.
|
|
||||||
SCOPE_EXIT({ request->Close(); });
|
|
||||||
|
|
||||||
// If we're terminating, close a reference to the thread and event.
|
|
||||||
if (terminate) {
|
|
||||||
thread->Close();
|
|
||||||
if (event != nullptr) {
|
|
||||||
event->Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we need to, reply.
|
|
||||||
if (event != nullptr && !cur_request) {
|
|
||||||
// There must be no mappings.
|
|
||||||
ASSERT(request->GetSendCount() == 0);
|
|
||||||
ASSERT(request->GetReceiveCount() == 0);
|
|
||||||
ASSERT(request->GetExchangeCount() == 0);
|
|
||||||
|
|
||||||
// // Get the process and page table.
|
|
||||||
// KProcess *client_process = thread->GetOwnerProcess();
|
|
||||||
// auto &client_pt = client_process->GetPageTable();
|
|
||||||
|
|
||||||
// // Reply to the request.
|
|
||||||
// ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(),
|
|
||||||
// ResultSessionClosed);
|
|
||||||
|
|
||||||
// // Unlock the buffer.
|
|
||||||
// // NOTE: Nintendo does not check the result of this.
|
|
||||||
// client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize());
|
|
||||||
|
|
||||||
// Signal the event.
|
|
||||||
event->Signal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify.
|
|
||||||
this->NotifyAvailable(ResultSessionClosed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KServerSession::IsSignaled() const {
|
bool KServerSession::IsSignaled() const {
|
||||||
|
@ -152,6 +73,24 @@ bool KServerSession::IsSignaled() const {
|
||||||
return !m_request_list.empty() && m_current_request == nullptr;
|
return !m_request_list.empty() && m_current_request == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
|
||||||
|
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
|
||||||
|
auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
|
||||||
|
|
||||||
|
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
||||||
|
|
||||||
|
return manager->QueueSyncRequest(parent, std::move(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
||||||
|
Result result = manager->CompleteSyncRequest(this, context);
|
||||||
|
|
||||||
|
// The calling thread is waiting for this request to complete, so wake it up.
|
||||||
|
context.GetThread().EndWait(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Result KServerSession::OnRequest(KSessionRequest* request) {
|
Result KServerSession::OnRequest(KSessionRequest* request) {
|
||||||
// Create the wait queue.
|
// Create the wait queue.
|
||||||
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
|
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
|
||||||
|
@ -166,6 +105,13 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
|
||||||
// Check that we're not terminating.
|
// Check that we're not terminating.
|
||||||
R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
|
R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
|
||||||
|
|
||||||
|
if (manager) {
|
||||||
|
// HLE request.
|
||||||
|
auto& memory{kernel.System().Memory()};
|
||||||
|
this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
|
||||||
|
} else {
|
||||||
|
// Non-HLE request.
|
||||||
|
|
||||||
// Get whether we're empty.
|
// Get whether we're empty.
|
||||||
const bool was_empty = m_request_list.empty();
|
const bool was_empty = m_request_list.empty();
|
||||||
|
|
||||||
|
@ -177,6 +123,7 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
|
||||||
if (was_empty) {
|
if (was_empty) {
|
||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we have a request event, this is asynchronous, and we don't need to wait.
|
// If we have a request event, this is asynchronous, and we don't need to wait.
|
||||||
R_SUCCEED_IF(request->GetEvent() != nullptr);
|
R_SUCCEED_IF(request->GetEvent() != nullptr);
|
||||||
|
@ -189,7 +136,7 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
|
||||||
return GetCurrentThread(kernel).GetWaitResult();
|
return GetCurrentThread(kernel).GetWaitResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KServerSession::SendReply(bool is_hle) {
|
Result KServerSession::SendReply() {
|
||||||
// Lock the session.
|
// Lock the session.
|
||||||
KScopedLightLock lk{m_lock};
|
KScopedLightLock lk{m_lock};
|
||||||
|
|
||||||
|
@ -224,10 +171,6 @@ Result KServerSession::SendReply(bool is_hle) {
|
||||||
Result result = ResultSuccess;
|
Result result = ResultSuccess;
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
// If we're not closed, send the reply.
|
// If we're not closed, send the reply.
|
||||||
if (is_hle) {
|
|
||||||
// HLE servers write directly to a pointer to the thread command buffer. Therefore
|
|
||||||
// the reply has already been written in this case.
|
|
||||||
} else {
|
|
||||||
Core::Memory::Memory& memory{kernel.System().Memory()};
|
Core::Memory::Memory& memory{kernel.System().Memory()};
|
||||||
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
||||||
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
||||||
|
@ -235,7 +178,6 @@ Result KServerSession::SendReply(bool is_hle) {
|
||||||
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
||||||
auto* dst_msg_buffer = memory.GetPointer(client_message);
|
auto* dst_msg_buffer = memory.GetPointer(client_message);
|
||||||
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
result = ResultSessionClosed;
|
result = ResultSessionClosed;
|
||||||
}
|
}
|
||||||
|
@ -281,8 +223,7 @@ Result KServerSession::SendReply(bool is_hle) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context,
|
Result KServerSession::ReceiveRequest() {
|
||||||
std::weak_ptr<SessionRequestManager> manager) {
|
|
||||||
// Lock the session.
|
// Lock the session.
|
||||||
KScopedLightLock lk{m_lock};
|
KScopedLightLock lk{m_lock};
|
||||||
|
|
||||||
|
@ -326,22 +267,12 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_co
|
||||||
|
|
||||||
// Receive the message.
|
// Receive the message.
|
||||||
Core::Memory::Memory& memory{kernel.System().Memory()};
|
Core::Memory::Memory& memory{kernel.System().Memory()};
|
||||||
if (out_context != nullptr) {
|
|
||||||
// HLE request.
|
|
||||||
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))};
|
|
||||||
*out_context = std::make_shared<HLERequestContext>(kernel, memory, this, client_thread);
|
|
||||||
(*out_context)->SetSessionRequestManager(manager);
|
|
||||||
(*out_context)
|
|
||||||
->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
|
|
||||||
cmd_buf);
|
|
||||||
} else {
|
|
||||||
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
||||||
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
||||||
|
|
||||||
auto* src_msg_buffer = memory.GetPointer(client_message);
|
auto* src_msg_buffer = memory.GetPointer(client_message);
|
||||||
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
||||||
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
||||||
}
|
|
||||||
|
|
||||||
// We succeeded.
|
// We succeeded.
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -16,11 +16,21 @@
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Core::Memory {
|
||||||
|
class Memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core::Timing {
|
||||||
|
class CoreTiming;
|
||||||
|
struct EventType;
|
||||||
|
} // namespace Core::Timing
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class HLERequestContext;
|
class HLERequestContext;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class KSession;
|
class KSession;
|
||||||
|
class SessionRequestHandler;
|
||||||
class SessionRequestManager;
|
class SessionRequestManager;
|
||||||
class KThread;
|
class KThread;
|
||||||
|
|
||||||
|
@ -36,7 +46,8 @@ public:
|
||||||
|
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
|
|
||||||
void Initialize(KSession* parent_session_, std::string&& name_);
|
void Initialize(KSession* parent_session_, std::string&& name_,
|
||||||
|
std::shared_ptr<SessionRequestManager> manager_);
|
||||||
|
|
||||||
KSession* GetParent() {
|
KSession* GetParent() {
|
||||||
return parent;
|
return parent;
|
||||||
|
@ -49,26 +60,38 @@ public:
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
void OnClientClosed();
|
void OnClientClosed();
|
||||||
|
|
||||||
|
/// Gets the session request manager, which forwards requests to the underlying service
|
||||||
|
std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
/// TODO: flesh these out to match the real kernel
|
/// TODO: flesh these out to match the real kernel
|
||||||
Result OnRequest(KSessionRequest* request);
|
Result OnRequest(KSessionRequest* request);
|
||||||
Result SendReply(bool is_hle = false);
|
Result SendReply();
|
||||||
Result ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context = nullptr,
|
Result ReceiveRequest();
|
||||||
std::weak_ptr<SessionRequestManager> manager = {});
|
|
||||||
|
|
||||||
Result SendReplyHLE() {
|
|
||||||
return SendReply(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Frees up waiting client sessions when this server session is about to die
|
/// Frees up waiting client sessions when this server session is about to die
|
||||||
void CleanupRequests();
|
void CleanupRequests();
|
||||||
|
|
||||||
|
/// Queues a sync request from the emulated application.
|
||||||
|
Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
|
||||||
|
|
||||||
|
/// Completes a sync request from the emulated application.
|
||||||
|
Result CompleteSyncRequest(HLERequestContext& context);
|
||||||
|
|
||||||
|
/// This session's HLE request handlers; if nullptr, this is not an HLE server
|
||||||
|
std::shared_ptr<SessionRequestManager> manager;
|
||||||
|
|
||||||
|
/// When set to True, converts the session to a domain at the end of the command
|
||||||
|
bool convert_to_domain{};
|
||||||
|
|
||||||
/// KSession that owns this KServerSession
|
/// KSession that owns this KServerSession
|
||||||
KSession* parent{};
|
KSession* parent{};
|
||||||
|
|
||||||
/// List of threads which are pending a reply.
|
/// List of threads which are pending a reply.
|
||||||
boost::intrusive::list<KSessionRequest> m_request_list;
|
boost::intrusive::list<KSessionRequest> m_request_list;
|
||||||
KSessionRequest* m_current_request{};
|
KSessionRequest* m_current_request;
|
||||||
|
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,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
|
||||||
|
@ -25,7 +26,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.
|
||||||
|
|
|
@ -21,7 +21,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;
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,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;
|
||||||
|
|
||||||
|
@ -85,8 +86,6 @@ struct KernelCore::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterHostThread();
|
RegisterHostThread();
|
||||||
|
|
||||||
default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeCores() {
|
void InitializeCores() {
|
||||||
|
@ -704,15 +703,6 @@ struct KernelCore::Impl {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
|
|
||||||
auto search = service_interface_handlers.find(name);
|
|
||||||
if (search == service_interface_handlers.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
search->second(system.ServiceManager(), server_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterServerObject(KAutoObject* server_object) {
|
void RegisterServerObject(KAutoObject* server_object) {
|
||||||
std::scoped_lock lk(server_objects_lock);
|
std::scoped_lock lk(server_objects_lock);
|
||||||
server_objects.insert(server_object);
|
server_objects.insert(server_object);
|
||||||
|
@ -725,7 +715,7 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
|
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
|
||||||
const std::string& name) {
|
const std::string& name) {
|
||||||
auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, name);
|
auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, 1, name);
|
||||||
|
|
||||||
service_threads_manager.QueueWork(
|
service_threads_manager.QueueWork(
|
||||||
[this, service_thread]() { service_threads.emplace(service_thread); });
|
[this, service_thread]() { service_threads.emplace(service_thread); });
|
||||||
|
@ -784,7 +774,6 @@ struct KernelCore::Impl {
|
||||||
/// Map of named ports managed by the kernel, which can be retrieved using
|
/// Map of named ports managed by the kernel, which can be retrieved using
|
||||||
/// the ConnectToPort SVC.
|
/// the ConnectToPort SVC.
|
||||||
std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
|
std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
|
||||||
std::unordered_map<std::string, ServiceInterfaceHandlerFn> service_interface_handlers;
|
|
||||||
NamedPortTable named_ports;
|
NamedPortTable named_ports;
|
||||||
std::unordered_set<KAutoObject*> server_objects;
|
std::unordered_set<KAutoObject*> server_objects;
|
||||||
std::unordered_set<KAutoObject*> registered_objects;
|
std::unordered_set<KAutoObject*> registered_objects;
|
||||||
|
@ -992,19 +981,10 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&
|
||||||
impl->service_interface_factory.emplace(std::move(name), factory);
|
impl->service_interface_factory.emplace(std::move(name), factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::RegisterInterfaceForNamedService(std::string name,
|
|
||||||
ServiceInterfaceHandlerFn&& handler) {
|
|
||||||
impl->service_interface_handlers.emplace(std::move(name), handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
|
KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
|
||||||
return impl->CreateNamedServicePort(std::move(name));
|
return impl->CreateNamedServicePort(std::move(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
|
|
||||||
impl->RegisterNamedServiceHandler(std::move(name), server_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KernelCore::RegisterServerObject(KAutoObject* server_object) {
|
void KernelCore::RegisterServerObject(KAutoObject* server_object) {
|
||||||
impl->RegisterServerObject(server_object);
|
impl->RegisterServerObject(server_object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,6 @@ class KPort;
|
||||||
class KProcess;
|
class KProcess;
|
||||||
class KResourceLimit;
|
class KResourceLimit;
|
||||||
class KScheduler;
|
class KScheduler;
|
||||||
class KServerPort;
|
|
||||||
class KServerSession;
|
class KServerSession;
|
||||||
class KSession;
|
class KSession;
|
||||||
class KSessionRequest;
|
class KSessionRequest;
|
||||||
|
@ -64,8 +63,6 @@ class TimeManager;
|
||||||
using ServiceInterfaceFactory =
|
using ServiceInterfaceFactory =
|
||||||
std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
|
std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
|
||||||
|
|
||||||
using ServiceInterfaceHandlerFn = std::function<void(Service::SM::ServiceManager&, KServerPort*)>;
|
|
||||||
|
|
||||||
namespace Init {
|
namespace Init {
|
||||||
struct KSlabResourceCounts;
|
struct KSlabResourceCounts;
|
||||||
}
|
}
|
||||||
|
@ -195,15 +192,9 @@ public:
|
||||||
/// Registers a named HLE service, passing a factory used to open a port to that service.
|
/// Registers a named HLE service, passing a factory used to open a port to that service.
|
||||||
void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
|
void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
|
||||||
|
|
||||||
/// Registers a setup function for the named HLE service.
|
|
||||||
void RegisterInterfaceForNamedService(std::string name, ServiceInterfaceHandlerFn&& handler);
|
|
||||||
|
|
||||||
/// Opens a port to a service previously registered with RegisterNamedService.
|
/// Opens a port to a service previously registered with RegisterNamedService.
|
||||||
KClientPort* CreateNamedServicePort(std::string name);
|
KClientPort* CreateNamedServicePort(std::string name);
|
||||||
|
|
||||||
/// Accepts a session on a port created by CreateNamedServicePort.
|
|
||||||
void RegisterNamedServiceHandler(std::string name, KServerPort* server_port);
|
|
||||||
|
|
||||||
/// Registers a server session or port with the gobal emulation state, to be freed on shutdown.
|
/// Registers a server session or port with the gobal emulation state, to be freed on shutdown.
|
||||||
/// This is necessary because we do not emulate processes for HLE sessions and ports.
|
/// This is necessary because we do not emulate processes for HLE sessions and ports.
|
||||||
void RegisterServerObject(KAutoObject* server_object);
|
void RegisterServerObject(KAutoObject* server_object);
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
|
||||||
#include "core/hle/kernel/k_event.h"
|
|
||||||
#include "core/hle/kernel/k_scoped_resource_reservation.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"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
@ -22,198 +19,101 @@ namespace Kernel {
|
||||||
|
|
||||||
class ServiceThread::Impl final {
|
class ServiceThread::Impl final {
|
||||||
public:
|
public:
|
||||||
explicit Impl(KernelCore& kernel, const std::string& service_name);
|
explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
|
||||||
~Impl();
|
~Impl();
|
||||||
|
|
||||||
void WaitAndProcessImpl();
|
void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||||
void SessionClosed(KServerSession* server_session,
|
|
||||||
std::shared_ptr<SessionRequestManager> manager);
|
|
||||||
void LoopProcess();
|
|
||||||
|
|
||||||
void RegisterServerSession(KServerSession* session,
|
|
||||||
std::shared_ptr<SessionRequestManager> manager);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KernelCore& kernel;
|
std::vector<std::jthread> threads;
|
||||||
|
std::queue<std::function<void()>> requests;
|
||||||
std::jthread m_thread;
|
std::mutex queue_mutex;
|
||||||
std::mutex m_session_mutex;
|
std::condition_variable_any condition;
|
||||||
std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions;
|
const std::string service_name;
|
||||||
KEvent* m_wakeup_event;
|
|
||||||
KProcess* m_process;
|
|
||||||
std::atomic<bool> m_shutdown_requested;
|
|
||||||
const std::string m_service_name;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void ServiceThread::Impl::WaitAndProcessImpl() {
|
ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)
|
||||||
// Create local list of waitable sessions.
|
: service_name{name} {
|
||||||
std::vector<KSynchronizationObject*> objs;
|
for (std::size_t i = 0; i < num_threads; ++i) {
|
||||||
std::vector<std::shared_ptr<SessionRequestManager>> managers;
|
threads.emplace_back([this, &kernel](std::stop_token stop_token) {
|
||||||
|
Common::SetCurrentThreadName(std::string{service_name}.c_str());
|
||||||
|
|
||||||
|
// Wait for first request before trying to acquire a render context
|
||||||
{
|
{
|
||||||
// Lock to get the set.
|
std::unique_lock lock{queue_mutex};
|
||||||
std::scoped_lock lk{m_session_mutex};
|
condition.wait(lock, stop_token, [this] { return !requests.empty(); });
|
||||||
|
|
||||||
// Reserve the needed quantity.
|
|
||||||
objs.reserve(m_sessions.size() + 1);
|
|
||||||
managers.reserve(m_sessions.size());
|
|
||||||
|
|
||||||
// Copy to our local list.
|
|
||||||
for (const auto& [session, manager] : m_sessions) {
|
|
||||||
objs.push_back(session);
|
|
||||||
managers.push_back(manager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the wakeup event at the end.
|
if (stop_token.stop_requested()) {
|
||||||
objs.push_back(&m_wakeup_event->GetReadableEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait on the list of sessions.
|
|
||||||
s32 index{-1};
|
|
||||||
Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(),
|
|
||||||
static_cast<s32>(objs.size()), -1);
|
|
||||||
ASSERT(!rc.IsFailure());
|
|
||||||
|
|
||||||
// If this was the wakeup event, clear it and finish.
|
|
||||||
if (index >= static_cast<s64>(objs.size() - 1)) {
|
|
||||||
m_wakeup_event->Clear();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This event is from a server session.
|
// Allocate a dummy guest thread for this host thread.
|
||||||
auto* server_session = static_cast<KServerSession*>(objs[index]);
|
|
||||||
auto& manager = managers[index];
|
|
||||||
|
|
||||||
// Fetch the HLE request context.
|
|
||||||
std::shared_ptr<HLERequestContext> context;
|
|
||||||
rc = server_session->ReceiveRequest(&context, manager);
|
|
||||||
|
|
||||||
// If the session was closed, handle that.
|
|
||||||
if (rc == ResultSessionClosed) {
|
|
||||||
SessionClosed(server_session, manager);
|
|
||||||
|
|
||||||
// Finish.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle other cases
|
|
||||||
ASSERT(rc == ResultSuccess);
|
|
||||||
|
|
||||||
// Perform the request.
|
|
||||||
Result service_rc = manager->CompleteSyncRequest(server_session, *context);
|
|
||||||
|
|
||||||
// Reply to the client.
|
|
||||||
rc = server_session->SendReplyHLE();
|
|
||||||
|
|
||||||
if (rc == ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) {
|
|
||||||
SessionClosed(server_session, manager);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle other cases
|
|
||||||
ASSERT(rc == ResultSuccess);
|
|
||||||
ASSERT(service_rc == ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
|
|
||||||
std::shared_ptr<SessionRequestManager> manager) {
|
|
||||||
{
|
|
||||||
// Lock to get the set.
|
|
||||||
std::scoped_lock lk{m_session_mutex};
|
|
||||||
|
|
||||||
// Erase the session.
|
|
||||||
ASSERT(m_sessions.erase(server_session) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close our reference to the server session.
|
|
||||||
server_session->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceThread::Impl::LoopProcess() {
|
|
||||||
Common::SetCurrentThreadName(m_service_name.c_str());
|
|
||||||
|
|
||||||
kernel.RegisterHostThread();
|
kernel.RegisterHostThread();
|
||||||
|
|
||||||
while (!m_shutdown_requested.load()) {
|
while (true) {
|
||||||
WaitAndProcessImpl();
|
std::function<void()> task;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceThread::Impl::RegisterServerSession(KServerSession* server_session,
|
|
||||||
std::shared_ptr<SessionRequestManager> manager) {
|
|
||||||
// Open the server session.
|
|
||||||
server_session->Open();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Lock to get the set.
|
std::unique_lock lock{queue_mutex};
|
||||||
std::scoped_lock lk{m_session_mutex};
|
condition.wait(lock, stop_token, [this] { return !requests.empty(); });
|
||||||
|
|
||||||
// Insert the session and manager.
|
if (stop_token.stop_requested()) {
|
||||||
m_sessions[server_session] = manager;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal the wakeup event.
|
if (requests.empty()) {
|
||||||
m_wakeup_event->Signal();
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
task = std::move(requests.front());
|
||||||
|
requests.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
task();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServiceThread::Impl::QueueSyncRequest(KSession& session,
|
||||||
|
std::shared_ptr<HLERequestContext>&& context) {
|
||||||
|
{
|
||||||
|
std::unique_lock lock{queue_mutex};
|
||||||
|
|
||||||
|
auto* server_session{&session.GetServerSession()};
|
||||||
|
|
||||||
|
// Open a reference to the session to ensure it is not closes while the service request
|
||||||
|
// completes asynchronously.
|
||||||
|
server_session->Open();
|
||||||
|
|
||||||
|
requests.emplace([server_session, context{std::move(context)}]() {
|
||||||
|
// Close the reference.
|
||||||
|
SCOPE_EXIT({ server_session->Close(); });
|
||||||
|
|
||||||
|
// Complete the service request.
|
||||||
|
server_session->CompleteSyncRequest(*context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
condition.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceThread::Impl::~Impl() {
|
ServiceThread::Impl::~Impl() {
|
||||||
// Shut down the processing thread.
|
condition.notify_all();
|
||||||
m_shutdown_requested.store(true);
|
for (auto& thread : threads) {
|
||||||
m_wakeup_event->Signal();
|
thread.request_stop();
|
||||||
m_thread.join();
|
thread.join();
|
||||||
|
}
|
||||||
// Lock mutex.
|
|
||||||
m_session_mutex.lock();
|
|
||||||
|
|
||||||
// Close all remaining sessions.
|
|
||||||
for (const auto& [server_session, manager] : m_sessions) {
|
|
||||||
server_session->Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy remaining managers.
|
ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name)
|
||||||
m_sessions.clear();
|
: impl{std::make_unique<Impl>(kernel, num_threads, name)} {}
|
||||||
|
|
||||||
// Close event.
|
|
||||||
m_wakeup_event->GetReadableEvent().Close();
|
|
||||||
m_wakeup_event->Close();
|
|
||||||
|
|
||||||
// Close process.
|
|
||||||
m_process->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
|
|
||||||
: kernel{kernel_}, m_service_name{service_name} {
|
|
||||||
// Initialize process.
|
|
||||||
m_process = KProcess::Create(kernel);
|
|
||||||
KProcess::Initialize(m_process, kernel.System(), service_name,
|
|
||||||
KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit());
|
|
||||||
|
|
||||||
// Reserve a new event from the process resource limit
|
|
||||||
KScopedResourceReservation event_reservation(m_process, LimitableResource::Events);
|
|
||||||
ASSERT(event_reservation.Succeeded());
|
|
||||||
|
|
||||||
// Initialize event.
|
|
||||||
m_wakeup_event = KEvent::Create(kernel);
|
|
||||||
m_wakeup_event->Initialize(m_process);
|
|
||||||
|
|
||||||
// Commit the event reservation.
|
|
||||||
event_reservation.Commit();
|
|
||||||
|
|
||||||
// Register the event.
|
|
||||||
KEvent::Register(kernel, m_wakeup_event);
|
|
||||||
|
|
||||||
// Start thread.
|
|
||||||
m_thread = std::jthread([this] { LoopProcess(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)
|
|
||||||
: impl{std::make_unique<Impl>(kernel, name)} {}
|
|
||||||
|
|
||||||
ServiceThread::~ServiceThread() = default;
|
ServiceThread::~ServiceThread() = default;
|
||||||
|
|
||||||
void ServiceThread::RegisterServerSession(KServerSession* session,
|
void ServiceThread::QueueSyncRequest(KSession& session,
|
||||||
std::shared_ptr<SessionRequestManager> manager) {
|
std::shared_ptr<HLERequestContext>&& context) {
|
||||||
impl->RegisterServerSession(session, manager);
|
impl->QueueSyncRequest(session, std::move(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -11,15 +11,13 @@ namespace Kernel {
|
||||||
class HLERequestContext;
|
class HLERequestContext;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class KSession;
|
class KSession;
|
||||||
class SessionRequestManager;
|
|
||||||
|
|
||||||
class ServiceThread final {
|
class ServiceThread final {
|
||||||
public:
|
public:
|
||||||
explicit ServiceThread(KernelCore& kernel, const std::string& name);
|
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
|
||||||
~ServiceThread();
|
~ServiceThread();
|
||||||
|
|
||||||
void RegisterServerSession(KServerSession* session,
|
void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||||
std::shared_ptr<SessionRequestManager> manager);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Impl;
|
class Impl;
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "core/hle/kernel/k_memory_block.h"
|
#include "core/hle/kernel/k_memory_block.h"
|
||||||
#include "core/hle/kernel/k_memory_layout.h"
|
#include "core/hle/kernel/k_memory_layout.h"
|
||||||
#include "core/hle/kernel/k_page_table.h"
|
#include "core/hle/kernel/k_page_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_readable_event.h"
|
#include "core/hle/kernel/k_readable_event.h"
|
||||||
#include "core/hle/kernel/k_resource_limit.h"
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
|
@ -383,11 +382,10 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n
|
||||||
|
|
||||||
// Create a session.
|
// Create a session.
|
||||||
KClientSession* session{};
|
KClientSession* session{};
|
||||||
R_TRY(port->CreateSession(std::addressof(session)));
|
R_TRY(port->CreateSession(std::addressof(session),
|
||||||
|
std::make_shared<SessionRequestManager>(kernel)));
|
||||||
port->Close();
|
port->Close();
|
||||||
|
|
||||||
kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
|
|
||||||
|
|
||||||
// Register the session in the table, close the extra reference.
|
// Register the session in the table, close the extra reference.
|
||||||
handle_table.Register(*out, session);
|
handle_table.Register(*out, session);
|
||||||
session->Close();
|
session->Close();
|
||||||
|
|
|
@ -99,10 +99,6 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
|
||||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||||
// Wait for other threads to release access before destroying
|
// Wait for other threads to release access before destroying
|
||||||
const auto guard = LockService();
|
const auto guard = LockService();
|
||||||
|
|
||||||
if (named_port != nullptr) {
|
|
||||||
named_port->Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
||||||
|
@ -119,12 +115,13 @@ Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
|
||||||
|
|
||||||
ASSERT(!service_registered);
|
ASSERT(!service_registered);
|
||||||
|
|
||||||
named_port = Kernel::KPort::Create(kernel);
|
auto* port = Kernel::KPort::Create(kernel);
|
||||||
named_port->Initialize(max_sessions, false, service_name);
|
port->Initialize(max_sessions, false, service_name);
|
||||||
|
port->GetServerPort().SetSessionHandler(shared_from_this());
|
||||||
|
|
||||||
service_registered = true;
|
service_registered = true;
|
||||||
|
|
||||||
return named_port->GetClientPort();
|
return port->GetClientPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
||||||
|
@ -202,6 +199,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
|
||||||
switch (ctx.GetCommandType()) {
|
switch (ctx.GetCommandType()) {
|
||||||
case IPC::CommandType::Close:
|
case IPC::CommandType::Close:
|
||||||
case IPC::CommandType::TIPC_Close: {
|
case IPC::CommandType::TIPC_Close: {
|
||||||
|
session.Close();
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
result = IPC::ERR_REMOTE_PROCESS_DEAD;
|
result = IPC::ERR_REMOTE_PROCESS_DEAD;
|
||||||
|
@ -246,7 +244,6 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
|
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
|
||||||
|
|
||||||
system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory);
|
system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory);
|
||||||
system.Kernel().RegisterInterfaceForNamedService("sm:", SM::ServiceManager::SessionHandler);
|
|
||||||
|
|
||||||
Account::InstallInterfaces(system);
|
Account::InstallInterfaces(system);
|
||||||
AM::InstallInterfaces(*sm, *nv_flinger, system);
|
AM::InstallInterfaces(*sm, *nv_flinger, system);
|
||||||
|
|
|
@ -20,7 +20,6 @@ class System;
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class HLERequestContext;
|
class HLERequestContext;
|
||||||
class KClientPort;
|
class KClientPort;
|
||||||
class KPort;
|
|
||||||
class KServerSession;
|
class KServerSession;
|
||||||
class ServiceThread;
|
class ServiceThread;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -99,9 +98,6 @@ protected:
|
||||||
/// Identifier string used to connect to the service.
|
/// Identifier string used to connect to the service.
|
||||||
std::string service_name;
|
std::string service_name;
|
||||||
|
|
||||||
/// Port used by ManageNamedPort.
|
|
||||||
Kernel::KPort* named_port{};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend class ServiceFramework;
|
friend class ServiceFramework;
|
||||||
|
|
|
@ -43,10 +43,6 @@ Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core
|
||||||
return self.sm_interface->CreatePort();
|
return self.sm_interface->CreatePort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceManager::SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port) {
|
|
||||||
self.sm_interface->AcceptSession(server_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
|
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
|
||||||
Kernel::SessionRequestHandlerPtr handler) {
|
Kernel::SessionRequestHandlerPtr handler) {
|
||||||
|
|
||||||
|
@ -88,6 +84,7 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
|
||||||
|
|
||||||
port->Initialize(ServerSessionCountMax, false, name);
|
port->Initialize(ServerSessionCountMax, false, name);
|
||||||
auto handler = it->second;
|
auto handler = it->second;
|
||||||
|
port->GetServerPort().SetSessionHandler(std::move(handler));
|
||||||
|
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
@ -148,21 +145,23 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
|
||||||
|
|
||||||
// Find the named port.
|
// Find the named port.
|
||||||
auto port_result = service_manager.GetServicePort(name);
|
auto port_result = service_manager.GetServicePort(name);
|
||||||
auto service = service_manager.GetService<Kernel::SessionRequestHandler>(name);
|
if (port_result.Failed()) {
|
||||||
if (port_result.Failed() || !service) {
|
|
||||||
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
|
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
|
||||||
return port_result.Code();
|
return port_result.Code();
|
||||||
}
|
}
|
||||||
auto& port = port_result.Unwrap();
|
auto& port = port_result.Unwrap();
|
||||||
SCOPE_EXIT({ port->GetClientPort().Close(); });
|
SCOPE_EXIT({ port->GetClientPort().Close(); });
|
||||||
|
|
||||||
|
kernel.RegisterServerObject(&port->GetServerPort());
|
||||||
|
|
||||||
// Create a new session.
|
// Create a new session.
|
||||||
Kernel::KClientSession* session{};
|
Kernel::KClientSession* session{};
|
||||||
if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) {
|
if (const auto result = port->GetClientPort().CreateSession(
|
||||||
|
std::addressof(session), std::make_shared<Kernel::SessionRequestManager>(kernel));
|
||||||
|
result.IsError()) {
|
||||||
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
|
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
service->AcceptSession(&port->GetServerPort());
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
|
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ private:
|
||||||
class ServiceManager {
|
class ServiceManager {
|
||||||
public:
|
public:
|
||||||
static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
|
static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
|
||||||
static void SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port);
|
|
||||||
|
|
||||||
explicit ServiceManager(Kernel::KernelCore& kernel_);
|
explicit ServiceManager(Kernel::KernelCore& kernel_);
|
||||||
~ServiceManager();
|
~ServiceManager();
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
namespace Service::SM {
|
namespace Service::SM {
|
||||||
|
|
||||||
void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
|
void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
|
||||||
ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Session is already a domain");
|
ASSERT_MSG(!ctx.Session()->GetSessionRequestManager()->IsDomain(),
|
||||||
|
"Session is already a domain");
|
||||||
LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
|
LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
|
||||||
ctx.GetManager()->ConvertToDomainOnRequestEnd();
|
ctx.Session()->GetSessionRequestManager()->ConvertToDomainOnRequestEnd();
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -27,35 +28,23 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
|
||||||
void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
|
void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service, "called");
|
LOG_DEBUG(Service, "called");
|
||||||
|
|
||||||
auto& process = *ctx.GetThread().GetOwnerProcess();
|
auto& parent_session = *ctx.Session()->GetParent();
|
||||||
auto session_manager = ctx.GetManager();
|
auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort();
|
||||||
|
auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager();
|
||||||
|
|
||||||
// FIXME: this is duplicated from the SVC, it should just call it instead
|
// Create a session.
|
||||||
// once this is a proper process
|
Kernel::KClientSession* session{};
|
||||||
|
const Result result = parent_port.CreateSession(std::addressof(session), session_manager);
|
||||||
// Reserve a new session from the process resource limit.
|
if (result.IsError()) {
|
||||||
Kernel::KScopedResourceReservation session_reservation(&process,
|
LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw);
|
||||||
Kernel::LimitableResource::Sessions);
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
ASSERT(session_reservation.Succeeded());
|
rb.Push(result);
|
||||||
|
}
|
||||||
// Create the sessionn.
|
|
||||||
Kernel::KSession* session = Kernel::KSession::Create(system.Kernel());
|
|
||||||
ASSERT(session != nullptr);
|
|
||||||
|
|
||||||
// Initialize the session.
|
|
||||||
session->Initialize(nullptr, "");
|
|
||||||
|
|
||||||
// Commit the session reservation.
|
|
||||||
session_reservation.Commit();
|
|
||||||
|
|
||||||
// Register with manager.
|
|
||||||
session_manager->SessionHandler().RegisterSession(&session->GetServerSession(),
|
|
||||||
session_manager);
|
|
||||||
|
|
||||||
// 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(session->GetClientSession());
|
rb.PushMoveObjects(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
|
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
Loading…
Reference in a new issue