diff options
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_port.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_session.cpp | 40 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_session.h | 21 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/object.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/object.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.cpp | 117 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h | 49 | ||||
| -rw-r--r-- | src/core/hle/kernel/session.cpp | 32 | ||||
| -rw-r--r-- | src/core/hle/kernel/session.h | 57 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/sm/controller.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 33 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.h | 6 | 
18 files changed, 245 insertions, 167 deletions
| diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index b9f9ae1fa..0dc6a4a43 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -19,6 +19,7 @@  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/kernel/object.h"  #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/session.h"  #include "core/hle/result.h"  namespace IPC { @@ -139,10 +140,9 @@ public:              context->AddDomainObject(std::move(iface));          } else {              auto& kernel = Core::System::GetInstance().Kernel(); -            auto [server, client] = -                Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName()); -            iface->ClientConnected(server); +            auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());              context->AddMoveObject(std::move(client)); +            iface->ClientConnected(std::move(server));          }      } diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 4637b6017..00bb939a0 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -9,6 +9,7 @@  #include "core/hle/kernel/object.h"  #include "core/hle/kernel/server_port.h"  #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/session.h"  namespace Kernel { @@ -20,28 +21,23 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {  }  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) {          return ERR_MAX_CONNECTIONS_REACHED;      }      active_sessions++; -    // Create a new session pair, let the created sessions inherit the parent port's HLE handler. -    auto [server, client] = -        ServerSession::CreateSessionPair(kernel, server_port->GetName(), SharedFrom(this)); +    auto [client, server] = Kernel::Session::Create(kernel, name);      if (server_port->HasHLEHandler()) { -        server_port->GetHLEHandler()->ClientConnected(server); +        server_port->GetHLEHandler()->ClientConnected(std::move(server));      } else { -        server_port->AppendPendingSession(server); +        server_port->AppendPendingSession(std::move(server));      }      // Wake the threads waiting on the ServerPort      server_port->WakeupAllWaitingThreads(); -    return MakeResult(client); +    return MakeResult(std::move(client));  }  void ClientPort::ConnectionClosed() { diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 9849dbe91..4669a14ad 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -12,22 +12,44 @@  namespace Kernel { -ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {} +ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} +  ClientSession::~ClientSession() {      // This destructor will be called automatically when the last ClientSession handle is closed by      // the emulated application. -    if (auto server = parent->server.lock()) { -        server->ClientDisconnected(); +    if (parent->Server()) { +        parent->Server()->ClientDisconnected();      }  } -ResultCode ClientSession::SendSyncRequest(Thread* thread, Memory::Memory& memory) { -    // Signal the server session that new data is available -    if (auto server = parent->server.lock()) { -        return server->HandleSyncRequest(SharedFrom(thread), memory); +bool ClientSession::ShouldWait(const Thread* thread) const { +    UNIMPLEMENTED(); +    return {}; +} + +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 diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 484dd7bc9..b4289a9a8 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -6,7 +6,9 @@  #include <memory>  #include <string> -#include "core/hle/kernel/object.h" + +#include "core/hle/kernel/wait_object.h" +#include "core/hle/result.h"  union ResultCode; @@ -18,15 +20,14 @@ namespace Kernel {  class KernelCore;  class Session; -class ServerSession;  class Thread; -class ClientSession final : public Object { +class ClientSession final : public WaitObject {  public:      explicit ClientSession(KernelCore& kernel);      ~ClientSession() override; -    friend class ServerSession; +    friend class Session;      std::string GetTypeName() const override {          return "ClientSession"; @@ -41,9 +42,17 @@ public:          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: +    static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, +                                                            std::shared_ptr<Session> parent, +                                                            std::string name = "Unknown"); +      /// The parent session, which links to the server endpoint.      std::shared_ptr<Session> parent; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 8b01567a8..2db28dcf0 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -74,6 +74,8 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(          thread->WakeAfterDelay(timeout);      } +    is_thread_waiting = true; +      return writable_event;  } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index dab37ba0d..050ad8fd7 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -264,6 +264,18 @@ public:      std::string Description() const; +    Thread& GetThread() { +        return *thread; +    } + +    const Thread& GetThread() const { +        return *thread; +    } + +    bool IsThreadWaiting() const { +        return is_thread_waiting; +    } +  private:      void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); @@ -290,6 +302,7 @@ private:      u32_le command{};      std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; +    bool is_thread_waiting{};  };  } // namespace Kernel diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 10431e94c..2c571792b 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -27,6 +27,7 @@ bool Object::IsWaitable() const {      case HandleType::ResourceLimit:      case HandleType::ClientPort:      case HandleType::ClientSession: +    case HandleType::Session:          return false;      } diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index bbbb4e7cc..e3391e2af 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -29,6 +29,7 @@ enum class HandleType : u32 {      ServerPort,      ClientSession,      ServerSession, +    Session,  };  class Object : NonCopyable, public std::enable_shared_from_this<Object> { diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 1198c7a97..7825e1ec4 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -9,6 +9,7 @@  #include "common/common_types.h"  #include "common/logging/log.h"  #include "core/core.h" +#include "core/core_timing.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h" @@ -24,34 +25,29 @@  namespace Kernel {  ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} -ServerSession::~ServerSession() { -    // 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(); -    } -} +ServerSession::~ServerSession() = default;  ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, +                                                                std::shared_ptr<Session> parent,                                                                  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); -    server_session->parent = nullptr; +    session->request_event = Core::Timing::CreateEvent( +        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 { -    // Wait if we have no pending requests, or if we're currently handling a request. -    if (auto client = parent->client.lock()) { -        return pending_requesting_threads.empty() || currently_handling != nullptr; +    // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. +    if (!parent->Client()) { +        return false;      } -    // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. -    return {}; +    // Wait if we have no pending requests, or if we're currently handling a request. +    return pending_requesting_threads.empty() || currently_handling != nullptr;  }  void ServerSession::Acquire(Thread* thread) { @@ -128,14 +124,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con      return RESULT_SUCCESS;  } -ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, -                                            Memory::Memory& memory) { -    // The ServerSession received a sync request, this means that there's new data available -    // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or -    // similar. -    Kernel::HLERequestContext context(SharedFrom(this), thread); -    u32* cmd_buf = (u32*)memory.GetPointer(thread->GetTLSAddress()); -    context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); +ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { +    u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; +    std::shared_ptr<Kernel::HLERequestContext> context{ +        std::make_shared<Kernel::HLERequestContext>(SharedFrom(this), std::move(thread))}; + +    context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); +    request_queue.Push(std::move(context)); + +    return RESULT_SUCCESS; +} + +ResultCode ServerSession::CompleteSyncRequest() { +    ASSERT(!request_queue.Empty()); + +    auto& context = *request_queue.Front();      ResultCode result = RESULT_SUCCESS;      // 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);      } -    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) {          ASSERT_MSG(IsSession(), "ServerSession is already a domain instance.");          domain_request_handlers = {hle_handler};          convert_to_domain = false;      } -    return result; -} - -ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel, -                                                            const std::string& name, -                                                            std::shared_ptr<ClientPort> port) { -    auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap(); -    std::shared_ptr<ClientSession> client_session = std::make_shared<ClientSession>(kernel); -    client_session->name = name + "_Client"; +    // Some service requests require the thread to block +    if (!context.IsThreadWaiting()) { +        context.GetThread().ResumeFromWait(); +        context.GetThread().SetWaitSynchronizationResult(result); +    } -    std::shared_ptr<Session> parent = std::make_shared<Session>(); -    parent->client = client_session; -    parent->server = server_session; -    parent->port = std::move(port); +    request_queue.Pop(); -    client_session->parent = parent; -    server_session->parent = parent; +    return result; +} -    return std::make_pair(std::move(server_session), std::move(client_session)); +ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, +                                            Memory::Memory& memory) { +    Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {}); +    return QueueSyncRequest(std::move(thread), memory);  } +  } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 641709a45..d6e48109e 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2019 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -9,7 +9,7 @@  #include <utility>  #include <vector> -#include "core/hle/kernel/object.h" +#include "common/threadsafe_queue.h"  #include "core/hle/kernel/wait_object.h"  #include "core/hle/result.h" @@ -17,13 +17,14 @@ namespace Memory {  class Memory;  } +namespace Core::Timing { +struct EventType; +} +  namespace Kernel { -class ClientPort; -class ClientSession;  class HLERequestContext;  class KernelCore; -class ServerSession;  class Session;  class SessionRequestHandler;  class Thread; @@ -45,6 +46,12 @@ public:      explicit ServerSession(KernelCore& kernel);      ~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 {          return "ServerSession";      } @@ -66,18 +73,6 @@ public:          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       * instead of the regular IPC machinery. (The regular IPC machinery is currently not @@ -128,15 +123,11 @@ public:      }  private: -    /** -     * Creates a server session. The server session can have an optional HLE handler, -     * which will be invoked to handle the IPC requests that this session receives. -     * @param kernel The kernel instance to create this server session under. -     * @param name Optional name of the server session. -     * @return The created server session -     */ -    static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, -                                                            std::string name = "Unknown"); +    /// Queues a sync request from the emulated application. +    ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); + +    /// Completes a sync request from the emulated application. +    ResultCode CompleteSyncRequest();      /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an      /// object handle. @@ -166,6 +157,12 @@ private:      /// The name of this session (optional)      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 diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 642914744..dee6e2b72 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp @@ -1,12 +1,36 @@ -// Copyright 2015 Citra Emulator Project +// Copyright 2019 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include "common/assert.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h"  #include "core/hle/kernel/session.h" -#include "core/hle/kernel/thread.h"  namespace Kernel { -Session::Session() {} -Session::~Session() {} +Session::Session(KernelCore& kernel) : WaitObject{kernel} {} +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 diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 94395f9f5..5a9d4e9ad 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -1,27 +1,64 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2019 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included.  #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 {  class ClientSession; -class ClientPort;  class ServerSession;  /**   * 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 - * 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. + * client port.   */ -class Session final { +class Session final : public WaitObject {  public: -    std::weak_ptr<ClientSession> client; ///< The client endpoint of the session. -    std::weak_ptr<ServerSession> server; ///< The server endpoint of the session. -    std::shared_ptr<ClientPort> port; ///< The port that this session is associated with (optional). +    explicit Session(KernelCore& kernel); +    ~Session() override; + +    using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>; + +    static SessionPair Create(KernelCore& kernel, std::string name = "Unknown"); + +    std::string GetName() const override { +        return name; +    } + +    static constexpr HandleType HANDLE_TYPE = HandleType::Session; +    HandleType GetHandleType() const override { +        return HANDLE_TYPE; +    } + +    bool 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 diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index db3ae3eb8..bd25de478 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -381,11 +381,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {      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 -    // responds and cause a reschedule. -    return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread(), system.Memory()); +    return session->SendSyncRequest(SharedFrom(thread), system.Memory());  }  /// Get the ID for the specified thread. diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index ec0367978..4b79eb81d 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -189,7 +189,7 @@ private:          LOG_DEBUG(Service_NFP, "called");          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;              nfc_event->Clear();          } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5698f429f..fa5347af9 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -186,7 +186,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co          UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType()));      } -    context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread()); +    context.WriteToOutgoingCommandBuffer(context.GetThread());      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);      system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); -    SM::ServiceManager::InstallInterfaces(sm); +    SM::ServiceManager::InstallInterfaces(sm, system.Kernel());      Account::InstallInterfaces(system);      AM::InstallInterfaces(*sm, nv_flinger, system); diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index af2fadcef..c45b285f8 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -30,10 +30,7 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};      rb.Push(RESULT_SUCCESS); -    std::shared_ptr<Kernel::ClientSession> session{ctx.Session()->GetParent()->client}; -    rb.PushMoveObjects(session); - -    LOG_DEBUG(Service, "session={}", session->GetObjectId()); +    rb.PushMoveObjects(ctx.Session()->GetParent()->Client());  }  void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index a0a7206bb..88909504d 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -36,10 +36,11 @@ static ResultCode ValidateServiceName(const std::string& name) {      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()); -    auto sm = std::make_shared<SM>(self); +    auto sm = std::make_shared<SM>(self, kernel);      sm->InstallAsNamedPort();      self->sm_interface = sm;      self->controller_interface = std::make_unique<Controller>(); @@ -114,8 +115,6 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {      std::string name(name_buf.begin(), end); -    // TODO(yuriks): Permission checks go here -      auto client_port = service_manager->GetServicePort(name);      if (client_port.Failed()) {          IPC::ResponseBuilder rb{ctx, 2}; @@ -127,14 +126,22 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {          return;      } -    auto session = client_port.Unwrap()->Connect(); -    ASSERT(session.Succeeded()); -    if (session.Succeeded()) { -        LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); -        IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; -        rb.Push(session.Code()); -        rb.PushMoveObjects(std::move(session).Unwrap()); +    auto [client, server] = Kernel::Session::Create(kernel, name); + +    const auto& server_port = client_port.Unwrap()->GetServerPort(); +    if (server_port->GetHLEHandler()) { +        server_port->GetHLEHandler()->ClientConnected(server); +    } else { +        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) { @@ -178,8 +185,8 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {      rb.Push(service_manager->UnregisterService(name));  } -SM::SM(std::shared_ptr<ServiceManager> service_manager) -    : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { +SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel) +    : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} {      static const FunctionInfo functions[] = {          {0x00000000, &SM::Initialize, "Initialize"},          {0x00000001, &SM::GetService, "GetService"}, diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 3de22268b..b06d2f103 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -18,6 +18,7 @@  namespace Kernel {  class ClientPort;  class ClientSession; +class KernelCore;  class ServerPort;  class SessionRequestHandler;  } // namespace Kernel @@ -29,7 +30,7 @@ class Controller;  /// Interface to "sm:" service  class SM final : public ServiceFramework<SM> {  public: -    explicit SM(std::shared_ptr<ServiceManager> service_manager); +    explicit SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel);      ~SM() override;  private: @@ -39,11 +40,12 @@ private:      void UnregisterService(Kernel::HLERequestContext& ctx);      std::shared_ptr<ServiceManager> service_manager; +    Kernel::KernelCore& kernel;  };  class ServiceManager {  public: -    static void InstallInterfaces(std::shared_ptr<ServiceManager> self); +    static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel);      ServiceManager();      ~ServiceManager(); | 
