2
1
Fork 0
mirror of https://github.com/yuzu-emu/yuzu.git synced 2024-07-04 23:31:19 +01:00

hle: kernel: Migrate KPort, KClientPort, and KServerPort to KAutoObject.

This commit is contained in:
bunnei 2021-04-23 17:00:15 -07:00
parent 7a06864100
commit 626f746971
22 changed files with 447 additions and 169 deletions

View file

@ -194,6 +194,8 @@ add_library(core STATIC
hle/kernel/k_page_linked_list.h hle/kernel/k_page_linked_list.h
hle/kernel/k_page_table.cpp hle/kernel/k_page_table.cpp
hle/kernel/k_page_table.h hle/kernel/k_page_table.h
hle/kernel/k_port.cpp
hle/kernel/k_port.h
hle/kernel/k_priority_queue.h hle/kernel/k_priority_queue.h
hle/kernel/k_readable_event.cpp hle/kernel/k_readable_event.cpp
hle/kernel/k_readable_event.h hle/kernel/k_readable_event.h

View file

@ -136,10 +136,10 @@ public:
context->AddDomainObject(std::move(iface)); context->AddDomainObject(std::move(iface));
} else { } else {
auto* session = Kernel::KSession::Create(kernel); auto* session = Kernel::KSession::Create(kernel);
session->Initialize(iface->GetServiceName()); session->Initialize(nullptr, iface->GetServiceName());
context->AddMoveObject(&session->GetClientSession()); context->AddMoveObject(&session->GetClientSession());
iface->ClientConnected(session); iface->ClientConnected(&session->GetServerSession());
} }
} }

View file

@ -35,14 +35,12 @@ SessionRequestHandler::SessionRequestHandler() = default;
SessionRequestHandler::~SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default;
void SessionRequestHandler::ClientConnected(KSession* session) { void SessionRequestHandler::ClientConnected(KServerSession* session) {
session->GetServerSession().SetHleHandler(shared_from_this()); session->SetHleHandler(shared_from_this());
sessions.push_back(session);
} }
void SessionRequestHandler::ClientDisconnected(KSession* session) { void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
session->GetServerSession().SetHleHandler(nullptr); session->SetHleHandler(nullptr);
boost::range::remove_erase(sessions, session);
} }
HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,

View file

@ -72,20 +72,14 @@ public:
* associated ServerSession alive for the duration of the connection. * associated ServerSession alive for the duration of the connection.
* @param server_session Owning pointer to the ServerSession associated with the connection. * @param server_session Owning pointer to the ServerSession associated with the connection.
*/ */
void ClientConnected(KSession* session); void ClientConnected(KServerSession* session);
/** /**
* Signals that a client has just disconnected from this HLE handler and releases the * Signals that a client has just disconnected from this HLE handler and releases the
* associated ServerSession. * associated ServerSession.
* @param server_session ServerSession associated with the connection. * @param server_session ServerSession associated with the connection.
*/ */
void ClientDisconnected(KSession* session); void ClientDisconnected(KServerSession* session);
protected:
/// List of sessions that are connected to this handler.
/// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
/// for the duration of the connection.
std::vector<KSession*> sessions;
}; };
/** /**

View file

@ -12,6 +12,7 @@
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
@ -30,8 +31,9 @@ namespace Kernel::Init {
HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \
HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)

View file

@ -1,12 +1,14 @@
// Copyright 2016 Citra Emulator Project // Copyright 2021 Citra Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/scope_exit.h"
#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_scheduler.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/object.h"
#include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_results.h"
namespace Kernel { namespace Kernel {
@ -14,45 +16,110 @@ namespace Kernel {
KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KClientPort::~KClientPort() = default; KClientPort::~KClientPort() = default;
void KClientPort::Initialize(s32 max_sessions_, std::string&& name_) { void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) {
// Set member variables.
num_sessions = 0;
peak_sessions = 0;
parent = parent_;
max_sessions = max_sessions_; max_sessions = max_sessions_;
name = std::move(name_); name = std::move(name_);
} }
KServerPort* KClientPort::GetServerPort() const { void KClientPort::OnSessionFinalized() {
return server_port; KScopedSchedulerLock sl{kernel};
const auto prev = num_sessions--;
if (prev == max_sessions) {
this->NotifyAvailable();
}
} }
ResultVal<KClientSession*> KClientPort::Connect() { void KClientPort::OnServerClosed() {}
if (num_sessions >= max_sessions) {
return ResultOutOfSessions;
}
num_sessions++;
auto* session = Kernel::KSession::Create(kernel); bool KClientPort::IsLight() const {
session->Initialize(name + ":ClientPort"); return this->GetParent()->IsLight();
if (server_port->HasHLEHandler()) {
server_port->GetHLEHandler()->ClientConnected(session);
} else {
server_port->AppendPendingSession(std::addressof(session->GetServerSession()));
} }
return MakeResult(std::addressof(session->GetClientSession())); bool KClientPort::IsServerClosed() const {
return this->GetParent()->IsServerClosed();
} }
void KClientPort::ConnectionClosed() { void KClientPort::Destroy() {
if (num_sessions == 0) { // Note with our parent that we're closed.
return; parent->OnClientClosed();
}
--num_sessions; // Close our reference to our parent.
parent->Close();
} }
void KClientPort::Destroy() {}
bool KClientPort::IsSignaled() const { bool KClientPort::IsSignaled() const {
return num_sessions < max_sessions; return num_sessions < max_sessions;
} }
ResultCode KClientPort::CreateSession(KClientSession** out) {
// Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
LimitableResource::Sessions);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
// Update the session counts.
{
// Atomically increment the number of sessions.
s32 new_sessions;
{
const auto max = max_sessions;
auto cur_sessions = num_sessions.load(std::memory_order_acquire);
do {
R_UNLESS(cur_sessions < max, ResultOutOfSessions);
new_sessions = cur_sessions + 1;
} while (!num_sessions.compare_exchange_weak(cur_sessions, new_sessions,
std::memory_order_relaxed));
}
// Atomically update the peak session tracking.
{
auto peak = peak_sessions.load(std::memory_order_acquire);
do {
if (peak >= new_sessions) {
break;
}
} while (!peak_sessions.compare_exchange_weak(peak, new_sessions,
std::memory_order_relaxed));
}
}
// Create a new session.
KSession* session = KSession::Create(kernel);
if (session == nullptr) {
/* Decrement the session count. */
const auto prev = num_sessions--;
if (prev == max_sessions) {
this->NotifyAvailable();
}
return ResultOutOfResource;
}
// Initialize the session.
session->Initialize(this, parent->GetName());
// Commit the session reservation.
session_reservation.Commit();
// Register the session.
KSession::Register(kernel, session);
auto session_guard = SCOPE_GUARD({
session->GetClientSession().Close();
session->GetServerSession().Close();
});
// Enqueue the session with our parent.
R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession())));
// We succeeded, so set the output.
session_guard.Cancel();
*out = std::addressof(session->GetClientSession());
return RESULT_SUCCESS;
}
} // namespace Kernel } // namespace Kernel

View file

@ -15,7 +15,7 @@ namespace Kernel {
class KClientSession; class KClientSession;
class KernelCore; class KernelCore;
class KServerPort; class KPort;
class KClientPort final : public KSynchronizationObject { class KClientPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
@ -24,30 +24,33 @@ public:
explicit KClientPort(KernelCore& kernel); explicit KClientPort(KernelCore& kernel);
virtual ~KClientPort() override; virtual ~KClientPort() override;
friend class KServerPort; void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
void OnSessionFinalized();
void OnServerClosed();
void Initialize(s32 max_sessions_, std::string&& name_); constexpr const KPort* GetParent() const {
return parent;
}
KServerPort* GetServerPort() const; s32 GetNumSessions() const {
return num_sessions;
}
s32 GetPeakSessions() const {
return peak_sessions;
}
s32 GetMaxSessions() const {
return max_sessions;
}
/** bool IsLight() const;
* Creates a new Session pair, adds the created ServerSession to the associated ServerPort's bool IsServerClosed() const;
* list of pending sessions, and signals the ServerPort, causing any threads
* waiting on it to awake.
* @returns ClientSession The client endpoint of the created Session pair, or error code.
*/
ResultVal<KClientSession*> Connect();
/**
* Signifies that a previously active connection has been closed,
* decreasing the total number of active connections to this port.
*/
void ConnectionClosed();
// Overridden virtual functions. // Overridden virtual functions.
virtual void Destroy() override; virtual void Destroy() override;
virtual bool IsSignaled() const override; virtual bool IsSignaled() const override;
ResultCode CreateSession(KClientSession** out);
// DEPRECATED // DEPRECATED
std::string GetTypeName() const override { std::string GetTypeName() const override {
@ -63,10 +66,11 @@ public:
} }
private: private:
KServerPort* server_port{}; ///< ServerPort associated with this client port. std::atomic<s32> num_sessions{};
s32 max_sessions{}; ///< Maximum number of simultaneous sessions the port can have std::atomic<s32> peak_sessions{};
std::atomic<s32> num_sessions{}; ///< Number of currently open sessions to this port s32 max_sessions{};
std::string name; ///< Name of client port (optional) KPort* parent{};
std::string name;
}; };
} // namespace Kernel } // namespace Kernel

View file

@ -20,7 +20,7 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObj
public: public:
explicit KEvent(KernelCore& kernel); explicit KEvent(KernelCore& kernel);
~KEvent() override; virtual ~KEvent();
void Initialize(std::string&& name); void Initialize(std::string&& name);

View file

@ -0,0 +1,68 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
KPort::KPort(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, server{kernel}, client{kernel} {}
KPort::~KPort() = default;
void KPort::Initialize(s32 max_sessions_, bool is_light_, const std::string& name_) {
// Open a new reference count to the initialized port.
Open();
// Create and initialize our server/client pair.
KAutoObject::Create(std::addressof(server));
KAutoObject::Create(std::addressof(client));
server.Initialize(this, name_ + ":Server");
client.Initialize(this, max_sessions_, name_ + ":Client");
// Set our member variables.
is_light = is_light_;
name = name_;
state = State::Normal;
}
void KPort::OnClientClosed() {
KScopedSchedulerLock sl{kernel};
if (state == State::Normal) {
state = State::ClientClosed;
}
}
void KPort::OnServerClosed() {
KScopedSchedulerLock sl{kernel};
if (state == State::Normal) {
state = State::ServerClosed;
}
}
bool KPort::IsServerClosed() const {
KScopedSchedulerLock sl{kernel};
return state == State::ServerClosed;
}
ResultCode KPort::EnqueueSession(KServerSession* session) {
KScopedSchedulerLock sl{kernel};
R_UNLESS(state == State::Normal, ResultPortClosed);
if (server.HasHLEHandler()) {
server.GetHLEHandler()->ClientConnected(session);
} else {
server.EnqueueSession(session);
}
return RESULT_SUCCESS;
}
} // namespace Kernel

View file

@ -0,0 +1,87 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_server_port.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Kernel {
class KServerSession;
class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> {
KERNEL_AUTOOBJECT_TRAITS(KPort, KAutoObject);
public:
explicit KPort(KernelCore& kernel);
virtual ~KPort();
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
void Initialize(s32 max_sessions_, bool is_light_, const std::string& name_);
void OnClientClosed();
void OnServerClosed();
bool IsLight() const {
return is_light;
}
bool IsServerClosed() const;
ResultCode EnqueueSession(KServerSession* session);
KClientPort& GetClientPort() {
return client;
}
KServerPort& GetServerPort() {
return server;
}
const KClientPort& GetClientPort() const {
return client;
}
const KServerPort& GetServerPort() const {
return server;
}
// DEPRECATED
friend class ServerPort;
std::string GetTypeName() const override {
return "Port";
}
std::string GetName() const override {
return name;
}
HandleType GetHandleType() const override {
return {};
}
void Finalize() override {}
private:
enum class State : u8 {
Invalid = 0,
Normal = 1,
ClientClosed = 2,
ServerClosed = 3,
};
private:
KServerPort server;
KClientPort client;
State state{State::Invalid};
bool is_light{};
std::string name; ///< Name of client port (optional)
};
} // namespace Kernel

View file

@ -1,10 +1,12 @@
// Copyright 2016 Citra Emulator Project // Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <tuple> #include <tuple>
#include "common/assert.h" #include "common/assert.h"
#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_server_port.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"
@ -16,50 +18,88 @@ namespace Kernel {
KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KServerPort::~KServerPort() = default; KServerPort::~KServerPort() = default;
void KServerPort::Initialize(std::string&& name_) { void KServerPort::Initialize(KPort* parent_, std::string&& name_) {
// Set member variables. // Set member variables.
parent = parent_;
name = std::move(name_); name = std::move(name_);
} }
ResultVal<KServerSession*> KServerPort::Accept() { bool KServerPort::IsLight() const {
if (pending_sessions.empty()) { return this->GetParent()->IsLight();
return ResultNotFound;
} }
auto* session = pending_sessions.back(); void KServerPort::CleanupSessions() {
pending_sessions.pop_back(); // Ensure our preconditions are met.
return MakeResult(session); if (this->IsLight()) {
UNIMPLEMENTED();
} }
void KServerPort::AppendPendingSession(KServerSession* pending_session) { // Cleanup the session list.
pending_sessions.push_back(std::move(pending_session)); while (true) {
if (pending_sessions.size() == 1) { // Get the last session in the list
NotifyAvailable(); KServerSession* session = nullptr;
{
KScopedSchedulerLock sl{kernel};
if (!session_list.empty()) {
session = std::addressof(session_list.front());
session_list.pop_front();
} }
} }
void KServerPort::Destroy() {} // Close the session.
if (session != nullptr) {
session->Close();
} else {
break;
}
}
}
void KServerPort::Destroy() {
// Note with our parent that we're closed.
parent->OnServerClosed();
// Perform necessary cleanup of our session lists.
this->CleanupSessions();
// Close our reference to our parent.
parent->Close();
}
bool KServerPort::IsSignaled() const { bool KServerPort::IsSignaled() const {
return !pending_sessions.empty(); if (this->IsLight()) {
UNIMPLEMENTED();
return false;
} else {
return !session_list.empty();
}
} }
KServerPort::PortPair KServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, void KServerPort::EnqueueSession(KServerSession* session) {
std::string name) { ASSERT(!this->IsLight());
KServerPort* server_port = new KServerPort(kernel);
KClientPort* client_port = new KClientPort(kernel);
KAutoObject::Create(server_port); KScopedSchedulerLock sl{kernel};
KAutoObject::Create(client_port);
server_port->Initialize(name + "_Server"); // Add the session to our queue.
client_port->Initialize(max_sessions, name + "_Client"); session_list.push_back(*session);
if (session_list.size() == 1) {
this->NotifyAvailable();
}
}
client_port->server_port = server_port; KServerSession* KServerPort::AcceptSession() {
ASSERT(!this->IsLight());
server_port->name = name + "_Server"; KScopedSchedulerLock sl{kernel};
return std::make_pair(server_port, client_port); // Return the first session in the list.
if (session_list.empty()) {
return nullptr;
}
KServerSession* session = std::addressof(session_list.front());
session_list.pop_front();
return session;
} }
} // namespace Kernel } // namespace Kernel

View file

@ -1,4 +1,4 @@
// Copyright 2016 Citra Emulator Project // Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
@ -8,46 +8,33 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/intrusive/list.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/object.h"
#include "core/hle/result.h" #include "core/hle/result.h"
namespace Kernel { namespace Kernel {
class KClientPort;
class KernelCore; class KernelCore;
class KServerSession; class KPort;
class SessionRequestHandler; class SessionRequestHandler;
class KServerPort final : public KSynchronizationObject { class KServerPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject);
private:
using SessionList = boost::intrusive::list<KServerSession>;
public: public:
explicit KServerPort(KernelCore& kernel); explicit KServerPort(KernelCore& kernel);
virtual ~KServerPort() override; virtual ~KServerPort() override;
using HLEHandler = std::shared_ptr<SessionRequestHandler>; using HLEHandler = std::shared_ptr<SessionRequestHandler>;
using PortPair = std::pair<KServerPort*, KClientPort*>;
void Initialize(std::string&& name_); void Initialize(KPort* parent_, std::string&& name_);
/**
* Creates a pair of ServerPort and an associated ClientPort.
*
* @param kernel The kernel instance to create the port pair under.
* @param max_sessions Maximum number of sessions to the port
* @param name Optional name of the ports
* @return The created port tuple
*/
static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions,
std::string name = "UnknownPort");
/**
* Accepts a pending incoming connection on this port. If there are no pending sessions, will
* return ERR_NO_PENDING_SESSIONS.
*/
ResultVal<KServerSession*> Accept();
/// Whether or not this server port has an HLE handler available. /// Whether or not this server port has an HLE handler available.
bool HasHLEHandler() const { bool HasHLEHandler() const {
@ -67,9 +54,15 @@ public:
hle_handler = std::move(hle_handler_); hle_handler = std::move(hle_handler_);
} }
/// Appends a ServerSession to the collection of ServerSessions void EnqueueSession(KServerSession* pending_session);
/// waiting to be accepted by this port.
void AppendPendingSession(KServerSession* pending_session); KServerSession* AcceptSession();
constexpr const KPort* GetParent() const {
return parent;
}
bool IsLight() const;
// Overridden virtual functions. // Overridden virtual functions.
virtual void Destroy() override; virtual void Destroy() override;
@ -90,14 +83,12 @@ public:
} }
private: private:
/// ServerSessions waiting to be accepted by the port void CleanupSessions();
std::vector<KServerSession*> pending_sessions;
/// This session's HLE request handler template (optional) private:
/// ServerSessions created from this port inherit a reference to this handler. SessionList session_list;
HLEHandler hle_handler; HLEHandler hle_handler;
KPort* parent{};
/// Name of the port (optional)
std::string name; std::string name;
}; };

View file

@ -50,7 +50,7 @@ void KServerSession::OnClientClosed() {
if (handler) { if (handler) {
// Note that after this returns, this server session's hle_handler is // Note that after this returns, this server session's hle_handler is
// invalidated (set to null). // invalidated (set to null).
handler->ClientDisconnected(parent); handler->ClientDisconnected(this);
} }
} }

View file

@ -9,6 +9,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/intrusive/list.hpp>
#include "common/threadsafe_queue.h" #include "common/threadsafe_queue.h"
#include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/service_thread.h" #include "core/hle/kernel/service_thread.h"
@ -31,7 +33,8 @@ class KSession;
class SessionRequestHandler; class SessionRequestHandler;
class KThread; class KThread;
class KServerSession final : public KSynchronizationObject { class KServerSession final : public KSynchronizationObject,
public boost::intrusive::list_base_hook<> {
KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
friend class ServiceThread; friend class ServiceThread;

View file

@ -1,8 +1,9 @@
// Copyright 2019 yuzu emulator team // Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/assert.h" #include "common/assert.h"
#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_server_session.h"
@ -14,7 +15,7 @@ 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(std::string&& name_) { void KSession::Initialize(KClientPort* port_, std::string&& name_) {
// 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
@ -37,11 +38,22 @@ void KSession::Initialize(std::string&& name_) {
process = kernel.CurrentProcess(); process = kernel.CurrentProcess();
process->Open(); process->Open();
// Set our port.
port = port_;
if (port != nullptr) {
port->Open();
}
// Mark initialized. // Mark initialized.
initialized = true; initialized = true;
} }
void KSession::Finalize() {} void KSession::Finalize() {
if (port != nullptr) {
port->OnSessionFinalized();
port->Close();
}
}
void KSession::OnServerClosed() { void KSession::OnServerClosed() {
if (GetState() == State::Normal) { if (GetState() == State::Normal) {

View file

@ -28,7 +28,7 @@ public:
explicit KSession(KernelCore& kernel); explicit KSession(KernelCore& kernel);
virtual ~KSession() override; virtual ~KSession() override;
void Initialize(std::string&& name_); void Initialize(KClientPort* port_, std::string&& name_);
virtual void Finalize() override; virtual void Finalize() override;

View file

@ -37,6 +37,8 @@ class KClientSession;
class KEvent; class KEvent;
class KLinkedListNode; class KLinkedListNode;
class KMemoryManager; class KMemoryManager;
class KPort;
class Process;
class KResourceLimit; class KResourceLimit;
class KScheduler; class KScheduler;
class KSession; class KSession;
@ -45,7 +47,6 @@ class KThread;
class KTransferMemory; class KTransferMemory;
class KWritableEvent; class KWritableEvent;
class PhysicalCore; class PhysicalCore;
class Process;
class ServiceThread; class ServiceThread;
class Synchronization; class Synchronization;
class TimeManager; class TimeManager;
@ -272,6 +273,8 @@ public:
return slab_heap_container->event; return slab_heap_container->event;
} else if constexpr (std::is_same_v<T, KLinkedListNode>) { } else if constexpr (std::is_same_v<T, KLinkedListNode>) {
return slab_heap_container->linked_list_node; return slab_heap_container->linked_list_node;
} else if constexpr (std::is_same_v<T, KPort>) {
return slab_heap_container->port;
} else if constexpr (std::is_same_v<T, Process>) { } else if constexpr (std::is_same_v<T, Process>) {
return slab_heap_container->process; return slab_heap_container->process;
} else if constexpr (std::is_same_v<T, KResourceLimit>) { } else if constexpr (std::is_same_v<T, KResourceLimit>) {
@ -323,6 +326,7 @@ private:
KSlabHeap<KClientSession> client_session; KSlabHeap<KClientSession> client_session;
KSlabHeap<KEvent> event; KSlabHeap<KEvent> event;
KSlabHeap<KLinkedListNode> linked_list_node; KSlabHeap<KLinkedListNode> linked_list_node;
KSlabHeap<KPort> port;
KSlabHeap<Process> process; KSlabHeap<Process> process;
KSlabHeap<KResourceLimit> resource_limit; KSlabHeap<KResourceLimit> resource_limit;
KSlabHeap<KSession> session; KSlabHeap<KSession> session;

View file

@ -293,9 +293,7 @@ static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr
/// Connect to an OS service given the port name, returns the handle to the port to out /// Connect to an OS service given the port name, returns the handle to the port to out
static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
VAddr port_name_address) { VAddr port_name_address) {
std::lock_guard lock{HLE::g_hle_lock};
auto& memory = system.Memory(); auto& memory = system.Memory();
if (!memory.IsValidVirtualAddress(port_name_address)) { if (!memory.IsValidVirtualAddress(port_name_address)) {
LOG_ERROR(Kernel_SVC, LOG_ERROR(Kernel_SVC,
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
@ -314,21 +312,27 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
// Get the current handle table.
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
// Find the client port.
const auto it = kernel.FindNamedPort(port_name); const auto it = kernel.FindNamedPort(port_name);
if (!kernel.IsValidNamedPort(it)) { if (!kernel.IsValidNamedPort(it)) {
LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
return ResultNotFound; return ResultNotFound;
} }
auto port = it->second;
auto client_port = it->second; // Create a session.
KClientSession* session{};
R_TRY(port->CreateSession(std::addressof(session)));
KClientSession* client_session{}; // Register the session in the table, close the extra reference.
CASCADE_RESULT(client_session, client_port->Connect()); handle_table.Add(out_handle, session);
session->Close();
// Return the client session // We succeeded.
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
handle_table.Add(out_handle, client_session);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -340,13 +344,13 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,
/// Makes a blocking IPC call to an OS service. /// Makes a blocking IPC call to an OS service.
static ResultCode SendSyncRequest(Core::System& system, Handle handle) { static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
KScopedAutoObject session = KScopedAutoObject session =
kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
R_UNLESS(session.IsNotNull(), ResultInvalidHandle); R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
auto thread = kernel.CurrentScheduler()->GetCurrentThread(); auto thread = kernel.CurrentScheduler()->GetCurrentThread();
{ {

View file

@ -36,6 +36,7 @@ constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};
constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123}; constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123};
constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};
constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126}; constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126};
constexpr ResultCode ResultPortClosed{ErrorModule::Kernel, 131};
constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132}; constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132};
constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519}; constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519};

View file

@ -116,10 +116,11 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
ASSERT(!port_installed); ASSERT(!port_installed);
auto [server_port, client_port] = auto* port = Kernel::KPort::Create(kernel);
Kernel::KServerPort::CreatePortPair(kernel, max_sessions, service_name); port->Initialize(max_sessions, false, service_name);
server_port->SetHleHandler(shared_from_this()); port->GetServerPort().SetHleHandler(shared_from_this());
kernel.AddNamedPort(service_name, client_port); kernel.AddNamedPort(service_name, &port->GetClientPort());
port_installed = true; port_installed = true;
} }

View file

@ -8,6 +8,7 @@
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_server_port.h"
#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_session.h"
@ -59,13 +60,12 @@ ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name
return ERR_ALREADY_REGISTERED; return ERR_ALREADY_REGISTERED;
} }
auto [server_port, client_port] = auto* port = Kernel::KPort::Create(kernel);
Kernel::KServerPort::CreatePortPair(kernel, max_sessions, name); port->Initialize(max_sessions, false, name);
client_port->Open(); registered_services.emplace(std::move(name), port);
registered_services.emplace(std::move(name), client_port); return MakeResult(&port->GetServerPort());
return MakeResult(server_port);
} }
ResultCode ServiceManager::UnregisterService(const std::string& name) { ResultCode ServiceManager::UnregisterService(const std::string& name) {
@ -83,7 +83,7 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultVal<Kernel::KClientPort*> ServiceManager::GetServicePort(const std::string& name) { ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name)); CASCADE_CODE(ValidateServiceName(name));
auto it = registered_services.find(name); auto it = registered_services.find(name);
@ -118,25 +118,26 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
std::string name(name_buf.begin(), end); std::string name(name_buf.begin(), end);
auto client_port = service_manager->GetServicePort(name); auto result = service_manager->GetServicePort(name);
if (client_port.Failed()) { if (result.Failed()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(client_port.Code()); rb.Push(result.Code());
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);
if (name.length() == 0) if (name.length() == 0)
return; // LibNX Fix return; // LibNX Fix
UNIMPLEMENTED(); UNIMPLEMENTED();
return; return;
} }
auto* session = Kernel::KSession::Create(kernel); auto* port = result.Unwrap();
session->Initialize(std::move(name));
const auto& server_port = client_port.Unwrap()->GetServerPort(); auto* session = Kernel::KSession::Create(kernel);
if (server_port->GetHLEHandler()) { session->Initialize(&port->GetClientPort(), std::move(name));
server_port->GetHLEHandler()->ClientConnected(session);
if (port->GetServerPort().GetHLEHandler()) {
port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession());
} else { } else {
server_port->AppendPendingSession(&session->GetServerSession()); port->EnqueueSession(&session->GetServerSession());
} }
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetObjectId()); LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetObjectId());

View file

@ -10,9 +10,7 @@
#include <unordered_map> #include <unordered_map>
#include "common/concepts.h" #include "common/concepts.h"
#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_server_port.h"
#include "core/hle/kernel/object.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
@ -24,6 +22,7 @@ namespace Kernel {
class KClientPort; class KClientPort;
class KClientSession; class KClientSession;
class KernelCore; class KernelCore;
class KPort;
class KServerPort; class KServerPort;
class SessionRequestHandler; class SessionRequestHandler;
} // namespace Kernel } // namespace Kernel
@ -57,7 +56,7 @@ public:
ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions); ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions);
ResultCode UnregisterService(const std::string& name); ResultCode UnregisterService(const std::string& name);
ResultVal<Kernel::KClientPort*> GetServicePort(const std::string& name); ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
template <Common::DerivedFrom<Kernel::SessionRequestHandler> T> template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const { std::shared_ptr<T> GetService(const std::string& service_name) const {
@ -66,11 +65,11 @@ public:
LOG_DEBUG(Service, "Can't find service: {}", service_name); LOG_DEBUG(Service, "Can't find service: {}", service_name);
return nullptr; return nullptr;
} }
auto port = service->second->GetServerPort(); auto* port = service->second;
if (port == nullptr) { if (port == nullptr) {
return nullptr; return nullptr;
} }
return std::static_pointer_cast<T>(port->GetHLEHandler()); return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler());
} }
void InvokeControlRequest(Kernel::HLERequestContext& context); void InvokeControlRequest(Kernel::HLERequestContext& context);
@ -80,7 +79,7 @@ private:
std::unique_ptr<Controller> controller_interface; std::unique_ptr<Controller> controller_interface;
/// Map of registered services, retrieved using GetServicePort. /// Map of registered services, retrieved using GetServicePort.
std::unordered_map<std::string, Kernel::KClientPort*> registered_services; std::unordered_map<std::string, Kernel::KPort*> registered_services;
/// Kernel context /// Kernel context
Kernel::KernelCore& kernel; Kernel::KernelCore& kernel;