diff options
| author | bunnei <bunneidev@gmail.com> | 2021-04-23 17:00:15 -0700 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2021-05-05 16:40:52 -0700 | 
| commit | 626f746971d1d3216a38b20680959df3a1f5f256 (patch) | |
| tree | d9b9448732e264e84557e12d7a14a40f00cb006f /src/core | |
| parent | 7a068641006da739d6af5681a022018785379365 (diff) | |
hle: kernel: Migrate KPort, KClientPort, and KServerPort to KAutoObject.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/init/init_slab_setup.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.cpp | 119 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.h | 46 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_event.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_port.cpp | 68 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_port.h | 87 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_port.cpp | 94 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_port.h | 55 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.h | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_session.cpp | 18 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_session.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 22 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc_results.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 31 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.h | 13 | 
22 files changed, 444 insertions, 166 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 487e6f720..cee6d30f6 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -194,6 +194,8 @@ add_library(core STATIC      hle/kernel/k_page_linked_list.h      hle/kernel/k_page_table.cpp      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_readable_event.cpp      hle/kernel/k_readable_event.h diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 18aebf6ea..8128445fd 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -136,10 +136,10 @@ public:              context->AddDomainObject(std::move(iface));          } else {              auto* session = Kernel::KSession::Create(kernel); -            session->Initialize(iface->GetServiceName()); +            session->Initialize(nullptr, iface->GetServiceName());              context->AddMoveObject(&session->GetClientSession()); -            iface->ClientConnected(session); +            iface->ClientConnected(&session->GetServerSession());          }      } diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 9e1e63204..ddff9ce99 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -35,14 +35,12 @@ SessionRequestHandler::SessionRequestHandler() = default;  SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(KSession* session) { -    session->GetServerSession().SetHleHandler(shared_from_this()); -    sessions.push_back(session); +void SessionRequestHandler::ClientConnected(KServerSession* session) { +    session->SetHleHandler(shared_from_this());  } -void SessionRequestHandler::ClientDisconnected(KSession* session) { -    session->GetServerSession().SetHleHandler(nullptr); -    boost::range::remove_erase(sessions, session); +void SessionRequestHandler::ClientDisconnected(KServerSession* session) { +    session->SetHleHandler(nullptr);  }  HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index b7484c445..d63c730ac 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -72,20 +72,14 @@ public:       * associated ServerSession alive for the duration of 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       * associated ServerSession.       * @param server_session ServerSession associated with the connection.       */ -    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<KSession*> sessions; +    void ClientDisconnected(KServerSession* session);  };  /** diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index a5ddd7344..f8c255732 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -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_port.h"  #include "core/hle/kernel/k_resource_limit.h"  #include "core/hle/kernel/k_session.h"  #include "core/hle/kernel/k_shared_memory.h" @@ -30,8 +31,9 @@ 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(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__)                         \ +    HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__)                                             \      HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__)                             \ +    HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__)                         \      HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__)                                       \      HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 00e1bbc59..b6f1d713f 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -1,12 +1,14 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2021 Citra Emulator Project  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include "common/scope_exit.h"  #include "core/hle/kernel/hle_ipc.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/object.h"  #include "core/hle/kernel/svc_results.h"  namespace Kernel { @@ -14,45 +16,110 @@ namespace Kernel {  KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}  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_;      name = std::move(name_);  } -KServerPort* KClientPort::GetServerPort() const { -    return server_port; -} +void KClientPort::OnSessionFinalized() { +    KScopedSchedulerLock sl{kernel}; -ResultVal<KClientSession*> KClientPort::Connect() { -    if (num_sessions >= max_sessions) { -        return ResultOutOfSessions; +    const auto prev = num_sessions--; +    if (prev == max_sessions) { +        this->NotifyAvailable();      } -    num_sessions++; +} -    auto* session = Kernel::KSession::Create(kernel); -    session->Initialize(name + ":ClientPort"); +void KClientPort::OnServerClosed() {} -    if (server_port->HasHLEHandler()) { -        server_port->GetHLEHandler()->ClientConnected(session); -    } else { -        server_port->AppendPendingSession(std::addressof(session->GetServerSession())); -    } +bool KClientPort::IsLight() const { +    return this->GetParent()->IsLight(); +} -    return MakeResult(std::addressof(session->GetClientSession())); +bool KClientPort::IsServerClosed() const { +    return this->GetParent()->IsServerClosed();  } -void KClientPort::ConnectionClosed() { -    if (num_sessions == 0) { -        return; -    } +void KClientPort::Destroy() { +    // Note with our parent that we're closed. +    parent->OnClientClosed(); -    --num_sessions; +    // Close our reference to our parent. +    parent->Close();  } -void KClientPort::Destroy() {} -  bool KClientPort::IsSignaled() const {      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 diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 60dea4763..43a17f4a4 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -15,7 +15,7 @@ namespace Kernel {  class KClientSession;  class KernelCore; -class KServerPort; +class KPort;  class KClientPort final : public KSynchronizationObject {      KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); @@ -24,30 +24,33 @@ public:      explicit KClientPort(KernelCore& kernel);      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_); - -    KServerPort* GetServerPort() const; +    constexpr const KPort* GetParent() const { +        return parent; +    } -    /** -     * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's -     * 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(); +    s32 GetNumSessions() const { +        return num_sessions; +    } +    s32 GetPeakSessions() const { +        return peak_sessions; +    } +    s32 GetMaxSessions() const { +        return max_sessions; +    } -    /** -     * Signifies that a previously active connection has been closed, -     * decreasing the total number of active connections to this port. -     */ -    void ConnectionClosed(); +    bool IsLight() const; +    bool IsServerClosed() const;      // Overridden virtual functions.      virtual void Destroy() override;      virtual bool IsSignaled() const override; +    ResultCode CreateSession(KClientSession** out); +      // DEPRECATED      std::string GetTypeName() const override { @@ -63,10 +66,11 @@ public:      }  private: -    KServerPort* server_port{};      ///< ServerPort associated with this client port. -    s32 max_sessions{};              ///< Maximum number of simultaneous sessions the port can have -    std::atomic<s32> num_sessions{}; ///< Number of currently open sessions to this port -    std::string name;                ///< Name of client port (optional) +    std::atomic<s32> num_sessions{}; +    std::atomic<s32> peak_sessions{}; +    s32 max_sessions{}; +    KPort* parent{}; +    std::string name;  };  } // namespace Kernel diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index 2c48a0499..45634e401 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -20,7 +20,7 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObj  public:      explicit KEvent(KernelCore& kernel); -    ~KEvent() override; +    virtual ~KEvent();      void Initialize(std::string&& name); diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp new file mode 100644 index 000000000..734aa2a8c --- /dev/null +++ b/src/core/hle/kernel/k_port.cpp @@ -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 diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h new file mode 100644 index 000000000..68c8ed8df --- /dev/null +++ b/src/core/hle/kernel/k_port.h @@ -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 diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp index 2c51d66db..fcc04abaa 100644 --- a/src/core/hle/kernel/k_server_port.cpp +++ b/src/core/hle/kernel/k_server_port.cpp @@ -1,10 +1,12 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2021 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included.  #include <tuple>  #include "common/assert.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_session.h"  #include "core/hle/kernel/k_thread.h" @@ -16,50 +18,88 @@ namespace Kernel {  KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}  KServerPort::~KServerPort() = default; -void KServerPort::Initialize(std::string&& name_) { +void KServerPort::Initialize(KPort* parent_, std::string&& name_) {      // Set member variables. +    parent = parent_;      name = std::move(name_);  } -ResultVal<KServerSession*> KServerPort::Accept() { -    if (pending_sessions.empty()) { -        return ResultNotFound; -    } - -    auto* session = pending_sessions.back(); -    pending_sessions.pop_back(); -    return MakeResult(session); +bool KServerPort::IsLight() const { +    return this->GetParent()->IsLight();  } -void KServerPort::AppendPendingSession(KServerSession* pending_session) { -    pending_sessions.push_back(std::move(pending_session)); -    if (pending_sessions.size() == 1) { -        NotifyAvailable(); +void KServerPort::CleanupSessions() { +    // Ensure our preconditions are met. +    if (this->IsLight()) { +        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 { -    return !pending_sessions.empty(); +    if (this->IsLight()) { +        UNIMPLEMENTED(); +        return false; +    } else { +        return !session_list.empty(); +    }  } -KServerPort::PortPair KServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, -                                                  std::string name) { -    KServerPort* server_port = new KServerPort(kernel); -    KClientPort* client_port = new KClientPort(kernel); +void KServerPort::EnqueueSession(KServerSession* session) { +    ASSERT(!this->IsLight()); + +    KScopedSchedulerLock sl{kernel}; -    KAutoObject::Create(server_port); -    KAutoObject::Create(client_port); +    // Add the session to our queue. +    session_list.push_back(*session); +    if (session_list.size() == 1) { +        this->NotifyAvailable(); +    } +} -    server_port->Initialize(name + "_Server"); -    client_port->Initialize(max_sessions, name + "_Client"); +KServerSession* KServerPort::AcceptSession() { +    ASSERT(!this->IsLight()); -    client_port->server_port = server_port; +    KScopedSchedulerLock sl{kernel}; -    server_port->name = name + "_Server"; +    // Return the first session in the list. +    if (session_list.empty()) { +        return nullptr; +    } -    return std::make_pair(server_port, client_port); +    KServerSession* session = std::addressof(session_list.front()); +    session_list.pop_front(); +    return session;  }  } // namespace Kernel diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index 13fa54e5e..9f45ca3f4 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2021 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -8,46 +8,33 @@  #include <string>  #include <utility>  #include <vector> + +#include <boost/intrusive/list.hpp> +  #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/object.h"  #include "core/hle/result.h"  namespace Kernel { -class KClientPort;  class KernelCore; -class KServerSession; +class KPort;  class SessionRequestHandler;  class KServerPort final : public KSynchronizationObject {      KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); +private: +    using SessionList = boost::intrusive::list<KServerSession>; +  public:      explicit KServerPort(KernelCore& kernel);      virtual ~KServerPort() override;      using HLEHandler = std::shared_ptr<SessionRequestHandler>; -    using PortPair = std::pair<KServerPort*, KClientPort*>; - -    void Initialize(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(); +    void Initialize(KPort* parent_, std::string&& name_);      /// Whether or not this server port has an HLE handler available.      bool HasHLEHandler() const { @@ -67,9 +54,15 @@ public:          hle_handler = std::move(hle_handler_);      } -    /// Appends a ServerSession to the collection of ServerSessions -    /// waiting to be accepted by this port. -    void AppendPendingSession(KServerSession* pending_session); +    void EnqueueSession(KServerSession* pending_session); + +    KServerSession* AcceptSession(); + +    constexpr const KPort* GetParent() const { +        return parent; +    } + +    bool IsLight() const;      // Overridden virtual functions.      virtual void Destroy() override; @@ -90,14 +83,12 @@ public:      }  private: -    /// ServerSessions waiting to be accepted by the port -    std::vector<KServerSession*> pending_sessions; +    void CleanupSessions(); -    /// This session's HLE request handler template (optional) -    /// ServerSessions created from this port inherit a reference to this handler. +private: +    SessionList session_list;      HLEHandler hle_handler; - -    /// Name of the port (optional) +    KPort* parent{};      std::string name;  }; diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 46ba7081b..863f9aa5f 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -50,7 +50,7 @@ void KServerSession::OnClientClosed() {      if (handler) {          // Note that after this returns, this server session's hle_handler is          // invalidated (set to null). -        handler->ClientDisconnected(parent); +        handler->ClientDisconnected(this);      }  } diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index ef81c4e30..d748754d0 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -9,6 +9,8 @@  #include <utility>  #include <vector> +#include <boost/intrusive/list.hpp> +  #include "common/threadsafe_queue.h"  #include "core/hle/kernel/k_synchronization_object.h"  #include "core/hle/kernel/service_thread.h" @@ -31,7 +33,8 @@ class KSession;  class SessionRequestHandler;  class KThread; -class KServerSession final : public KSynchronizationObject { +class KServerSession final : public KSynchronizationObject, +                             public boost::intrusive::list_base_hook<> {      KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);      friend class ServiceThread; diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index ca1cf18cd..6f4276189 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -1,8 +1,9 @@ -// Copyright 2019 yuzu emulator team +// Copyright 2021 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_port.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" @@ -14,7 +15,7 @@ KSession::KSession(KernelCore& kernel)      : KAutoObjectWithSlabHeapAndContainer{kernel}, server{kernel}, client{kernel} {}  KSession::~KSession() = default; -void KSession::Initialize(std::string&& name_) { +void KSession::Initialize(KClientPort* port_, 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 @@ -37,11 +38,22 @@ void KSession::Initialize(std::string&& name_) {      process = kernel.CurrentProcess();      process->Open(); +    // Set our port. +    port = port_; +    if (port != nullptr) { +        port->Open(); +    } +      // Mark initialized.      initialized = true;  } -void KSession::Finalize() {} +void KSession::Finalize() { +    if (port != nullptr) { +        port->OnSessionFinalized(); +        port->Close(); +    } +}  void KSession::OnServerClosed() {      if (GetState() == State::Normal) { diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 6a6fcb588..1597cc608 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -28,7 +28,7 @@ public:      explicit KSession(KernelCore& kernel);      virtual ~KSession() override; -    void Initialize(std::string&& name_); +    void Initialize(KClientPort* port_, std::string&& name_);      virtual void Finalize() override; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 19b3530b4..723be6b51 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -37,6 +37,8 @@ class KClientSession;  class KEvent;  class KLinkedListNode;  class KMemoryManager; +class KPort; +class Process;  class KResourceLimit;  class KScheduler;  class KSession; @@ -45,7 +47,6 @@ class KThread;  class KTransferMemory;  class KWritableEvent;  class PhysicalCore; -class Process;  class ServiceThread;  class Synchronization;  class TimeManager; @@ -272,6 +273,8 @@ public:              return slab_heap_container->event;          } else if constexpr (std::is_same_v<T, KLinkedListNode>) {              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>) {              return slab_heap_container->process;          } else if constexpr (std::is_same_v<T, KResourceLimit>) { @@ -323,6 +326,7 @@ private:          KSlabHeap<KClientSession> client_session;          KSlabHeap<KEvent> event;          KSlabHeap<KLinkedListNode> linked_list_node; +        KSlabHeap<KPort> port;          KSlabHeap<Process> process;          KSlabHeap<KResourceLimit> resource_limit;          KSlabHeap<KSession> session; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8d8d3dd5a..ef8fa98a9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -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  static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,                                       VAddr port_name_address) { -    std::lock_guard lock{HLE::g_hle_lock};      auto& memory = system.Memory(); -      if (!memory.IsValidVirtualAddress(port_name_address)) {          LOG_ERROR(Kernel_SVC,                    "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); +    // Get the current handle table.      auto& kernel = system.Kernel(); +    auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + +    // Find the client port.      const auto it = kernel.FindNamedPort(port_name);      if (!kernel.IsValidNamedPort(it)) {          LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);          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{}; -    CASCADE_RESULT(client_session, client_port->Connect()); +    // Register the session in the table, close the extra reference. +    handle_table.Add(out_handle, session); +    session->Close(); -    // Return the client session -    auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); -    handle_table.Add(out_handle, client_session); +    // We succeeded.      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.  static ResultCode SendSyncRequest(Core::System& system, Handle handle) { -    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); +    LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());      auto thread = kernel.CurrentScheduler()->GetCurrentThread();      { diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index cd32acd99..53a940723 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h @@ -36,6 +36,7 @@ constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};  constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123};  constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};  constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126}; +constexpr ResultCode ResultPortClosed{ErrorModule::Kernel, 131};  constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132};  constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519}; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index a882b3b4e..42e464024 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -116,10 +116,11 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {      ASSERT(!port_installed); -    auto [server_port, client_port] = -        Kernel::KServerPort::CreatePortPair(kernel, max_sessions, service_name); -    server_port->SetHleHandler(shared_from_this()); -    kernel.AddNamedPort(service_name, client_port); +    auto* port = Kernel::KPort::Create(kernel); +    port->Initialize(max_sessions, false, service_name); +    port->GetServerPort().SetHleHandler(shared_from_this()); +    kernel.AddNamedPort(service_name, &port->GetClientPort()); +      port_installed = true;  } diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 51274bfb1..71ab4b6f5 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -8,6 +8,7 @@  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/k_client_port.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_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;      } -    auto [server_port, client_port] = -        Kernel::KServerPort::CreatePortPair(kernel, max_sessions, name); +    auto* port = Kernel::KPort::Create(kernel); +    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(server_port); +    return MakeResult(&port->GetServerPort());  }  ResultCode ServiceManager::UnregisterService(const std::string& name) { @@ -83,7 +83,7 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {      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));      auto it = registered_services.find(name); @@ -118,25 +118,26 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {      std::string name(name_buf.begin(), end); -    auto client_port = service_manager->GetServicePort(name); -    if (client_port.Failed()) { +    auto result = service_manager->GetServicePort(name); +    if (result.Failed()) {          IPC::ResponseBuilder rb{ctx, 2}; -        rb.Push(client_port.Code()); -        LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); +        rb.Push(result.Code()); +        LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);          if (name.length() == 0)              return; // LibNX Fix          UNIMPLEMENTED();          return;      } +    auto* port = result.Unwrap(); +      auto* session = Kernel::KSession::Create(kernel); -    session->Initialize(std::move(name)); +    session->Initialize(&port->GetClientPort(), std::move(name)); -    const auto& server_port = client_port.Unwrap()->GetServerPort(); -    if (server_port->GetHLEHandler()) { -        server_port->GetHLEHandler()->ClientConnected(session); +    if (port->GetServerPort().GetHLEHandler()) { +        port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession());      } else { -        server_port->AppendPendingSession(&session->GetServerSession()); +        port->EnqueueSession(&session->GetServerSession());      }      LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetObjectId()); diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index b0204c4bb..af5010c3b 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -10,9 +10,7 @@  #include <unordered_map>  #include "common/concepts.h" -#include "core/hle/kernel/k_client_port.h" -#include "core/hle/kernel/k_server_port.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_port.h"  #include "core/hle/result.h"  #include "core/hle/service/service.h" @@ -24,6 +22,7 @@ namespace Kernel {  class KClientPort;  class KClientSession;  class KernelCore; +class KPort;  class KServerPort;  class SessionRequestHandler;  } // namespace Kernel @@ -57,7 +56,7 @@ public:      ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions);      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>      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);              return nullptr;          } -        auto port = service->second->GetServerPort(); +        auto* port = service->second;          if (port == 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); @@ -80,7 +79,7 @@ private:      std::unique_ptr<Controller> controller_interface;      /// 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::KernelCore& kernel;  | 
