Merge pull request #3177 from bunnei/new-ipc-req

kernel: Implement a more accurate IPC dispatch.
master
bunnei 2019-11-30 18:56:35 +07:00 committed by GitHub
commit 5c7253f8d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 246 additions and 167 deletions

@ -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();