hle: kernel: Migrate KSession, KClientSession, and KServerSession to KAutoObject.

This commit is contained in:
bunnei 2021-04-13 17:48:37 -07:00
parent 2cb6106523
commit 7444963bbb
31 changed files with 416 additions and 360 deletions

View File

@ -146,8 +146,6 @@ add_library(core STATIC
hle/kernel/board/nintendo/nx/secure_monitor.h
hle/kernel/client_port.cpp
hle/kernel/client_port.h
hle/kernel/client_session.cpp
hle/kernel/client_session.h
hle/kernel/code_set.cpp
hle/kernel/code_set.h
hle/kernel/svc_results.h
@ -170,6 +168,8 @@ add_library(core STATIC
hle/kernel/k_affinity_mask.h
hle/kernel/k_class_token.cpp
hle/kernel/k_class_token.h
hle/kernel/k_client_session.cpp
hle/kernel/k_client_session.h
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
hle/kernel/k_event.cpp
@ -205,6 +205,10 @@ add_library(core STATIC
hle/kernel/k_scoped_lock.h
hle/kernel/k_scoped_resource_reservation.h
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
hle/kernel/k_server_session.cpp
hle/kernel/k_server_session.h
hle/kernel/k_session.cpp
hle/kernel/k_session.h
hle/kernel/k_shared_memory.cpp
hle/kernel/k_shared_memory.h
hle/kernel/k_slab_heap.h
@ -233,12 +237,8 @@ add_library(core STATIC
hle/kernel/process_capability.h
hle/kernel/server_port.cpp
hle/kernel/server_port.h
hle/kernel/server_session.cpp
hle/kernel/server_session.h
hle/kernel/service_thread.cpp
hle/kernel/service_thread.h
hle/kernel/session.cpp
hle/kernel/session.h
hle/kernel/slab_helpers.h
hle/kernel/svc.cpp
hle/kernel/svc.h

View File

@ -14,11 +14,9 @@
#include "common/common_types.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/result.h"
namespace IPC {
@ -137,9 +135,11 @@ public:
if (context->Session()->IsDomain()) {
context->AddDomainObject(std::move(iface));
} else {
auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
context->AddMoveObject(client.get());
iface->ClientConnected(std::move(client), std::move(server));
auto* session = Kernel::KSession::Create(kernel);
session->Initialize(iface->GetServiceName());
context->AddMoveObject(&session->GetClientSession());
iface->ClientConnected(session);
}
}

View File

@ -3,11 +3,10 @@
// Refer to the license.txt file included.
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
@ -19,21 +18,22 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
return server_port;
}
ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
ResultVal<KClientSession*> ClientPort::Connect() {
if (active_sessions >= max_sessions) {
return ResultOutOfSessions;
}
active_sessions++;
auto [client, server] = Kernel::Session::Create(kernel, name);
auto* session = Kernel::KSession::Create(kernel);
session->Initialize(name + ":ClientPort");
if (server_port->HasHLEHandler()) {
server_port->GetHLEHandler()->ClientConnected(client, std::move(server));
server_port->GetHLEHandler()->ClientConnected(session);
} else {
server_port->AppendPendingSession(std::move(server));
server_port->AppendPendingSession(std::addressof(session->GetServerSession()));
}
return MakeResult(std::move(client));
return MakeResult(std::addressof(session->GetClientSession()));
}
void ClientPort::ConnectionClosed() {

View File

@ -13,7 +13,7 @@
namespace Kernel {
class ClientSession;
class KClientSession;
class KernelCore;
class ServerPort;
@ -43,7 +43,7 @@ public:
* waiting on it to awake.
* @returns ClientSession The client endpoint of the created Session pair, or error code.
*/
ResultVal<std::shared_ptr<ClientSession>> Connect();
ResultVal<KClientSession*> Connect();
/**
* Signifies that a previously active connection has been closed,

View File

@ -1,52 +0,0 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/result.h"
namespace Kernel {
ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
ClientSession::~ClientSession() {
// This destructor will be called automatically when the last ClientSession handle is closed by
// the emulated application.
if (parent->Server()) {
parent->Server()->ClientDisconnected();
}
}
bool ClientSession::IsSignaled() const {
UNIMPLEMENTED();
return true;
}
ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
std::shared_ptr<Session> parent,
std::string name) {
std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)};
client_session->name = std::move(name);
client_session->parent = std::move(parent);
return MakeResult(std::move(client_session));
}
ResultCode ClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing) {
// Keep ServerSession alive until we're done working with it.
if (!parent->Server()) {
return ResultSessionClosed;
}
// Signal the server session that new data is available
return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing);
}
} // namespace Kernel

View File

@ -56,7 +56,10 @@ ResultVal<Handle> HandleTable::Create(Object* obj) {
case HandleType::Event:
case HandleType::Process:
case HandleType::ReadableEvent:
case HandleType::WritableEvent: {
case HandleType::WritableEvent:
case HandleType::ClientSession:
case HandleType::ServerSession:
case HandleType::Session: {
Handle handle{};
Add(&handle, reinterpret_cast<KAutoObject*>(obj), {});
return MakeResult<Handle>(handle);

View File

@ -19,12 +19,12 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
#include "core/memory.h"
@ -35,24 +35,19 @@ SessionRequestHandler::SessionRequestHandler() = default;
SessionRequestHandler::~SessionRequestHandler() = default;
void SessionRequestHandler::ClientConnected(std::shared_ptr<ClientSession> client_session,
std::shared_ptr<ServerSession> server_session) {
server_session->SetHleHandler(shared_from_this());
client_sessions.push_back(std::move(client_session));
server_sessions.push_back(std::move(server_session));
void SessionRequestHandler::ClientConnected(KSession* session) {
session->GetServerSession().SetHleHandler(shared_from_this());
sessions.push_back(session);
}
void SessionRequestHandler::ClientDisconnected(
const std::shared_ptr<ServerSession>& server_session) {
server_session->SetHleHandler(nullptr);
boost::range::remove_erase(server_sessions, server_session);
void SessionRequestHandler::ClientDisconnected(KSession* session) {
session->GetServerSession().SetHleHandler(nullptr);
boost::range::remove_erase(sessions, session);
}
HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
std::shared_ptr<ServerSession> server_session_,
KThread* thread_)
: server_session(std::move(server_session_)),
thread(thread_), kernel{kernel_}, memory{memory_} {
KServerSession* server_session_, KThread* thread_)
: server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
cmd_buf[0] = 0;
}

View File

@ -39,10 +39,10 @@ class HandleTable;
class HLERequestContext;
class KernelCore;
class Process;
class ClientSession;
class ServerSession;
class KServerSession;
class KThread;
class KReadableEvent;
class KSession;
class KWritableEvent;
enum class ThreadWakeupReason;
@ -72,22 +72,20 @@ public:
* associated ServerSession alive for the duration of the connection.
* @param server_session Owning pointer to the ServerSession associated with the connection.
*/
void ClientConnected(
std::shared_ptr<ClientSession> client_session, std::shared_ptr<ServerSession> server_session);
void ClientConnected(KSession* session);
/**
* Signals that a client has just disconnected from this HLE handler and releases the
* associated ServerSession.
* @param server_session ServerSession associated with the connection.
*/
void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session);
void ClientDisconnected(KSession* 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<std::shared_ptr<ClientSession>> client_sessions;
std::vector<std::shared_ptr<ServerSession>> server_sessions;
std::vector<KSession*> sessions;
};
/**
@ -112,7 +110,7 @@ protected:
class HLERequestContext {
public:
explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
std::shared_ptr<ServerSession> session, KThread* thread);
KServerSession* session, KThread* thread);
~HLERequestContext();
/// Returns a pointer to the IPC command buffer for this request.
@ -124,7 +122,7 @@ public:
* Returns the session through which this request was made. This can be used as a map key to
* access per-client data on services.
*/
const std::shared_ptr<Kernel::ServerSession>& Session() const {
Kernel::KServerSession* Session() {
return server_session;
}
@ -288,7 +286,7 @@ private:
void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
std::shared_ptr<Kernel::ServerSession> server_session;
Kernel::KServerSession* server_session{};
KThread* thread;
// TODO(yuriks): Check common usage of this and optimize size accordingly

View File

@ -12,6 +12,7 @@
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/k_thread.h"
@ -27,7 +28,8 @@ namespace Kernel::Init {
HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \
HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__)
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__)
namespace {

View File

@ -0,0 +1,31 @@
// Copyright 2021 yuzu emulator team
// 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_client_session.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/result.h"
namespace Kernel {
KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
KClientSession::~KClientSession() = default;
void KClientSession::Destroy() {
parent->OnClientClosed();
parent->Close();
}
void KClientSession::OnServerClosed() {}
ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing) {
// Signal the server session that new data is available
return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing);
}
} // namespace Kernel

View File

@ -1,4 +1,4 @@
// Copyright 2019 yuzu emulator team
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -7,7 +7,9 @@
#include <memory>
#include <string>
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
union ResultCode;
@ -23,15 +25,41 @@ class CoreTiming;
namespace Kernel {
class KernelCore;
class Session;
class KSession;
class KThread;
class ClientSession final : public KSynchronizationObject {
public:
explicit ClientSession(KernelCore& kernel);
~ClientSession() override;
class KClientSession final
: public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> {
KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject);
friend class Session;
public:
explicit KClientSession(KernelCore& kernel);
virtual ~KClientSession();
void Initialize(KSession* parent_, std::string&& name_) {
// Set member variables.
parent = parent_;
name = std::move(name_);
}
virtual void Destroy() override;
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
constexpr KSession* GetParent() const {
return parent;
}
ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing);
void OnServerClosed();
// DEPRECATED
static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
std::string GetTypeName() const override {
return "ClientSession";
@ -41,25 +69,9 @@ public:
return name;
}
static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing);
bool IsSignaled() const override;
void Finalize() override {}
private:
static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
std::shared_ptr<Session> parent,
std::string name = "Unknown");
/// The parent session, which links to the server endpoint.
std::shared_ptr<Session> parent;
KSession* parent{};
/// Name of the client session (optional)
std::string name;

View File

@ -11,43 +11,38 @@
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/memory.h"
namespace Kernel {
ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KServerSession::KServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
ServerSession::~ServerSession() {
KServerSession::~KServerSession() {
kernel.ReleaseServiceThread(service_thread);
}
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
std::shared_ptr<Session> parent,
std::string name) {
std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
session->name = std::move(name);
session->parent = std::move(parent);
session->service_thread = kernel.CreateServiceThread(session->name);
return MakeResult(std::move(session));
void KServerSession::Initialize(KSession* parent_, std::string&& name_) {
// Set member variables.
parent = parent_;
name = std::move(name_);
service_thread = kernel.CreateServiceThread(name);
}
bool ServerSession::IsSignaled() const {
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
return !parent->Client();
void KServerSession::Destroy() {
parent->OnServerClosed();
parent->Close();
}
void ServerSession::ClientDisconnected() {
void KServerSession::OnClientClosed() {
// We keep a shared pointer to the hle handler to keep it alive throughout
// the call to ClientDisconnected, as ClientDisconnected invalidates the
// hle_handler member itself during the course of the function executing.
@ -55,19 +50,31 @@ void ServerSession::ClientDisconnected() {
if (handler) {
// Note that after this returns, this server session's hle_handler is
// invalidated (set to null).
handler->ClientDisconnected(SharedFrom(this));
handler->ClientDisconnected(parent);
}
}
void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) {
bool KServerSession::IsSignaled() const {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
// If the client is closed, we're always signaled.
if (parent->IsClientClosed()) {
return true;
}
// Otherwise, we're signaled if we have a request and aren't handling one.
return false;
}
void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) {
domain_request_handlers.push_back(std::move(handler));
}
std::size_t ServerSession::NumDomainRequestHandlers() const {
std::size_t KServerSession::NumDomainRequestHandlers() const {
return domain_request_handlers.size();
}
ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
if (!context.HasDomainMessageHeader()) {
return RESULT_SUCCESS;
}
@ -106,21 +113,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
return RESULT_SUCCESS;
}
ResultCode ServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
auto context = std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), thread);
auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
if (auto strong_ptr = service_thread.lock()) {
strong_ptr->QueueSyncRequest(*this, std::move(context));
strong_ptr->QueueSyncRequest(*parent, std::move(context));
return RESULT_SUCCESS;
}
return RESULT_SUCCESS;
}
ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
ResultCode result = RESULT_SUCCESS;
// If the session has been converted to a domain, handle the domain request
if (IsDomain() && context.HasDomainMessageHeader()) {
@ -149,8 +156,8 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
return result;
}
ResultCode ServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing) {
ResultCode KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing) {
return QueueSyncRequest(thread, memory);
}

View File

@ -27,55 +27,34 @@ namespace Kernel {
class HLERequestContext;
class KernelCore;
class Session;
class KSession;
class SessionRequestHandler;
class KThread;
/**
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
* primitive for communication between different processes, and are used to implement service calls
* to the various system services.
*
* To make a service call, the client must write the command header and parameters to the buffer
* located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
* SVC call with its ClientSession handle. The kernel will read the command header, using it to
* marshall the parameters to the process at the server endpoint of the session.
* After the server replies to the request, the response is marshalled back to the caller's
* TLS buffer and control is transferred back to it.
*/
class ServerSession final : public KSynchronizationObject {
class KServerSession final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
friend class ServiceThread;
public:
explicit ServerSession(KernelCore& kernel);
~ServerSession() override;
explicit KServerSession(KernelCore& kernel);
virtual ~KServerSession() override;
friend class Session;
virtual void Destroy() override;
static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel,
std::shared_ptr<Session> parent,
std::string name = "Unknown");
void Initialize(KSession* parent_, std::string&& name_);
std::string GetTypeName() const override {
return "ServerSession";
constexpr KSession* GetParent() {
return parent;
}
std::string GetName() const override {
return name;
constexpr const KSession* GetParent() const {
return parent;
}
static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
virtual bool IsSignaled() const override;
Session* GetParent() {
return parent.get();
}
const Session* GetParent() const {
return parent.get();
}
void OnClientClosed();
/**
* Sets the HLE handler for the session. This handler will be called to service IPC requests
@ -98,9 +77,6 @@ public:
ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing);
/// Called when a client disconnection occurs.
void ClientDisconnected();
/// Adds a new domain request handler to the collection of request handlers within
/// this ServerSession instance.
void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler);
@ -124,9 +100,20 @@ public:
convert_to_domain = true;
}
bool IsSignaled() const override;
// DEPRECATED
void Finalize() override {}
std::string GetTypeName() const override {
return "ServerSession";
}
std::string GetName() const override {
return name;
}
static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
private:
/// Queues a sync request from the emulated application.
@ -139,9 +126,6 @@ private:
/// object handle.
ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context);
/// The parent session, which links to the client endpoint.
std::shared_ptr<Session> parent;
/// This session's HLE request handler (applicable when not a domain)
std::shared_ptr<SessionRequestHandler> hle_handler;
@ -156,6 +140,9 @@ private:
/// Thread to dispatch service requests
std::weak_ptr<ServiceThread> service_thread;
/// KSession that owns this KServerSession
KSession* parent{};
};
} // namespace Kernel

View File

@ -0,0 +1,67 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
namespace Kernel {
KSession::KSession(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, server{kernel}, client{kernel} {}
KSession::~KSession() = default;
void KSession::Initialize(std::string&& name_) {
// Increment reference count.
// Because reference count is one on creation, this will result
// in a reference count of two. Thus, when both server and client are closed
// this object will be destroyed.
Open();
// Create our sub sessions.
KAutoObject::Create(std::addressof(server));
KAutoObject::Create(std::addressof(client));
// Initialize our sub sessions.
server.Initialize(this, name_ + ":Server");
client.Initialize(this, name_ + ":Client");
// Set state and name.
SetState(State::Normal);
name = std::move(name_);
// Set our owner process.
process = kernel.CurrentProcess();
process->Open();
// Mark initialized.
initialized = true;
}
void KSession::Finalize() {}
void KSession::OnServerClosed() {
if (GetState() == State::Normal) {
SetState(State::ServerClosed);
client.OnServerClosed();
}
}
void KSession::OnClientClosed() {
if (GetState() == State::Normal) {
SetState(State::ClientClosed);
server.OnClientClosed();
}
}
void KSession::PostDestroy(uintptr_t arg) {
// Release the session count resource the owner process holds.
Process* owner = reinterpret_cast<Process*>(arg);
owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1);
owner->Close();
}
} // namespace Kernel

View File

@ -0,0 +1,108 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <atomic>
#include <string>
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> {
KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
private:
enum class State : u8 {
Invalid = 0,
Normal = 1,
ClientClosed = 2,
ServerClosed = 3,
};
public:
explicit KSession(KernelCore& kernel);
virtual ~KSession() override;
void Initialize(std::string&& name_);
virtual void Finalize() override;
virtual bool IsInitialized() const override {
return initialized;
}
virtual uintptr_t GetPostDestroyArgument() const override {
return reinterpret_cast<uintptr_t>(process);
}
static void PostDestroy(uintptr_t arg);
void OnServerClosed();
void OnClientClosed();
bool IsServerClosed() const {
return this->GetState() != State::Normal;
}
bool IsClientClosed() const {
return this->GetState() != State::Normal;
}
KClientSession& GetClientSession() {
return client;
}
KServerSession& GetServerSession() {
return server;
}
const KClientSession& GetClientSession() const {
return client;
}
const KServerSession& GetServerSession() const {
return server;
}
const ClientPort* GetParent() const {
return port;
}
// DEPRECATED
std::string GetName() const override {
return name;
}
static constexpr HandleType HANDLE_TYPE = HandleType::Session;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
private:
void SetState(State state) {
atomic_state = static_cast<u8>(state);
}
State GetState() const {
return static_cast<State>(atomic_state.load());
}
private:
KServerSession server;
KClientSession client;
std::atomic<std::underlying_type<State>::type> atomic_state{
static_cast<std::underlying_type<State>::type>(State::Invalid)};
ClientPort* port{};
std::string name;
Process* process{};
bool initialized{};
};
} // namespace Kernel

View File

@ -33,11 +33,13 @@ class ClientPort;
class GlobalSchedulerContext;
class HandleTable;
class KAutoObjectWithListContainer;
class KClientSession;
class KEvent;
class KLinkedListNode;
class KMemoryManager;
class KResourceLimit;
class KScheduler;
class KSession;
class KSharedMemory;
class KThread;
class KWritableEvent;
@ -272,6 +274,10 @@ public:
return slab_heap_container->linked_list_node;
} else if constexpr (std::is_same_v<T, KWritableEvent>) {
return slab_heap_container->writeable_event;
} else if constexpr (std::is_same_v<T, KClientSession>) {
return slab_heap_container->client_session;
} else if constexpr (std::is_same_v<T, KSession>) {
return slab_heap_container->session;
}
}
@ -312,6 +318,8 @@ private:
KSlabHeap<KSharedMemory> shared_memory;
KSlabHeap<KLinkedListNode> linked_list_node;
KSlabHeap<KWritableEvent> writeable_event;
KSlabHeap<KClientSession> client_session;
KSlabHeap<KSession> session;
};
std::unique_ptr<SlabHeapContainer> slab_heap_container;

View File

@ -5,10 +5,10 @@
#include <tuple>
#include "common/assert.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
@ -16,17 +16,17 @@ namespace Kernel {
ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
ServerPort::~ServerPort() = default;
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
ResultVal<KServerSession*> ServerPort::Accept() {
if (pending_sessions.empty()) {
return ResultNotFound;
}
auto session = std::move(pending_sessions.back());
auto* session = pending_sessions.back();
pending_sessions.pop_back();
return MakeResult(std::move(session));
return MakeResult(session);
}
void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) {
void ServerPort::AppendPendingSession(KServerSession* pending_session) {
pending_sessions.push_back(std::move(pending_session));
if (pending_sessions.size() == 1) {
NotifyAvailable();

View File

@ -17,7 +17,7 @@ namespace Kernel {
class ClientPort;
class KernelCore;
class ServerSession;
class KServerSession;
class SessionRequestHandler;
class ServerPort final : public KSynchronizationObject {
@ -55,7 +55,7 @@ public:
* Accepts a pending incoming connection on this port. If there are no pending sessions, will
* return ERR_NO_PENDING_SESSIONS.
*/
ResultVal<std::shared_ptr<ServerSession>> Accept();
ResultVal<KServerSession*> Accept();
/// Whether or not this server port has an HLE handler available.
bool HasHLEHandler() const {
@ -77,7 +77,7 @@ public:
/// Appends a ServerSession to the collection of ServerSessions
/// waiting to be accepted by this port.
void AppendPendingSession(std::shared_ptr<ServerSession> pending_session);
void AppendPendingSession(KServerSession* pending_session);
bool IsSignaled() const override;
@ -85,7 +85,7 @@ public:
private:
/// ServerSessions waiting to be accepted by the port
std::vector<std::shared_ptr<ServerSession>> pending_sessions;
std::vector<KServerSession*> pending_sessions;
/// This session's HLE request handler template (optional)
/// ServerSessions created from this port inherit a reference to this handler.

View File

@ -13,8 +13,8 @@
#include "common/scope_exit.h"
#include "common/thread.h"
#include "core/core.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/service_thread.h"
#include "core/hle/lock.h"
#include "video_core/renderer_base.h"
@ -26,7 +26,7 @@ public:
explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
~Impl();
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
private:
std::vector<std::thread> threads;
@ -69,18 +69,27 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
});
}
void ServiceThread::Impl::QueueSyncRequest(ServerSession& session,
void ServiceThread::Impl::QueueSyncRequest(KSession& session,
std::shared_ptr<HLERequestContext>&& context) {
{
std::unique_lock lock{queue_mutex};
// ServerSession owns the service thread, so we cannot caption a strong pointer here in the
// event that the ServerSession is terminated.
std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)};
requests.emplace([weak_ptr, context{std::move(context)}]() {
if (auto strong_ptr = weak_ptr.lock()) {
strong_ptr->CompleteSyncRequest(*context);
// Open a reference to the session to ensure it is not closes while the service request
// completes asynchronously.
session.Open();
requests.emplace([session_ptr{&session}, context{std::move(context)}]() {
// Close the reference.
SCOPE_EXIT({ session_ptr->Close(); });
// If the session has been closed, we are done.
if (session_ptr->IsServerClosed()) {
return;
}
// Complete the service request.
KScopedAutoObject server_session{&session_ptr->GetServerSession()};
server_session->CompleteSyncRequest(*context);
});
}
condition.notify_one();
@ -102,7 +111,7 @@ ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const
ServiceThread::~ServiceThread() = default;
void ServiceThread::QueueSyncRequest(ServerSession& session,
void ServiceThread::QueueSyncRequest(KSession& session,
std::shared_ptr<HLERequestContext>&& context) {
impl->QueueSyncRequest(session, std::move(context));
}

View File

@ -11,14 +11,14 @@ namespace Kernel {
class HLERequestContext;
class KernelCore;
class ServerSession;
class KSession;
class ServiceThread final {
public:
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
~ServiceThread();
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
private:
class Impl;

View File

@ -1,41 +0,0 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
namespace Kernel {
Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {}
Session::~Session() {
// Release reserved resource when the Session pair was created.
kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1);
}
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
// Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(),
LimitableResource::Sessions);
ASSERT(session_reservation.Succeeded());
auto session{std::make_shared<Session>(kernel)};
auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()};
auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()};
session->name = std::move(name);
session->client = client_session;
session->server = server_session;
session_reservation.Commit();
return std::make_pair(std::move(client_session), std::move(server_session));
}
bool Session::IsSignaled() const {
UNIMPLEMENTED();
return true;
}
} // namespace Kernel

View File

@ -1,64 +0,0 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include <utility>
#include "core/hle/kernel/k_synchronization_object.h"
namespace Kernel {
class ClientSession;
class ServerSession;
/**
* Parent structure to link the client and server endpoints of a session with their associated
* client port.
*/
class Session final : public KSynchronizationObject {
public:
explicit Session(KernelCore& kernel);
~Session() override;
using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>;
static SessionPair Create(KernelCore& kernel, std::string name = "Unknown");
std::string GetName() const override {
return name;
}
static constexpr HandleType HANDLE_TYPE = HandleType::Session;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
bool IsSignaled() const override;
void Finalize() override {}
std::shared_ptr<ClientSession> Client() {
if (auto result{client.lock()}) {
return result;
}
return {};
}
std::shared_ptr<ServerSession> Server() {
if (auto result{server.lock()}) {
return result;
}
return {};
}
private:
std::string name;
std::weak_ptr<ClientSession> client;
std::weak_ptr<ServerSession> server;
};
} // namespace Kernel

View File

@ -22,9 +22,9 @@
#include "core/core_timing_util.h"
#include "core/cpu_manager.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_condition_variable.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_memory_block.h"
@ -323,12 +323,12 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
auto client_port = it->second;
std::shared_ptr<ClientSession> client_session;
KClientSession* client_session{};
CASCADE_RESULT(client_session, client_port->Connect());
// Return the client session
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
CASCADE_RESULT(*out_handle, handle_table.Create(client_session.get()));
CASCADE_RESULT(*out_handle, handle_table.Create(client_session));
return RESULT_SUCCESS;
}
@ -340,16 +340,14 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,
/// Makes a blocking IPC call to an OS service.
static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
auto& kernel = system.Kernel();
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
auto session = handle_table.Get<ClientSession>(handle);
if (!session) {
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
return ResultInvalidHandle;
}
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
auto& kernel = system.Kernel();
KScopedAutoObject session =
kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
auto thread = kernel.CurrentScheduler()->GetCurrentThread();
{
KScopedSchedulerLock lock(kernel);

View File

@ -14,7 +14,6 @@
#include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"

View File

@ -14,7 +14,6 @@
#include "core/hardware_properties.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_writable_event.h"

View File

@ -4,7 +4,6 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/mm/mm_u.h"
#include "core/hle/service/sm/sm.h"

View File

@ -21,11 +21,8 @@ class System;
}
namespace Kernel {
class ClientPort;
class ServerPort;
class ServerSession;
class HLERequestContext;
} // namespace Kernel
}
namespace Service {

View File

@ -5,9 +5,9 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/service/sm/controller.h"
namespace Service::SM {
@ -30,7 +30,7 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(RESULT_SUCCESS);
rb.PushMoveObjects(ctx.Session()->GetParent()->Client().get());
rb.PushMoveObjects(ctx.Session()->GetParent()->GetClientSession());
}
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {

View File

@ -7,7 +7,9 @@
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/result.h"
#include "core/hle/service/sm/controller.h"
@ -89,13 +91,6 @@ ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
return MakeResult(it->second);
}
ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService(
const std::string& name) {
CASCADE_RESULT(auto client_port, GetServicePort(name));
return client_port->Connect();
}
SM::~SM() = default;
/**
@ -130,19 +125,20 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
return;
}
auto [client, server] = Kernel::Session::Create(kernel, name);
auto* session = Kernel::KSession::Create(kernel);
session->Initialize(std::move(name));
const auto& server_port = client_port.Unwrap()->GetServerPort();
if (server_port->GetHLEHandler()) {
server_port->GetHLEHandler()->ClientConnected(client, server);
server_port->GetHLEHandler()->ClientConnected(session);
} else {
server_port->AppendPendingSession(server);
server_port->AppendPendingSession(&session->GetServerSession());
}
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetObjectId());
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(RESULT_SUCCESS);
rb.PushMoveObjects(client.get());
rb.PushMoveObjects(session->GetClientSession());
}
void SM::RegisterService(Kernel::HLERequestContext& ctx) {

View File

@ -22,7 +22,7 @@ class System;
namespace Kernel {
class ClientPort;
class ClientSession;
class KClientSession;
class KernelCore;
class ServerPort;
class SessionRequestHandler;
@ -59,7 +59,6 @@ public:
u32 max_sessions);
ResultCode UnregisterService(const std::string& name);
ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const {
@ -81,7 +80,7 @@ private:
std::weak_ptr<SM> sm_interface;
std::unique_ptr<Controller> controller_interface;
/// Map of registered services, retrieved using GetServicePort or ConnectToService.
/// Map of registered services, retrieved using GetServicePort.
std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services;
/// Kernel context

View File

@ -9,7 +9,6 @@
#include "core/hardware_properties.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/time/interface.h"