mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #3177 from bunnei/new-ipc-req
kernel: Implement a more accurate IPC dispatch.
This commit is contained in:
		
						commit
						5c7253f8d3
					
				@ -170,6 +170,7 @@ add_library(core STATIC
 | 
				
			|||||||
    hle/kernel/server_port.h
 | 
					    hle/kernel/server_port.h
 | 
				
			||||||
    hle/kernel/server_session.cpp
 | 
					    hle/kernel/server_session.cpp
 | 
				
			||||||
    hle/kernel/server_session.h
 | 
					    hle/kernel/server_session.h
 | 
				
			||||||
 | 
					    hle/kernel/session.cpp
 | 
				
			||||||
    hle/kernel/session.h
 | 
					    hle/kernel/session.h
 | 
				
			||||||
    hle/kernel/shared_memory.cpp
 | 
					    hle/kernel/shared_memory.cpp
 | 
				
			||||||
    hle/kernel/shared_memory.h
 | 
					    hle/kernel/shared_memory.h
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@
 | 
				
			|||||||
#include "core/hle/kernel/hle_ipc.h"
 | 
					#include "core/hle/kernel/hle_ipc.h"
 | 
				
			||||||
#include "core/hle/kernel/object.h"
 | 
					#include "core/hle/kernel/object.h"
 | 
				
			||||||
#include "core/hle/kernel/server_session.h"
 | 
					#include "core/hle/kernel/server_session.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/session.h"
 | 
				
			||||||
#include "core/hle/result.h"
 | 
					#include "core/hle/result.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace IPC {
 | 
					namespace IPC {
 | 
				
			||||||
@ -139,10 +140,9 @@ public:
 | 
				
			|||||||
            context->AddDomainObject(std::move(iface));
 | 
					            context->AddDomainObject(std::move(iface));
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            auto& kernel = Core::System::GetInstance().Kernel();
 | 
					            auto& kernel = Core::System::GetInstance().Kernel();
 | 
				
			||||||
            auto [server, client] =
 | 
					            auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
 | 
				
			||||||
                Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName());
 | 
					 | 
				
			||||||
            iface->ClientConnected(server);
 | 
					 | 
				
			||||||
            context->AddMoveObject(std::move(client));
 | 
					            context->AddMoveObject(std::move(client));
 | 
				
			||||||
 | 
					            iface->ClientConnected(std::move(server));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@
 | 
				
			|||||||
#include "core/hle/kernel/object.h"
 | 
					#include "core/hle/kernel/object.h"
 | 
				
			||||||
#include "core/hle/kernel/server_port.h"
 | 
					#include "core/hle/kernel/server_port.h"
 | 
				
			||||||
#include "core/hle/kernel/server_session.h"
 | 
					#include "core/hle/kernel/server_session.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/session.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Kernel {
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -20,28 +21,23 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
 | 
					ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
 | 
				
			||||||
    // Note: Threads do not wait for the server endpoint to call
 | 
					 | 
				
			||||||
    // AcceptSession before returning from this call.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (active_sessions >= max_sessions) {
 | 
					    if (active_sessions >= max_sessions) {
 | 
				
			||||||
        return ERR_MAX_CONNECTIONS_REACHED;
 | 
					        return ERR_MAX_CONNECTIONS_REACHED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    active_sessions++;
 | 
					    active_sessions++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
 | 
					    auto [client, server] = Kernel::Session::Create(kernel, name);
 | 
				
			||||||
    auto [server, client] =
 | 
					 | 
				
			||||||
        ServerSession::CreateSessionPair(kernel, server_port->GetName(), SharedFrom(this));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (server_port->HasHLEHandler()) {
 | 
					    if (server_port->HasHLEHandler()) {
 | 
				
			||||||
        server_port->GetHLEHandler()->ClientConnected(server);
 | 
					        server_port->GetHLEHandler()->ClientConnected(std::move(server));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        server_port->AppendPendingSession(server);
 | 
					        server_port->AppendPendingSession(std::move(server));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Wake the threads waiting on the ServerPort
 | 
					    // Wake the threads waiting on the ServerPort
 | 
				
			||||||
    server_port->WakeupAllWaitingThreads();
 | 
					    server_port->WakeupAllWaitingThreads();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return MakeResult(client);
 | 
					    return MakeResult(std::move(client));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClientPort::ConnectionClosed() {
 | 
					void ClientPort::ConnectionClosed() {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
// Copyright 2016 Citra Emulator Project
 | 
					// Copyright 2019 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -12,22 +12,44 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kernel {
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {}
 | 
					ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ClientSession::~ClientSession() {
 | 
					ClientSession::~ClientSession() {
 | 
				
			||||||
    // This destructor will be called automatically when the last ClientSession handle is closed by
 | 
					    // This destructor will be called automatically when the last ClientSession handle is closed by
 | 
				
			||||||
    // the emulated application.
 | 
					    // the emulated application.
 | 
				
			||||||
    if (auto server = parent->server.lock()) {
 | 
					    if (parent->Server()) {
 | 
				
			||||||
        server->ClientDisconnected();
 | 
					        parent->Server()->ClientDisconnected();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ResultCode ClientSession::SendSyncRequest(Thread* thread, Memory::Memory& memory) {
 | 
					bool ClientSession::ShouldWait(const Thread* thread) const {
 | 
				
			||||||
    // Signal the server session that new data is available
 | 
					    UNIMPLEMENTED();
 | 
				
			||||||
    if (auto server = parent->server.lock()) {
 | 
					    return {};
 | 
				
			||||||
        return server->HandleSyncRequest(SharedFrom(thread), memory);
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ClientSession::Acquire(Thread* thread) {
 | 
				
			||||||
 | 
					    UNIMPLEMENTED();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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(std::shared_ptr<Thread> thread, Memory::Memory& memory) {
 | 
				
			||||||
 | 
					    // Keep ServerSession alive until we're done working with it.
 | 
				
			||||||
 | 
					    if (!parent->Server()) {
 | 
				
			||||||
 | 
					        return ERR_SESSION_CLOSED_BY_REMOTE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ERR_SESSION_CLOSED_BY_REMOTE;
 | 
					    // Signal the server session that new data is available
 | 
				
			||||||
 | 
					    return parent->Server()->HandleSyncRequest(std::move(thread), memory);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Kernel
 | 
					} // namespace Kernel
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
// Copyright 2016 Citra Emulator Project
 | 
					// Copyright 2019 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -6,7 +6,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include "core/hle/kernel/object.h"
 | 
					
 | 
				
			||||||
 | 
					#include "core/hle/kernel/wait_object.h"
 | 
				
			||||||
 | 
					#include "core/hle/result.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
union ResultCode;
 | 
					union ResultCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -18,15 +20,14 @@ namespace Kernel {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class KernelCore;
 | 
					class KernelCore;
 | 
				
			||||||
class Session;
 | 
					class Session;
 | 
				
			||||||
class ServerSession;
 | 
					 | 
				
			||||||
class Thread;
 | 
					class Thread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClientSession final : public Object {
 | 
					class ClientSession final : public WaitObject {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    explicit ClientSession(KernelCore& kernel);
 | 
					    explicit ClientSession(KernelCore& kernel);
 | 
				
			||||||
    ~ClientSession() override;
 | 
					    ~ClientSession() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    friend class ServerSession;
 | 
					    friend class Session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetTypeName() const override {
 | 
					    std::string GetTypeName() const override {
 | 
				
			||||||
        return "ClientSession";
 | 
					        return "ClientSession";
 | 
				
			||||||
@ -41,9 +42,17 @@ public:
 | 
				
			|||||||
        return HANDLE_TYPE;
 | 
					        return HANDLE_TYPE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ResultCode SendSyncRequest(Thread* thread, Memory::Memory& memory);
 | 
					    ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool ShouldWait(const Thread* thread) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Acquire(Thread* thread) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					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.
 | 
					    /// The parent session, which links to the server endpoint.
 | 
				
			||||||
    std::shared_ptr<Session> parent;
 | 
					    std::shared_ptr<Session> parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -74,6 +74,8 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
 | 
				
			|||||||
        thread->WakeAfterDelay(timeout);
 | 
					        thread->WakeAfterDelay(timeout);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    is_thread_waiting = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return writable_event;
 | 
					    return writable_event;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -264,6 +264,18 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::string Description() const;
 | 
					    std::string Description() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Thread& GetThread() {
 | 
				
			||||||
 | 
					        return *thread;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const Thread& GetThread() const {
 | 
				
			||||||
 | 
					        return *thread;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsThreadWaiting() const {
 | 
				
			||||||
 | 
					        return is_thread_waiting;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
 | 
					    void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -290,6 +302,7 @@ private:
 | 
				
			|||||||
    u32_le command{};
 | 
					    u32_le command{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
 | 
					    std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
 | 
				
			||||||
 | 
					    bool is_thread_waiting{};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Kernel
 | 
					} // namespace Kernel
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@ bool Object::IsWaitable() const {
 | 
				
			|||||||
    case HandleType::ResourceLimit:
 | 
					    case HandleType::ResourceLimit:
 | 
				
			||||||
    case HandleType::ClientPort:
 | 
					    case HandleType::ClientPort:
 | 
				
			||||||
    case HandleType::ClientSession:
 | 
					    case HandleType::ClientSession:
 | 
				
			||||||
 | 
					    case HandleType::Session:
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@ enum class HandleType : u32 {
 | 
				
			|||||||
    ServerPort,
 | 
					    ServerPort,
 | 
				
			||||||
    ClientSession,
 | 
					    ClientSession,
 | 
				
			||||||
    ServerSession,
 | 
					    ServerSession,
 | 
				
			||||||
 | 
					    Session,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Object : NonCopyable, public std::enable_shared_from_this<Object> {
 | 
					class Object : NonCopyable, public std::enable_shared_from_this<Object> {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
// Copyright 2016 Citra Emulator Project
 | 
					// Copyright 2019 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,6 +9,7 @@
 | 
				
			|||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
#include "common/logging/log.h"
 | 
					#include "common/logging/log.h"
 | 
				
			||||||
#include "core/core.h"
 | 
					#include "core/core.h"
 | 
				
			||||||
 | 
					#include "core/core_timing.h"
 | 
				
			||||||
#include "core/hle/ipc_helpers.h"
 | 
					#include "core/hle/ipc_helpers.h"
 | 
				
			||||||
#include "core/hle/kernel/client_port.h"
 | 
					#include "core/hle/kernel/client_port.h"
 | 
				
			||||||
#include "core/hle/kernel/client_session.h"
 | 
					#include "core/hle/kernel/client_session.h"
 | 
				
			||||||
@ -24,34 +25,29 @@
 | 
				
			|||||||
namespace Kernel {
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
 | 
					ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
 | 
				
			||||||
ServerSession::~ServerSession() {
 | 
					ServerSession::~ServerSession() = default;
 | 
				
			||||||
    // This destructor will be called automatically when the last ServerSession handle is closed by
 | 
					 | 
				
			||||||
    // the emulated application.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Decrease the port's connection count.
 | 
					 | 
				
			||||||
    if (parent->port) {
 | 
					 | 
				
			||||||
        parent->port->ConnectionClosed();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
 | 
					ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
 | 
				
			||||||
 | 
					                                                                std::shared_ptr<Session> parent,
 | 
				
			||||||
                                                                std::string name) {
 | 
					                                                                std::string name) {
 | 
				
			||||||
    std::shared_ptr<ServerSession> server_session = std::make_shared<ServerSession>(kernel);
 | 
					    std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    server_session->name = std::move(name);
 | 
					    session->request_event = Core::Timing::CreateEvent(
 | 
				
			||||||
    server_session->parent = nullptr;
 | 
					        name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); });
 | 
				
			||||||
 | 
					    session->name = std::move(name);
 | 
				
			||||||
 | 
					    session->parent = std::move(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return MakeResult(std::move(server_session));
 | 
					    return MakeResult(std::move(session));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ServerSession::ShouldWait(const Thread* thread) const {
 | 
					bool ServerSession::ShouldWait(const Thread* thread) const {
 | 
				
			||||||
    // Wait if we have no pending requests, or if we're currently handling a request.
 | 
					    // Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
 | 
				
			||||||
    if (auto client = parent->client.lock()) {
 | 
					    if (!parent->Client()) {
 | 
				
			||||||
        return pending_requesting_threads.empty() || currently_handling != nullptr;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
 | 
					    // Wait if we have no pending requests, or if we're currently handling a request.
 | 
				
			||||||
    return {};
 | 
					    return pending_requesting_threads.empty() || currently_handling != nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ServerSession::Acquire(Thread* thread) {
 | 
					void ServerSession::Acquire(Thread* thread) {
 | 
				
			||||||
@ -128,14 +124,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
 | 
				
			|||||||
    return RESULT_SUCCESS;
 | 
					    return RESULT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
 | 
					ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) {
 | 
				
			||||||
                                            Memory::Memory& memory) {
 | 
					    u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
 | 
				
			||||||
    // The ServerSession received a sync request, this means that there's new data available
 | 
					    std::shared_ptr<Kernel::HLERequestContext> context{
 | 
				
			||||||
    // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
 | 
					        std::make_shared<Kernel::HLERequestContext>(SharedFrom(this), std::move(thread))};
 | 
				
			||||||
    // similar.
 | 
					
 | 
				
			||||||
    Kernel::HLERequestContext context(SharedFrom(this), thread);
 | 
					    context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
 | 
				
			||||||
    u32* cmd_buf = (u32*)memory.GetPointer(thread->GetTLSAddress());
 | 
					    request_queue.Push(std::move(context));
 | 
				
			||||||
    context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
 | 
					
 | 
				
			||||||
 | 
					    return RESULT_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ResultCode ServerSession::CompleteSyncRequest() {
 | 
				
			||||||
 | 
					    ASSERT(!request_queue.Empty());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto& context = *request_queue.Front();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ResultCode result = RESULT_SUCCESS;
 | 
					    ResultCode result = RESULT_SUCCESS;
 | 
				
			||||||
    // If the session has been converted to a domain, handle the domain request
 | 
					    // If the session has been converted to a domain, handle the domain request
 | 
				
			||||||
@ -147,61 +150,27 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
 | 
				
			|||||||
        result = hle_handler->HandleSyncRequest(context);
 | 
					        result = hle_handler->HandleSyncRequest(context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (thread->GetStatus() == ThreadStatus::Running) {
 | 
					 | 
				
			||||||
        // Put the thread to sleep until the server replies, it will be awoken in
 | 
					 | 
				
			||||||
        // svcReplyAndReceive for LLE servers.
 | 
					 | 
				
			||||||
        thread->SetStatus(ThreadStatus::WaitIPC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (hle_handler != nullptr) {
 | 
					 | 
				
			||||||
            // For HLE services, we put the request threads to sleep for a short duration to
 | 
					 | 
				
			||||||
            // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for
 | 
					 | 
				
			||||||
            // other reasons like an async callback. The IPC overhead is needed to prevent
 | 
					 | 
				
			||||||
            // starvation when a thread only does sync requests to HLE services while a
 | 
					 | 
				
			||||||
            // lower-priority thread is waiting to run.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // This delay was approximated in a homebrew application by measuring the average time
 | 
					 | 
				
			||||||
            // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC
 | 
					 | 
				
			||||||
            // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have
 | 
					 | 
				
			||||||
            // a high variance and vary between models.
 | 
					 | 
				
			||||||
            static constexpr u64 IPCDelayNanoseconds = 39000;
 | 
					 | 
				
			||||||
            thread->WakeAfterDelay(IPCDelayNanoseconds);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            // Add the thread to the list of threads that have issued a sync request with this
 | 
					 | 
				
			||||||
            // server.
 | 
					 | 
				
			||||||
            pending_requesting_threads.push_back(std::move(thread));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // If this ServerSession does not have an HLE implementation, just wake up the threads waiting
 | 
					 | 
				
			||||||
    // on it.
 | 
					 | 
				
			||||||
    WakeupAllWaitingThreads();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the
 | 
					 | 
				
			||||||
    // end of the command such that only commands following this one are handled as domains
 | 
					 | 
				
			||||||
    if (convert_to_domain) {
 | 
					    if (convert_to_domain) {
 | 
				
			||||||
        ASSERT_MSG(IsSession(), "ServerSession is already a domain instance.");
 | 
					        ASSERT_MSG(IsSession(), "ServerSession is already a domain instance.");
 | 
				
			||||||
        domain_request_handlers = {hle_handler};
 | 
					        domain_request_handlers = {hle_handler};
 | 
				
			||||||
        convert_to_domain = false;
 | 
					        convert_to_domain = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Some service requests require the thread to block
 | 
				
			||||||
 | 
					    if (!context.IsThreadWaiting()) {
 | 
				
			||||||
 | 
					        context.GetThread().ResumeFromWait();
 | 
				
			||||||
 | 
					        context.GetThread().SetWaitSynchronizationResult(result);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    request_queue.Pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel,
 | 
					ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
 | 
				
			||||||
                                                            const std::string& name,
 | 
					                                            Memory::Memory& memory) {
 | 
				
			||||||
                                                            std::shared_ptr<ClientPort> port) {
 | 
					    Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {});
 | 
				
			||||||
    auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap();
 | 
					    return QueueSyncRequest(std::move(thread), memory);
 | 
				
			||||||
    std::shared_ptr<ClientSession> client_session = std::make_shared<ClientSession>(kernel);
 | 
					 | 
				
			||||||
    client_session->name = name + "_Client";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<Session> parent = std::make_shared<Session>();
 | 
					 | 
				
			||||||
    parent->client = client_session;
 | 
					 | 
				
			||||||
    parent->server = server_session;
 | 
					 | 
				
			||||||
    parent->port = std::move(port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    client_session->parent = parent;
 | 
					 | 
				
			||||||
    server_session->parent = parent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return std::make_pair(std::move(server_session), std::move(client_session));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Kernel
 | 
					} // namespace Kernel
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
// Copyright 2014 Citra Emulator Project
 | 
					// Copyright 2019 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,7 +9,7 @@
 | 
				
			|||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/hle/kernel/object.h"
 | 
					#include "common/threadsafe_queue.h"
 | 
				
			||||||
#include "core/hle/kernel/wait_object.h"
 | 
					#include "core/hle/kernel/wait_object.h"
 | 
				
			||||||
#include "core/hle/result.h"
 | 
					#include "core/hle/result.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,13 +17,14 @@ namespace Memory {
 | 
				
			|||||||
class Memory;
 | 
					class Memory;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Core::Timing {
 | 
				
			||||||
 | 
					struct EventType;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Kernel {
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClientPort;
 | 
					 | 
				
			||||||
class ClientSession;
 | 
					 | 
				
			||||||
class HLERequestContext;
 | 
					class HLERequestContext;
 | 
				
			||||||
class KernelCore;
 | 
					class KernelCore;
 | 
				
			||||||
class ServerSession;
 | 
					 | 
				
			||||||
class Session;
 | 
					class Session;
 | 
				
			||||||
class SessionRequestHandler;
 | 
					class SessionRequestHandler;
 | 
				
			||||||
class Thread;
 | 
					class Thread;
 | 
				
			||||||
@ -45,6 +46,12 @@ public:
 | 
				
			|||||||
    explicit ServerSession(KernelCore& kernel);
 | 
					    explicit ServerSession(KernelCore& kernel);
 | 
				
			||||||
    ~ServerSession() override;
 | 
					    ~ServerSession() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    friend class Session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel,
 | 
				
			||||||
 | 
					                                                            std::shared_ptr<Session> parent,
 | 
				
			||||||
 | 
					                                                            std::string name = "Unknown");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetTypeName() const override {
 | 
					    std::string GetTypeName() const override {
 | 
				
			||||||
        return "ServerSession";
 | 
					        return "ServerSession";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -66,18 +73,6 @@ public:
 | 
				
			|||||||
        return parent.get();
 | 
					        return parent.get();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using SessionPair = std::pair<std::shared_ptr<ServerSession>, std::shared_ptr<ClientSession>>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Creates a pair of ServerSession and an associated ClientSession.
 | 
					 | 
				
			||||||
     * @param kernel      The kernal instance to create the session pair under.
 | 
					 | 
				
			||||||
     * @param name        Optional name of the ports.
 | 
					 | 
				
			||||||
     * @param client_port Optional The ClientPort that spawned this session.
 | 
					 | 
				
			||||||
     * @return The created session tuple
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown",
 | 
					 | 
				
			||||||
                                         std::shared_ptr<ClientPort> client_port = nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Sets the HLE handler for the session. This handler will be called to service IPC requests
 | 
					     * Sets the HLE handler for the session. This handler will be called to service IPC requests
 | 
				
			||||||
     * instead of the regular IPC machinery. (The regular IPC machinery is currently not
 | 
					     * instead of the regular IPC machinery. (The regular IPC machinery is currently not
 | 
				
			||||||
@ -128,15 +123,11 @@ public:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    /**
 | 
					    /// Queues a sync request from the emulated application.
 | 
				
			||||||
     * Creates a server session. The server session can have an optional HLE handler,
 | 
					    ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory);
 | 
				
			||||||
     * which will be invoked to handle the IPC requests that this session receives.
 | 
					
 | 
				
			||||||
     * @param kernel The kernel instance to create this server session under.
 | 
					    /// Completes a sync request from the emulated application.
 | 
				
			||||||
     * @param name Optional name of the server session.
 | 
					    ResultCode CompleteSyncRequest();
 | 
				
			||||||
     * @return The created server session
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel,
 | 
					 | 
				
			||||||
                                                            std::string name = "Unknown");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
 | 
					    /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
 | 
				
			||||||
    /// object handle.
 | 
					    /// object handle.
 | 
				
			||||||
@ -166,6 +157,12 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// The name of this session (optional)
 | 
					    /// The name of this session (optional)
 | 
				
			||||||
    std::string name;
 | 
					    std::string name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Core timing event used to schedule the service request at some point in the future
 | 
				
			||||||
 | 
					    std::shared_ptr<Core::Timing::EventType> request_event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Queue of scheduled service requests
 | 
				
			||||||
 | 
					    Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Kernel
 | 
					} // namespace Kernel
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,36 @@
 | 
				
			|||||||
// Copyright 2015 Citra Emulator Project
 | 
					// Copyright 2019 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 "core/hle/kernel/client_session.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/server_session.h"
 | 
				
			||||||
#include "core/hle/kernel/session.h"
 | 
					#include "core/hle/kernel/session.h"
 | 
				
			||||||
#include "core/hle/kernel/thread.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Kernel {
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Session::Session() {}
 | 
					Session::Session(KernelCore& kernel) : WaitObject{kernel} {}
 | 
				
			||||||
Session::~Session() {}
 | 
					Session::~Session() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return std::make_pair(std::move(client_session), std::move(server_session));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Session::ShouldWait(const Thread* thread) const {
 | 
				
			||||||
 | 
					    UNIMPLEMENTED();
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Session::Acquire(Thread* thread) {
 | 
				
			||||||
 | 
					    UNIMPLEMENTED();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Kernel
 | 
					} // namespace Kernel
 | 
				
			||||||
 | 
				
			|||||||
@ -1,27 +1,64 @@
 | 
				
			|||||||
// Copyright 2018 yuzu emulator team
 | 
					// Copyright 2019 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/hle/kernel/object.h"
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/hle/kernel/wait_object.h"
 | 
				
			||||||
 | 
					#include "core/hle/result.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Kernel {
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClientSession;
 | 
					class ClientSession;
 | 
				
			||||||
class ClientPort;
 | 
					 | 
				
			||||||
class ServerSession;
 | 
					class ServerSession;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Parent structure to link the client and server endpoints of a session with their associated
 | 
					 * Parent structure to link the client and server endpoints of a session with their associated
 | 
				
			||||||
 * client port. The client port need not exist, as is the case for portless sessions like the
 | 
					 * client port.
 | 
				
			||||||
 * FS File and Directory sessions. When one of the endpoints of a session is destroyed, its
 | 
					 | 
				
			||||||
 * corresponding field in this structure will be set to nullptr.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class Session final {
 | 
					class Session final : public WaitObject {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    std::weak_ptr<ClientSession> client; ///< The client endpoint of the session.
 | 
					    explicit Session(KernelCore& kernel);
 | 
				
			||||||
    std::weak_ptr<ServerSession> server; ///< The server endpoint of the session.
 | 
					    ~Session() override;
 | 
				
			||||||
    std::shared_ptr<ClientPort> port; ///< The port that this session is associated with (optional).
 | 
					
 | 
				
			||||||
 | 
					    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 ShouldWait(const Thread* thread) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Acquire(Thread* thread) 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
 | 
					} // namespace Kernel
 | 
				
			||||||
 | 
				
			|||||||
@ -381,11 +381,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
 | 
					    LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    system.PrepareReschedule();
 | 
					    auto thread = system.CurrentScheduler().GetCurrentThread();
 | 
				
			||||||
 | 
					    thread->InvalidateWakeupCallback();
 | 
				
			||||||
 | 
					    thread->SetStatus(ThreadStatus::WaitIPC);
 | 
				
			||||||
 | 
					    system.PrepareReschedule(thread->GetProcessorID());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
 | 
					    return session->SendSyncRequest(SharedFrom(thread), system.Memory());
 | 
				
			||||||
    // responds and cause a reschedule.
 | 
					 | 
				
			||||||
    return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread(), system.Memory());
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Get the ID for the specified thread.
 | 
					/// Get the ID for the specified thread.
 | 
				
			||||||
 | 
				
			|||||||
@ -189,7 +189,7 @@ private:
 | 
				
			|||||||
        LOG_DEBUG(Service_NFP, "called");
 | 
					        LOG_DEBUG(Service_NFP, "called");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto nfc_event = nfp_interface.GetNFCEvent();
 | 
					        auto nfc_event = nfp_interface.GetNFCEvent();
 | 
				
			||||||
        if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
 | 
					        if (!nfc_event->ShouldWait(&ctx.GetThread()) && !has_attached_handle) {
 | 
				
			||||||
            device_state = DeviceState::TagFound;
 | 
					            device_state = DeviceState::TagFound;
 | 
				
			||||||
            nfc_event->Clear();
 | 
					            nfc_event->Clear();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -186,7 +186,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
 | 
				
			|||||||
        UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType()));
 | 
					        UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread());
 | 
					    context.WriteToOutgoingCommandBuffer(context.GetThread());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return RESULT_SUCCESS;
 | 
					    return RESULT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -201,7 +201,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
 | 
				
			|||||||
    auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system);
 | 
					    auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system);
 | 
				
			||||||
    system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
 | 
					    system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SM::ServiceManager::InstallInterfaces(sm);
 | 
					    SM::ServiceManager::InstallInterfaces(sm, system.Kernel());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Account::InstallInterfaces(system);
 | 
					    Account::InstallInterfaces(system);
 | 
				
			||||||
    AM::InstallInterfaces(*sm, nv_flinger, system);
 | 
					    AM::InstallInterfaces(*sm, nv_flinger, system);
 | 
				
			||||||
 | 
				
			|||||||
@ -30,10 +30,7 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
 | 
					    IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
 | 
				
			||||||
    rb.Push(RESULT_SUCCESS);
 | 
					    rb.Push(RESULT_SUCCESS);
 | 
				
			||||||
    std::shared_ptr<Kernel::ClientSession> session{ctx.Session()->GetParent()->client};
 | 
					    rb.PushMoveObjects(ctx.Session()->GetParent()->Client());
 | 
				
			||||||
    rb.PushMoveObjects(session);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LOG_DEBUG(Service, "session={}", session->GetObjectId());
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
 | 
					void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
 | 
				
			||||||
 | 
				
			|||||||
@ -36,10 +36,11 @@ static ResultCode ValidateServiceName(const std::string& name) {
 | 
				
			|||||||
    return RESULT_SUCCESS;
 | 
					    return RESULT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self) {
 | 
					void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self,
 | 
				
			||||||
 | 
					                                       Kernel::KernelCore& kernel) {
 | 
				
			||||||
    ASSERT(self->sm_interface.expired());
 | 
					    ASSERT(self->sm_interface.expired());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto sm = std::make_shared<SM>(self);
 | 
					    auto sm = std::make_shared<SM>(self, kernel);
 | 
				
			||||||
    sm->InstallAsNamedPort();
 | 
					    sm->InstallAsNamedPort();
 | 
				
			||||||
    self->sm_interface = sm;
 | 
					    self->sm_interface = sm;
 | 
				
			||||||
    self->controller_interface = std::make_unique<Controller>();
 | 
					    self->controller_interface = std::make_unique<Controller>();
 | 
				
			||||||
@ -114,8 +115,6 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::string name(name_buf.begin(), end);
 | 
					    std::string name(name_buf.begin(), end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO(yuriks): Permission checks go here
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto client_port = service_manager->GetServicePort(name);
 | 
					    auto client_port = service_manager->GetServicePort(name);
 | 
				
			||||||
    if (client_port.Failed()) {
 | 
					    if (client_port.Failed()) {
 | 
				
			||||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
					        IPC::ResponseBuilder rb{ctx, 2};
 | 
				
			||||||
@ -127,14 +126,22 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto session = client_port.Unwrap()->Connect();
 | 
					    auto [client, server] = Kernel::Session::Create(kernel, name);
 | 
				
			||||||
    ASSERT(session.Succeeded());
 | 
					
 | 
				
			||||||
    if (session.Succeeded()) {
 | 
					    const auto& server_port = client_port.Unwrap()->GetServerPort();
 | 
				
			||||||
        LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId());
 | 
					    if (server_port->GetHLEHandler()) {
 | 
				
			||||||
        IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
 | 
					        server_port->GetHLEHandler()->ClientConnected(server);
 | 
				
			||||||
        rb.Push(session.Code());
 | 
					    } else {
 | 
				
			||||||
        rb.PushMoveObjects(std::move(session).Unwrap());
 | 
					        server_port->AppendPendingSession(server);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Wake the threads waiting on the ServerPort
 | 
				
			||||||
 | 
					    server_port->WakeupAllWaitingThreads();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
 | 
				
			||||||
 | 
					    IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
 | 
				
			||||||
 | 
					    rb.Push(RESULT_SUCCESS);
 | 
				
			||||||
 | 
					    rb.PushMoveObjects(std::move(client));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SM::RegisterService(Kernel::HLERequestContext& ctx) {
 | 
					void SM::RegisterService(Kernel::HLERequestContext& ctx) {
 | 
				
			||||||
@ -178,8 +185,8 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
 | 
				
			|||||||
    rb.Push(service_manager->UnregisterService(name));
 | 
					    rb.Push(service_manager->UnregisterService(name));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SM::SM(std::shared_ptr<ServiceManager> service_manager)
 | 
					SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel)
 | 
				
			||||||
    : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
 | 
					    : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} {
 | 
				
			||||||
    static const FunctionInfo functions[] = {
 | 
					    static const FunctionInfo functions[] = {
 | 
				
			||||||
        {0x00000000, &SM::Initialize, "Initialize"},
 | 
					        {0x00000000, &SM::Initialize, "Initialize"},
 | 
				
			||||||
        {0x00000001, &SM::GetService, "GetService"},
 | 
					        {0x00000001, &SM::GetService, "GetService"},
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@
 | 
				
			|||||||
namespace Kernel {
 | 
					namespace Kernel {
 | 
				
			||||||
class ClientPort;
 | 
					class ClientPort;
 | 
				
			||||||
class ClientSession;
 | 
					class ClientSession;
 | 
				
			||||||
 | 
					class KernelCore;
 | 
				
			||||||
class ServerPort;
 | 
					class ServerPort;
 | 
				
			||||||
class SessionRequestHandler;
 | 
					class SessionRequestHandler;
 | 
				
			||||||
} // namespace Kernel
 | 
					} // namespace Kernel
 | 
				
			||||||
@ -29,7 +30,7 @@ class Controller;
 | 
				
			|||||||
/// Interface to "sm:" service
 | 
					/// Interface to "sm:" service
 | 
				
			||||||
class SM final : public ServiceFramework<SM> {
 | 
					class SM final : public ServiceFramework<SM> {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    explicit SM(std::shared_ptr<ServiceManager> service_manager);
 | 
					    explicit SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel);
 | 
				
			||||||
    ~SM() override;
 | 
					    ~SM() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
@ -39,11 +40,12 @@ private:
 | 
				
			|||||||
    void UnregisterService(Kernel::HLERequestContext& ctx);
 | 
					    void UnregisterService(Kernel::HLERequestContext& ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::shared_ptr<ServiceManager> service_manager;
 | 
					    std::shared_ptr<ServiceManager> service_manager;
 | 
				
			||||||
 | 
					    Kernel::KernelCore& kernel;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ServiceManager {
 | 
					class ServiceManager {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    static void InstallInterfaces(std::shared_ptr<ServiceManager> self);
 | 
					    static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ServiceManager();
 | 
					    ServiceManager();
 | 
				
			||||||
    ~ServiceManager();
 | 
					    ~ServiceManager();
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user