summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp15
-rw-r--r--src/core/hle/kernel/hle_ipc.h9
-rw-r--r--src/core/hle/kernel/k_server_session.cpp42
-rw-r--r--src/core/hle/kernel/kernel.cpp18
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
42SessionRequestManager::~SessionRequestManager() = default; 42SessionRequestManager::~SessionRequestManager() = default;
43 43
44bool 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
44void SessionRequestHandler::ClientConnected(KServerSession* session) { 59void 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
92protected: 92protected:
@@ -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
159private: 161private:
160 bool is_domain{}; 162 bool is_domain{};
161 SessionRequestHandlerPtr session_handler; 163 SessionRequestHandlerPtr session_handler;
@@ -163,7 +165,6 @@ private:
163 165
164private: 166private:
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
132ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { 147ResultCode 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
987std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { 980std::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
994void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { 986void 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
1002Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { 992Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {