// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #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" namespace Kernel { KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} KServerPort::~KServerPort() = default; void KServerPort::Initialize(KPort* parent) { // Set member variables. m_parent = parent; } bool KServerPort::IsLight() const { return this->GetParent()->IsLight(); } void KServerPort::CleanupSessions() { // Ensure our preconditions are met. if (this->IsLight()) { ASSERT(m_session_list.empty()); } else { ASSERT(m_light_session_list.empty()); } // Cleanup the session list. while (true) { // Get the last session in the list. KServerSession* session = nullptr; { KScopedSchedulerLock sl{m_kernel}; if (!m_session_list.empty()) { session = std::addressof(m_session_list.front()); m_session_list.pop_front(); } } // Close the session. if (session != nullptr) { session->Close(); } else { break; } } // Cleanup the light session list. while (true) { // Get the last session in the list. KLightServerSession* session = nullptr; { KScopedSchedulerLock sl{m_kernel}; if (!m_light_session_list.empty()) { session = std::addressof(m_light_session_list.front()); m_light_session_list.pop_front(); } } // Close the session. if (session != nullptr) { session->Close(); } else { break; } } } void KServerPort::Destroy() { // Note with our parent that we're closed. m_parent->OnServerClosed(); // Perform necessary cleanup of our session lists. this->CleanupSessions(); // Close our reference to our parent. m_parent->Close(); } bool KServerPort::IsSignaled() const { if (this->IsLight()) { return !m_light_session_list.empty(); } else { return !m_session_list.empty(); } } void KServerPort::EnqueueSession(KServerSession* session) { ASSERT(!this->IsLight()); KScopedSchedulerLock sl{m_kernel}; // Add the session to our queue. m_session_list.push_back(*session); if (m_session_list.size() == 1) { this->NotifyAvailable(); } } void KServerPort::EnqueueSession(KLightServerSession* session) { ASSERT(this->IsLight()); KScopedSchedulerLock sl{m_kernel}; // Add the session to our queue. m_light_session_list.push_back(*session); if (m_light_session_list.size() == 1) { this->NotifyAvailable(); } } KServerSession* KServerPort::AcceptSession() { ASSERT(!this->IsLight()); KScopedSchedulerLock sl{m_kernel}; // Return the first session in the list. if (m_session_list.empty()) { return nullptr; } KServerSession* session = std::addressof(m_session_list.front()); m_session_list.pop_front(); return session; } KLightServerSession* KServerPort::AcceptLightSession() { ASSERT(this->IsLight()); KScopedSchedulerLock sl{m_kernel}; // Return the first session in the list. if (m_light_session_list.empty()) { return nullptr; } KLightServerSession* session = std::addressof(m_light_session_list.front()); m_light_session_list.pop_front(); return session; } } // namespace Kernel