Kernel: Add a dedicated SetHleHandler method to ServerPort/ServerSession

This allows attaching a HLE handle to a ServerPort at any point after it
is created, allowing port/session creation to be generic between HLE and
regular services.
master
Yuri Kunde Schlesner 2017-06-05 22:39:26 +07:00
parent 7e5dd46cf4
commit 6354d08359
11 changed files with 73 additions and 62 deletions

@ -26,20 +26,17 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
active_sessions++; active_sessions++;
// Create a new session pair, let the created sessions inherit the parent port's HLE handler. // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
auto sessions = auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), this);
ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler, this);
auto client_session = std::get<SharedPtr<ClientSession>>(sessions);
auto server_session = std::get<SharedPtr<ServerSession>>(sessions);
if (server_port->hle_handler) if (server_port->hle_handler)
server_port->hle_handler->ClientConnected(server_session); server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
else else
server_port->pending_sessions.push_back(std::move(server_session)); server_port->pending_sessions.push_back(std::get<SharedPtr<ServerSession>>(sessions));
// Wake the threads waiting on the ServerPort // Wake the threads waiting on the ServerPort
server_port->WakeupAllWaitingThreads(); server_port->WakeupAllWaitingThreads();
return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); return MakeResult(std::get<SharedPtr<ClientSession>>(sessions));
} }
} // namespace } // namespace

@ -12,10 +12,12 @@
namespace Kernel { namespace Kernel {
void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) { void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) {
server_session->SetHleHandler(shared_from_this());
connected_sessions.push_back(server_session); connected_sessions.push_back(server_session);
} }
void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_session) { void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_session) {
server_session->SetHleHandler(nullptr);
boost::range::remove_erase(connected_sessions, server_session); boost::range::remove_erase(connected_sessions, server_session);
} }

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <memory>
#include <vector> #include <vector>
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
@ -16,7 +17,7 @@ class ServerSession;
* This can be provided to a ServerSession in order to hook into several relevant events * This can be provided to a ServerSession in order to hook into several relevant events
* (such as a new connection or a SyncRequest) so they can be implemented in the emulator. * (such as a new connection or a SyncRequest) so they can be implemented in the emulator.
*/ */
class SessionRequestHandler { class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
public: public:
/** /**
* Handles a sync request from the emulated application. * Handles a sync request from the emulated application.

@ -24,13 +24,12 @@ void ServerPort::Acquire(Thread* thread) {
} }
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
u32 max_sessions, std::string name, std::shared_ptr<SessionRequestHandler> hle_handler) { u32 max_sessions, std::string name) {
SharedPtr<ServerPort> server_port(new ServerPort); SharedPtr<ServerPort> server_port(new ServerPort);
SharedPtr<ClientPort> client_port(new ClientPort); SharedPtr<ClientPort> client_port(new ClientPort);
server_port->name = name + "_Server"; server_port->name = name + "_Server";
server_port->hle_handler = std::move(hle_handler);
client_port->name = name + "_Client"; client_port->name = name + "_Client";
client_port->server_port = server_port; client_port->server_port = server_port;
client_port->max_sessions = max_sessions; client_port->max_sessions = max_sessions;

@ -20,15 +20,13 @@ class ServerPort final : public WaitObject {
public: public:
/** /**
* Creates a pair of ServerPort and an associated ClientPort. * Creates a pair of ServerPort and an associated ClientPort.
*
* @param max_sessions Maximum number of sessions to the port * @param max_sessions Maximum number of sessions to the port
* @param name Optional name of the ports * @param name Optional name of the ports
* @param hle_handler Optional HLE handler template for the port,
* ServerSessions crated from this port will inherit a reference to this handler.
* @return The created port tuple * @return The created port tuple
*/ */
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
u32 max_sessions, std::string name = "UnknownPort", u32 max_sessions, std::string name = "UnknownPort");
std::shared_ptr<SessionRequestHandler> hle_handler = nullptr);
std::string GetTypeName() const override { std::string GetTypeName() const override {
return "ServerPort"; return "ServerPort";
@ -42,6 +40,14 @@ public:
return HANDLE_TYPE; return HANDLE_TYPE;
} }
/**
* Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
* will inherit a reference to this handler.
*/
void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) {
hle_handler = std::move(hle_handler_);
}
std::string name; ///< Name of port (optional) std::string name; ///< Name of port (optional)
std::vector<SharedPtr<WaitObject>> std::vector<SharedPtr<WaitObject>>

@ -28,16 +28,14 @@ ServerSession::~ServerSession() {
parent->server = nullptr; parent->server = nullptr;
} }
ResultVal<SharedPtr<ServerSession>> ServerSession::Create( ResultVal<SharedPtr<ServerSession>> ServerSession::Create(std::string name) {
std::string name, std::shared_ptr<SessionRequestHandler> hle_handler) {
SharedPtr<ServerSession> server_session(new ServerSession); SharedPtr<ServerSession> server_session(new ServerSession);
server_session->name = std::move(name); server_session->name = std::move(name);
server_session->signaled = false; server_session->signaled = false;
server_session->hle_handler = std::move(hle_handler);
server_session->parent = nullptr; server_session->parent = nullptr;
return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); return MakeResult(std::move(server_session));
} }
bool ServerSession::ShouldWait(Thread* thread) const { bool ServerSession::ShouldWait(Thread* thread) const {
@ -71,13 +69,9 @@ ResultCode ServerSession::HandleSyncRequest() {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ServerSession::SessionPair ServerSession::CreateSessionPair( ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name,
const std::string& name, std::shared_ptr<SessionRequestHandler> hle_handler,
SharedPtr<ClientPort> port) { SharedPtr<ClientPort> port) {
auto server_session = ServerSession::Create(name + "_Server").MoveFrom();
auto server_session =
ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom();
SharedPtr<ClientSession> client_session(new ClientSession); SharedPtr<ClientSession> client_session(new ClientSession);
client_session->name = name + "_Client"; client_session->name = name + "_Client";

@ -50,15 +50,21 @@ public:
/** /**
* Creates a pair of ServerSession and an associated ClientSession. * Creates a pair of ServerSession and an associated ClientSession.
* @param name Optional name of the ports. * @param name Optional name of the ports.
* @param hle_handler Optional HLE handler for this server session.
* @param client_port Optional The ClientPort that spawned this session. * @param client_port Optional The ClientPort that spawned this session.
* @return The created session tuple * @return The created session tuple
*/ */
static SessionPair CreateSessionPair( static SessionPair CreateSessionPair(const std::string& name = "Unknown",
const std::string& name = "Unknown",
std::shared_ptr<SessionRequestHandler> hle_handler = nullptr,
SharedPtr<ClientPort> client_port = nullptr); SharedPtr<ClientPort> client_port = nullptr);
/**
* Sets the HLE handler for the session. This handler will be called to service IPC requests
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
* implemented.)
*/
void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) {
hle_handler = std::move(hle_handler_);
}
/** /**
* Handle a sync request from the emulated application. * Handle a sync request from the emulated application.
* @returns ResultCode from the operation. * @returns ResultCode from the operation.
@ -83,11 +89,9 @@ private:
* Creates a server session. The server session can have an optional HLE handler, * Creates a server session. The server session can have an optional HLE handler,
* which will be invoked to handle the IPC requests that this session receives. * which will be invoked to handle the IPC requests that this session receives.
* @param name Optional name of the server session. * @param name Optional name of the server session.
* @param hle_handler Optional HLE handler for this server session.
* @return The created server session * @return The created server session
*/ */
static ResultVal<SharedPtr<ServerSession>> Create( static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
std::string name = "Unknown", std::shared_ptr<SessionRequestHandler> hle_handler = nullptr);
}; };
/** /**

@ -84,6 +84,10 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path&
File::~File() {} File::~File() {}
void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
using Kernel::ClientSession;
using Kernel::ServerSession;
using Kernel::SharedPtr;
u32* cmd_buff = Kernel::GetCommandBuffer(); u32* cmd_buff = Kernel::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
switch (cmd) { switch (cmd) {
@ -162,10 +166,9 @@ void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_ses
case FileCommand::OpenLinkFile: { case FileCommand::OpenLinkFile: {
LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); auto sessions = ServerSession::CreateSessionPair(GetName());
ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
cmd_buff[3] = Kernel::g_handle_table cmd_buff[3] = Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions))
.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
.ValueOr(INVALID_HANDLE); .ValueOr(INVALID_HANDLE);
break; break;
} }

@ -43,7 +43,7 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 };
typedef u64 ArchiveHandle; typedef u64 ArchiveHandle;
class File final : public Kernel::SessionRequestHandler, public std::enable_shared_from_this<File> { class File final : public Kernel::SessionRequestHandler {
public: public:
File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
~File(); ~File();

@ -20,8 +20,9 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace FS_User // Namespace FS_User
using Kernel::SharedPtr; using Kernel::ClientSession;
using Kernel::ServerSession; using Kernel::ServerSession;
using Kernel::SharedPtr;
namespace Service { namespace Service {
namespace FS { namespace FS {
@ -79,11 +80,11 @@ static void OpenFile(Service::Interface* self) {
rb.Push(file_res.Code()); rb.Push(file_res.Code());
if (file_res.Succeeded()) { if (file_res.Succeeded()) {
std::shared_ptr<File> file = *file_res; std::shared_ptr<File> file = *file_res;
auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); auto sessions = ServerSession::CreateSessionPair(file->GetName());
file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
rb.PushMoveHandles(Kernel::g_handle_table
.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) rb.PushMoveHandles(
.MoveFrom()); Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom());
} else { } else {
rb.PushMoveHandles(0); rb.PushMoveHandles(0);
LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
@ -145,11 +146,11 @@ static void OpenFileDirectly(Service::Interface* self) {
cmd_buff[1] = file_res.Code().raw; cmd_buff[1] = file_res.Code().raw;
if (file_res.Succeeded()) { if (file_res.Succeeded()) {
std::shared_ptr<File> file = *file_res; std::shared_ptr<File> file = *file_res;
auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); auto sessions = ServerSession::CreateSessionPair(file->GetName());
file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
cmd_buff[3] = Kernel::g_handle_table
.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) cmd_buff[3] =
.MoveFrom(); Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom();
} else { } else {
cmd_buff[3] = 0; cmd_buff[3] = 0;
LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u",
@ -412,11 +413,11 @@ static void OpenDirectory(Service::Interface* self) {
cmd_buff[1] = dir_res.Code().raw; cmd_buff[1] = dir_res.Code().raw;
if (dir_res.Succeeded()) { if (dir_res.Succeeded()) {
std::shared_ptr<Directory> directory = *dir_res; std::shared_ptr<Directory> directory = *dir_res;
auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); auto sessions = ServerSession::CreateSessionPair(directory->GetName());
directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); directory->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
cmd_buff[3] = Kernel::g_handle_table
.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) cmd_buff[3] =
.MoveFrom(); Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom();
} else { } else {
LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
dirname_type, dirname_size, dir_path.DebugStr().c_str()); dirname_type, dirname_size, dir_path.DebugStr().c_str());

@ -105,18 +105,22 @@ void Interface::Register(const FunctionInfo* functions, size_t n) {
// Module interface // Module interface
static void AddNamedPort(Interface* interface_) { static void AddNamedPort(Interface* interface_) {
auto ports = Kernel::SharedPtr<Kernel::ServerPort> server_port;
Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), Kernel::SharedPtr<Kernel::ClientPort> client_port;
std::shared_ptr<Interface>(interface_)); std::tie(server_port, client_port) =
auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName());
server_port->SetHleHandler(std::shared_ptr<Interface>(interface_));
g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port));
} }
void AddService(Interface* interface_) { void AddService(Interface* interface_) {
auto ports = Kernel::SharedPtr<Kernel::ServerPort> server_port;
Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), Kernel::SharedPtr<Kernel::ClientPort> client_port;
std::shared_ptr<Interface>(interface_)); std::tie(server_port, client_port) =
auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName());
server_port->SetHleHandler(std::shared_ptr<Interface>(interface_));
g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); g_srv_services.emplace(interface_->GetPortName(), std::move(client_port));
} }