hle: kernel: Migrate KPort, KClientPort, and KServerPort to KAutoObject.
This commit is contained in:
parent
7a06864100
commit
626f746971
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_,
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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__)
|
||||||
|
|
||||||
|
|
|
@ -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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KClientPort::ConnectionClosed() {
|
bool KClientPort::IsServerClosed() const {
|
||||||
if (num_sessions == 0) {
|
return this->GetParent()->IsServerClosed();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
--num_sessions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KClientPort::Destroy() {}
|
void KClientPort::Destroy() {
|
||||||
|
// Note with our parent that we're closed.
|
||||||
|
parent->OnClientClosed();
|
||||||
|
|
||||||
|
// Close our reference to our parent.
|
||||||
|
parent->Close();
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
|
||||||
pending_sessions.pop_back();
|
|
||||||
return MakeResult(session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KServerPort::AppendPendingSession(KServerSession* pending_session) {
|
void KServerPort::CleanupSessions() {
|
||||||
pending_sessions.push_back(std::move(pending_session));
|
// Ensure our preconditions are met.
|
||||||
if (pending_sessions.size() == 1) {
|
if (this->IsLight()) {
|
||||||
NotifyAvailable();
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup the session list.
|
||||||
|
while (true) {
|
||||||
|
// Get the last session in the list
|
||||||
|
KServerSession* session = nullptr;
|
||||||
|
{
|
||||||
|
KScopedSchedulerLock sl{kernel};
|
||||||
|
if (!session_list.empty()) {
|
||||||
|
session = std::addressof(session_list.front());
|
||||||
|
session_list.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the session.
|
||||||
|
if (session != nullptr) {
|
||||||
|
session->Close();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KServerPort::Destroy() {}
|
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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
{
|
{
|
||||||
|
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue