diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 45533ed45..ce5d94e99 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -26,20 +26,17 @@ ResultVal> ClientPort::Connect() { active_sessions++; // Create a new session pair, let the created sessions inherit the parent port's HLE handler. - auto sessions = - ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler, this); - auto client_session = std::get>(sessions); - auto server_session = std::get>(sessions); + auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), this); if (server_port->hle_handler) - server_port->hle_handler->ClientConnected(server_session); + server_port->hle_handler->ClientConnected(std::get>(sessions)); else - server_port->pending_sessions.push_back(std::move(server_session)); + server_port->pending_sessions.push_back(std::get>(sessions)); // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); - return MakeResult>(std::move(client_session)); + return MakeResult(std::get>(sessions)); } } // namespace diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 4886afa5c..0922b3f47 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -12,10 +12,12 @@ namespace Kernel { void SessionRequestHandler::ClientConnected(SharedPtr server_session) { + server_session->SetHleHandler(shared_from_this()); connected_sessions.push_back(server_session); } void SessionRequestHandler::ClientDisconnected(SharedPtr server_session) { + server_session->SetHleHandler(nullptr); boost::range::remove_erase(connected_sessions, server_session); } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index b3550734c..14f682f44 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -4,6 +4,7 @@ #pragma once +#include #include #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 * (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 { public: /** * Handles a sync request from the emulated application. diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index f6e0c7dbf..4d20c39a1 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -24,13 +24,12 @@ void ServerPort::Acquire(Thread* thread) { } std::tuple, SharedPtr> ServerPort::CreatePortPair( - u32 max_sessions, std::string name, std::shared_ptr hle_handler) { + u32 max_sessions, std::string name) { SharedPtr server_port(new ServerPort); SharedPtr client_port(new ClientPort); server_port->name = name + "_Server"; - server_port->hle_handler = std::move(hle_handler); client_port->name = name + "_Client"; client_port->server_port = server_port; client_port->max_sessions = max_sessions; diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 281559acf..f1419cd46 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -20,15 +20,13 @@ class ServerPort final : public WaitObject { public: /** * Creates a pair of ServerPort and an associated ClientPort. + * * @param max_sessions Maximum number of sessions to the port * @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 */ static std::tuple, SharedPtr> CreatePortPair( - u32 max_sessions, std::string name = "UnknownPort", - std::shared_ptr hle_handler = nullptr); + u32 max_sessions, std::string name = "UnknownPort"); std::string GetTypeName() const override { return "ServerPort"; @@ -42,6 +40,14 @@ public: 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 hle_handler_) { + hle_handler = std::move(hle_handler_); + } + std::string name; ///< Name of port (optional) std::vector> diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index dc39d5229..2dc709bc9 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -28,16 +28,14 @@ ServerSession::~ServerSession() { parent->server = nullptr; } -ResultVal> ServerSession::Create( - std::string name, std::shared_ptr hle_handler) { +ResultVal> ServerSession::Create(std::string name) { SharedPtr server_session(new ServerSession); server_session->name = std::move(name); server_session->signaled = false; - server_session->hle_handler = std::move(hle_handler); server_session->parent = nullptr; - return MakeResult>(std::move(server_session)); + return MakeResult(std::move(server_session)); } bool ServerSession::ShouldWait(Thread* thread) const { @@ -71,13 +69,9 @@ ResultCode ServerSession::HandleSyncRequest() { return RESULT_SUCCESS; } -ServerSession::SessionPair ServerSession::CreateSessionPair( - const std::string& name, std::shared_ptr hle_handler, - SharedPtr port) { - - auto server_session = - ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); - +ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name, + SharedPtr port) { + auto server_session = ServerSession::Create(name + "_Server").MoveFrom(); SharedPtr client_session(new ClientSession); client_session->name = name + "_Client"; diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 62d23cf0a..28f365b9e 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -50,14 +50,20 @@ public: /** * Creates a pair of ServerSession and an associated ClientSession. * @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. * @return The created session tuple */ - static SessionPair CreateSessionPair( - const std::string& name = "Unknown", - std::shared_ptr hle_handler = nullptr, - SharedPtr client_port = nullptr); + static SessionPair CreateSessionPair(const std::string& name = "Unknown", + SharedPtr 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 hle_handler_) { + hle_handler = std::move(hle_handler_); + } /** * Handle a sync request from the emulated application. @@ -83,11 +89,9 @@ private: * 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. * @param name Optional name of the server session. - * @param hle_handler Optional HLE handler for this server session. * @return The created server session */ - static ResultVal> Create( - std::string name = "Unknown", std::shared_ptr hle_handler = nullptr); + static ResultVal> Create(std::string name = "Unknown"); }; /** diff --git a/src/core/hle/result.h b/src/core/hle/result.h index c49650f7d..5f2cdbb96 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -415,6 +415,16 @@ ResultVal MakeResult(Args&&... args) { return ResultVal::WithCode(RESULT_SUCCESS, std::forward(args)...); } +/** + * Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just + * copy or move constructing. + */ +template +ResultVal> MakeResult(Arg&& arg) { + return ResultVal>::WithCode(RESULT_SUCCESS, + std::forward(arg)); +} + /** * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps * the contained value and assigns it to `target`, which can be either an l-value expression or a @@ -426,3 +436,12 @@ ResultVal MakeResult(Args&&... args) { if (CONCAT2(check_result_L, __LINE__).Failed()) \ return CONCAT2(check_result_L, __LINE__).Code(); \ target = std::move(*CONCAT2(check_result_L, __LINE__)) + +/** + * Analogous to CASCADE_RESULT, but for a bare ResultCode. The code will be propagated if + * non-success, or discarded otherwise. + */ +#define CASCADE_CODE(source) \ + auto CONCAT2(check_result_L, __LINE__) = source; \ + if (CONCAT2(check_result_L, __LINE__).IsError()) \ + return CONCAT2(check_result_L, __LINE__); diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index d6128d6a7..bbc5f8067 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -84,6 +84,10 @@ File::File(std::unique_ptr&& backend, const FileSys::Path& File::~File() {} void File::HandleSyncRequest(Kernel::SharedPtr server_session) { + using Kernel::ClientSession; + using Kernel::ServerSession; + using Kernel::SharedPtr; + u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { @@ -162,10 +166,9 @@ void File::HandleSyncRequest(Kernel::SharedPtr server_ses case FileCommand::OpenLinkFile: { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); - auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); - ClientConnected(std::get>(sessions)); - cmd_buff[3] = Kernel::g_handle_table - .Create(std::get>(sessions)) + auto sessions = ServerSession::CreateSessionPair(GetName()); + ClientConnected(std::get>(sessions)); + cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)) .ValueOr(INVALID_HANDLE); break; } diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 28e33caaa..3a3371c88 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -43,7 +43,7 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; typedef u64 ArchiveHandle; -class File final : public Kernel::SessionRequestHandler, public std::enable_shared_from_this { +class File final : public Kernel::SessionRequestHandler { public: File(std::unique_ptr&& backend, const FileSys::Path& path); ~File(); diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index fafdd3cc8..fe50403b9 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -20,8 +20,9 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace FS_User -using Kernel::SharedPtr; +using Kernel::ClientSession; using Kernel::ServerSession; +using Kernel::SharedPtr; namespace Service { namespace FS { @@ -79,11 +80,11 @@ static void OpenFile(Service::Interface* self) { rb.Push(file_res.Code()); if (file_res.Succeeded()) { std::shared_ptr file = *file_res; - auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); - file->ClientConnected(std::get>(sessions)); - rb.PushMoveHandles(Kernel::g_handle_table - .Create(std::get>(sessions)) - .MoveFrom()); + auto sessions = ServerSession::CreateSessionPair(file->GetName()); + file->ClientConnected(std::get>(sessions)); + + rb.PushMoveHandles( + Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom()); } else { rb.PushMoveHandles(0); 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; if (file_res.Succeeded()) { std::shared_ptr file = *file_res; - auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); - file->ClientConnected(std::get>(sessions)); - cmd_buff[3] = Kernel::g_handle_table - .Create(std::get>(sessions)) - .MoveFrom(); + auto sessions = ServerSession::CreateSessionPair(file->GetName()); + file->ClientConnected(std::get>(sessions)); + + cmd_buff[3] = + Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { cmd_buff[3] = 0; 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; if (dir_res.Succeeded()) { std::shared_ptr directory = *dir_res; - auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); - directory->ClientConnected(std::get>(sessions)); - cmd_buff[3] = Kernel::g_handle_table - .Create(std::get>(sessions)) - .MoveFrom(); + auto sessions = ServerSession::CreateSessionPair(directory->GetName()); + directory->ClientConnected(std::get>(sessions)); + + cmd_buff[3] = + Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { 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()); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index bb22e25be..8f7c97d54 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -105,18 +105,22 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - auto ports = - Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), - std::shared_ptr(interface_)); - auto client_port = std::get>(ports); + Kernel::SharedPtr server_port; + Kernel::SharedPtr client_port; + std::tie(server_port, client_port) = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); + + server_port->SetHleHandler(std::shared_ptr(interface_)); g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); } void AddService(Interface* interface_) { - auto ports = - Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), - std::shared_ptr(interface_)); - auto client_port = std::get>(ports); + Kernel::SharedPtr server_port; + Kernel::SharedPtr client_port; + std::tie(server_port, client_port) = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); + + server_port->SetHleHandler(std::shared_ptr(interface_)); g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); }