diff options
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 15 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 9 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 42 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 18 |
4 files changed, 56 insertions, 28 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 260af87e5..45aced99f 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -41,6 +41,21 @@ SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kerne | |||
| 41 | 41 | ||
| 42 | SessionRequestManager::~SessionRequestManager() = default; | 42 | SessionRequestManager::~SessionRequestManager() = default; |
| 43 | 43 | ||
| 44 | bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& context) const { | ||
| 45 | if (IsDomain() && context.HasDomainMessageHeader()) { | ||
| 46 | const auto& message_header = context.GetDomainMessageHeader(); | ||
| 47 | const auto object_id = message_header.object_id; | ||
| 48 | |||
| 49 | if (object_id > DomainHandlerCount()) { | ||
| 50 | LOG_CRITICAL(IPC, "object_id {} is too big!", object_id); | ||
| 51 | return false; | ||
| 52 | } | ||
| 53 | return DomainHandler(object_id - 1) != nullptr; | ||
| 54 | } else { | ||
| 55 | return session_handler != nullptr; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 44 | void SessionRequestHandler::ClientConnected(KServerSession* session) { | 59 | void SessionRequestHandler::ClientConnected(KServerSession* session) { |
| 45 | session->SetSessionHandler(shared_from_this()); | 60 | session->SetSessionHandler(shared_from_this()); |
| 46 | } | 61 | } |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 2aaf93fca..a61870f8b 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -85,8 +85,8 @@ public: | |||
| 85 | */ | 85 | */ |
| 86 | void ClientDisconnected(KServerSession* session); | 86 | void ClientDisconnected(KServerSession* session); |
| 87 | 87 | ||
| 88 | std::shared_ptr<ServiceThread> GetServiceThread() const { | 88 | std::weak_ptr<ServiceThread> GetServiceThread() const { |
| 89 | return service_thread.lock(); | 89 | return service_thread; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | protected: | 92 | protected: |
| @@ -152,10 +152,12 @@ public: | |||
| 152 | session_handler = std::move(handler); | 152 | session_handler = std::move(handler); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | std::shared_ptr<ServiceThread> GetServiceThread() const { | 155 | std::weak_ptr<ServiceThread> GetServiceThread() const { |
| 156 | return session_handler->GetServiceThread(); | 156 | return session_handler->GetServiceThread(); |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | bool HasSessionRequestHandler(const HLERequestContext& context) const; | ||
| 160 | |||
| 159 | private: | 161 | private: |
| 160 | bool is_domain{}; | 162 | bool is_domain{}; |
| 161 | SessionRequestHandlerPtr session_handler; | 163 | SessionRequestHandlerPtr session_handler; |
| @@ -163,7 +165,6 @@ private: | |||
| 163 | 165 | ||
| 164 | private: | 166 | private: |
| 165 | KernelCore& kernel; | 167 | KernelCore& kernel; |
| 166 | std::weak_ptr<ServiceThread> service_thread; | ||
| 167 | }; | 168 | }; |
| 168 | 169 | ||
| 169 | /** | 170 | /** |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 528ca8614..5c3c13ce6 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/scope_exit.h" | ||
| 11 | #include "core/core_timing.h" | 12 | #include "core/core_timing.h" |
| 12 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/hle_ipc.h" | 14 | #include "core/hle/kernel/hle_ipc.h" |
| @@ -119,11 +120,25 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor | |||
| 119 | 120 | ||
| 120 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | 121 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); |
| 121 | 122 | ||
| 122 | if (auto strong_ptr = manager->GetServiceThread(); strong_ptr) { | 123 | // In the event that something fails here, stub a result to prevent the game from crashing. |
| 123 | strong_ptr->QueueSyncRequest(*parent, std::move(context)); | 124 | // This is a work-around in the event that somehow we process a service request after the |
| 124 | return ResultSuccess; | 125 | // session has been closed by the game. This has been observed to happen rarely in Pokemon |
| 126 | // Sword/Shield and is likely a result of us using host threads/scheduling for services. | ||
| 127 | // TODO(bunnei): Find a better solution here. | ||
| 128 | auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); }); | ||
| 129 | |||
| 130 | // Ensure we have a session request handler | ||
| 131 | if (manager->HasSessionRequestHandler(*context)) { | ||
| 132 | if (auto strong_ptr = manager->GetServiceThread().lock()) { | ||
| 133 | strong_ptr->QueueSyncRequest(*parent, std::move(context)); | ||
| 134 | |||
| 135 | // We succeeded. | ||
| 136 | error_guard.Cancel(); | ||
| 137 | } else { | ||
| 138 | ASSERT_MSG(false, "strong_ptr is nullptr!"); | ||
| 139 | } | ||
| 125 | } else { | 140 | } else { |
| 126 | ASSERT_MSG(false, "strong_ptr was nullptr!"); | 141 | ASSERT_MSG(false, "handler is invalid!"); |
| 127 | } | 142 | } |
| 128 | 143 | ||
| 129 | return ResultSuccess; | 144 | return ResultSuccess; |
| @@ -131,13 +146,20 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor | |||
| 131 | 146 | ||
| 132 | ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { | 147 | ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { |
| 133 | ResultCode result = ResultSuccess; | 148 | ResultCode result = ResultSuccess; |
| 149 | |||
| 134 | // If the session has been converted to a domain, handle the domain request | 150 | // If the session has been converted to a domain, handle the domain request |
| 135 | if (IsDomain() && context.HasDomainMessageHeader()) { | 151 | if (manager->HasSessionRequestHandler(context)) { |
| 136 | result = HandleDomainSyncRequest(context); | 152 | if (IsDomain() && context.HasDomainMessageHeader()) { |
| 137 | // If there is no domain header, the regular session handler is used | 153 | result = HandleDomainSyncRequest(context); |
| 138 | } else if (manager->HasSessionHandler()) { | 154 | // If there is no domain header, the regular session handler is used |
| 139 | // If this ServerSession has an associated HLE handler, forward the request to it. | 155 | } else if (manager->HasSessionHandler()) { |
| 140 | result = manager->SessionHandler().HandleSyncRequest(*this, context); | 156 | // If this ServerSession has an associated HLE handler, forward the request to it. |
| 157 | result = manager->SessionHandler().HandleSyncRequest(*this, context); | ||
| 158 | } | ||
| 159 | } else { | ||
| 160 | ASSERT_MSG(false, "Session handler is invalid, stubbing response!"); | ||
| 161 | IPC::ResponseBuilder rb(context, 2); | ||
| 162 | rb.Push(ResultSuccess); | ||
| 141 | } | 163 | } |
| 142 | 164 | ||
| 143 | if (convert_to_domain) { | 165 | if (convert_to_domain) { |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0ffb78d51..2ceeaeb5f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -63,8 +63,6 @@ struct KernelCore::Impl { | |||
| 63 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | 63 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); |
| 64 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); | 64 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); |
| 65 | 65 | ||
| 66 | service_thread_manager = | ||
| 67 | std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager"); | ||
| 68 | is_phantom_mode_for_singlecore = false; | 66 | is_phantom_mode_for_singlecore = false; |
| 69 | 67 | ||
| 70 | InitializePhysicalCores(); | 68 | InitializePhysicalCores(); |
| @@ -96,7 +94,6 @@ struct KernelCore::Impl { | |||
| 96 | process_list.clear(); | 94 | process_list.clear(); |
| 97 | 95 | ||
| 98 | // Ensures all service threads gracefully shutdown | 96 | // Ensures all service threads gracefully shutdown |
| 99 | service_thread_manager.reset(); | ||
| 100 | service_threads.clear(); | 97 | service_threads.clear(); |
| 101 | 98 | ||
| 102 | next_object_id = 0; | 99 | next_object_id = 0; |
| @@ -680,10 +677,6 @@ struct KernelCore::Impl { | |||
| 680 | // Threads used for services | 677 | // Threads used for services |
| 681 | std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; | 678 | std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; |
| 682 | 679 | ||
| 683 | // Service threads are managed by a worker thread, so that a calling service thread can queue up | ||
| 684 | // the release of itself | ||
| 685 | std::unique_ptr<Common::ThreadWorker> service_thread_manager; | ||
| 686 | |||
| 687 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; | 680 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; |
| 688 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | 681 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; |
| 689 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 682 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| @@ -986,17 +979,14 @@ void KernelCore::ExitSVCProfile() { | |||
| 986 | 979 | ||
| 987 | std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { | 980 | std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { |
| 988 | auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name); | 981 | auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name); |
| 989 | impl->service_thread_manager->QueueWork( | 982 | impl->service_threads.emplace(service_thread); |
| 990 | [this, service_thread] { impl->service_threads.emplace(service_thread); }); | ||
| 991 | return service_thread; | 983 | return service_thread; |
| 992 | } | 984 | } |
| 993 | 985 | ||
| 994 | void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { | 986 | void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { |
| 995 | impl->service_thread_manager->QueueWork([this, service_thread] { | 987 | if (auto strong_ptr = service_thread.lock()) { |
| 996 | if (auto strong_ptr = service_thread.lock()) { | 988 | impl->service_threads.erase(strong_ptr); |
| 997 | impl->service_threads.erase(strong_ptr); | 989 | } |
| 998 | } | ||
| 999 | }); | ||
| 1000 | } | 990 | } |
| 1001 | 991 | ||
| 1002 | Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { | 992 | Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { |