summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt13
-rw-r--r--src/core/hle/service/am/applet.h2
-rw-r--r--src/core/hle/service/am/applet_data_broker.h2
-rw-r--r--src/core/hle/service/glue/time/worker.cpp130
-rw-r--r--src/core/hle/service/os/event.cpp (renamed from src/core/hle/service/event.cpp)2
-rw-r--r--src/core/hle/service/os/event.h (renamed from src/core/hle/service/event.h)0
-rw-r--r--src/core/hle/service/os/multi_wait.cpp59
-rw-r--r--src/core/hle/service/os/multi_wait.h36
-rw-r--r--src/core/hle/service/os/multi_wait_holder.cpp25
-rw-r--r--src/core/hle/service/os/multi_wait_holder.h44
-rw-r--r--src/core/hle/service/os/multi_wait_utils.h109
-rw-r--r--src/core/hle/service/os/mutex.cpp (renamed from src/core/hle/service/mutex.cpp)2
-rw-r--r--src/core/hle/service/os/mutex.h (renamed from src/core/hle/service/mutex.h)0
-rw-r--r--src/core/hle/service/server_manager.cpp438
-rw-r--r--src/core/hle/service/server_manager.h59
15 files changed, 569 insertions, 352 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index eb8f643a2..1b44148f4 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -548,8 +548,6 @@ add_library(core STATIC
548 hle/service/es/es.h 548 hle/service/es/es.h
549 hle/service/eupld/eupld.cpp 549 hle/service/eupld/eupld.cpp
550 hle/service/eupld/eupld.h 550 hle/service/eupld/eupld.h
551 hle/service/event.cpp
552 hle/service/event.h
553 hle/service/fatal/fatal.cpp 551 hle/service/fatal/fatal.cpp
554 hle/service/fatal/fatal.h 552 hle/service/fatal/fatal.h
555 hle/service/fatal/fatal_p.cpp 553 hle/service/fatal/fatal_p.cpp
@@ -676,8 +674,6 @@ add_library(core STATIC
676 hle/service/mm/mm_u.h 674 hle/service/mm/mm_u.h
677 hle/service/mnpp/mnpp_app.cpp 675 hle/service/mnpp/mnpp_app.cpp
678 hle/service/mnpp/mnpp_app.h 676 hle/service/mnpp/mnpp_app.h
679 hle/service/mutex.cpp
680 hle/service/mutex.h
681 hle/service/ncm/ncm.cpp 677 hle/service/ncm/ncm.cpp
682 hle/service/ncm/ncm.h 678 hle/service/ncm/ncm.h
683 hle/service/nfc/common/amiibo_crypto.cpp 679 hle/service/nfc/common/amiibo_crypto.cpp
@@ -790,6 +786,15 @@ add_library(core STATIC
790 hle/service/nvnflinger/window.h 786 hle/service/nvnflinger/window.h
791 hle/service/olsc/olsc.cpp 787 hle/service/olsc/olsc.cpp
792 hle/service/olsc/olsc.h 788 hle/service/olsc/olsc.h
789 hle/service/os/event.cpp
790 hle/service/os/event.h
791 hle/service/os/multi_wait_holder.cpp
792 hle/service/os/multi_wait_holder.h
793 hle/service/os/multi_wait_utils.h
794 hle/service/os/multi_wait.cpp
795 hle/service/os/multi_wait.h
796 hle/service/os/mutex.cpp
797 hle/service/os/mutex.h
793 hle/service/pcie/pcie.cpp 798 hle/service/pcie/pcie.cpp
794 hle/service/pcie/pcie.h 799 hle/service/pcie/pcie.h
795 hle/service/pctl/pctl.cpp 800 hle/service/pctl/pctl.cpp
diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h
index bce6f9050..b29ecdfed 100644
--- a/src/core/hle/service/am/applet.h
+++ b/src/core/hle/service/am/applet.h
@@ -9,8 +9,8 @@
9#include "common/math_util.h" 9#include "common/math_util.h"
10#include "core/hle/service/apm/apm_controller.h" 10#include "core/hle/service/apm/apm_controller.h"
11#include "core/hle/service/caps/caps_types.h" 11#include "core/hle/service/caps/caps_types.h"
12#include "core/hle/service/event.h"
13#include "core/hle/service/kernel_helpers.h" 12#include "core/hle/service/kernel_helpers.h"
13#include "core/hle/service/os/event.h"
14#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
15 15
16#include "core/hle/service/am/am_types.h" 16#include "core/hle/service/am/am_types.h"
diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h
index 12326fd04..5a1d43c11 100644
--- a/src/core/hle/service/am/applet_data_broker.h
+++ b/src/core/hle/service/am/applet_data_broker.h
@@ -7,8 +7,8 @@
7#include <memory> 7#include <memory>
8#include <mutex> 8#include <mutex>
9 9
10#include "core/hle/service/event.h"
11#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/os/event.h"
12 12
13union Result; 13union Result;
14 14
diff --git a/src/core/hle/service/glue/time/worker.cpp b/src/core/hle/service/glue/time/worker.cpp
index f44f3077e..8787f2dcd 100644
--- a/src/core/hle/service/glue/time/worker.cpp
+++ b/src/core/hle/service/glue/time/worker.cpp
@@ -7,6 +7,7 @@
7#include "core/hle/service/glue/time/file_timestamp_worker.h" 7#include "core/hle/service/glue/time/file_timestamp_worker.h"
8#include "core/hle/service/glue/time/standard_steady_clock_resource.h" 8#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
9#include "core/hle/service/glue/time/worker.h" 9#include "core/hle/service/glue/time/worker.h"
10#include "core/hle/service/os/multi_wait_utils.h"
10#include "core/hle/service/psc/time/common.h" 11#include "core/hle/service/psc/time/common.h"
11#include "core/hle/service/psc/time/service_manager.h" 12#include "core/hle/service/psc/time/service_manager.h"
12#include "core/hle/service/psc/time/static.h" 13#include "core/hle/service/psc/time/static.h"
@@ -143,82 +144,46 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
143 Common::SetCurrentThreadName("TimeWorker"); 144 Common::SetCurrentThreadName("TimeWorker");
144 Common::SetCurrentThreadPriority(Common::ThreadPriority::Low); 145 Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
145 146
146 enum class EventType {
147 Exit = 0,
148 IpmModuleService_GetEvent = 1,
149 PowerStateChange = 2,
150 SignalAlarms = 3,
151 UpdateLocalSystemClock = 4,
152 UpdateNetworkSystemClock = 5,
153 UpdateEphemeralSystemClock = 6,
154 UpdateSteadyClock = 7,
155 UpdateFileTimestamp = 8,
156 AutoCorrect = 9,
157 Max = 10,
158 };
159
160 s32 num_objs{};
161 std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{};
162 std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{};
163
164 const auto AddWaiter{
165 [&](Kernel::KSynchronizationObject* synchronization_object, EventType type) {
166 // Open a new reference to the object.
167 synchronization_object->Open();
168
169 // Insert into the list.
170 wait_indices[num_objs] = type;
171 wait_objs[num_objs++] = synchronization_object;
172 }};
173
174 while (!stop_token.stop_requested()) { 147 while (!stop_token.stop_requested()) {
175 SCOPE_EXIT({ 148 enum class EventType : s32 {
176 for (s32 i = 0; i < num_objs; i++) { 149 Exit = 0,
177 wait_objs[i]->Close(); 150 PowerStateChange = 1,
178 } 151 SignalAlarms = 2,
179 }); 152 UpdateLocalSystemClock = 3,
153 UpdateNetworkSystemClock = 4,
154 UpdateEphemeralSystemClock = 5,
155 UpdateSteadyClock = 6,
156 UpdateFileTimestamp = 7,
157 AutoCorrect = 8,
158 };
159
160 s32 index{};
180 161
181 num_objs = {};
182 wait_objs = {};
183 if (m_pm_state_change_handler.m_priority != 0) { 162 if (m_pm_state_change_handler.m_priority != 0) {
184 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); 163 // TODO: gIPmModuleService::GetEvent() 1
185 // TODO 164 index = WaitAny(m_system.Kernel(),
186 // AddWaiter(gIPmModuleService::GetEvent(), 1); 165 &m_event->GetReadableEvent(), // 0
187 AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange); 166 &m_alarm_worker.GetEvent() // 1
167 );
188 } else { 168 } else {
189 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); 169 // TODO: gIPmModuleService::GetEvent() 1
190 // TODO 170 index = WaitAny(m_system.Kernel(),
191 // AddWaiter(gIPmModuleService::GetEvent(), 1); 171 &m_event->GetReadableEvent(), // 0
192 AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange); 172 &m_alarm_worker.GetEvent(), // 1
193 AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms); 173 &m_alarm_worker.GetTimerEvent().GetReadableEvent(), // 2
194 AddWaiter(m_local_clock_event, EventType::UpdateLocalSystemClock); 174 m_local_clock_event, // 3
195 AddWaiter(m_network_clock_event, EventType::UpdateNetworkSystemClock); 175 m_network_clock_event, // 4
196 AddWaiter(m_ephemeral_clock_event, EventType::UpdateEphemeralSystemClock); 176 m_ephemeral_clock_event, // 5
197 AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock); 177 &m_timer_steady_clock->GetReadableEvent(), // 6
198 AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp); 178 &m_timer_file_system->GetReadableEvent(), // 7
199 AddWaiter(m_standard_user_auto_correct_clock_event, EventType::AutoCorrect); 179 m_standard_user_auto_correct_clock_event // 8
180 );
200 } 181 }
201 182
202 s32 out_index{-1}; 183 switch (static_cast<EventType>(index)) {
203 Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(),
204 num_objs, -1);
205 ASSERT(out_index >= 0 && out_index < num_objs);
206
207 if (stop_token.stop_requested()) {
208 return;
209 }
210
211 switch (wait_indices[out_index]) {
212 case EventType::Exit: 184 case EventType::Exit:
213 return; 185 return;
214 186
215 case EventType::IpmModuleService_GetEvent:
216 // TODO
217 // IPmModuleService::GetEvent()
218 // clear the event
219 // Handle power state change event
220 break;
221
222 case EventType::PowerStateChange: 187 case EventType::PowerStateChange:
223 m_alarm_worker.GetEvent().Clear(); 188 m_alarm_worker.GetEvent().Clear();
224 if (m_pm_state_change_handler.m_priority <= 1) { 189 if (m_pm_state_change_handler.m_priority <= 1) {
@@ -235,19 +200,19 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
235 m_local_clock_event->Clear(); 200 m_local_clock_event->Clear();
236 201
237 Service::PSC::Time::SystemClockContext context{}; 202 Service::PSC::Time::SystemClockContext context{};
238 auto res = m_local_clock->GetSystemClockContext(&context); 203 R_ASSERT(m_local_clock->GetSystemClockContext(&context));
239 ASSERT(res == ResultSuccess);
240 204
241 m_set_sys->SetUserSystemClockContext(context); 205 m_set_sys->SetUserSystemClockContext(context);
242
243 m_file_timestamp_worker.SetFilesystemPosixTime(); 206 m_file_timestamp_worker.SetFilesystemPosixTime();
244 } break; 207 break;
208 }
245 209
246 case EventType::UpdateNetworkSystemClock: { 210 case EventType::UpdateNetworkSystemClock: {
247 m_network_clock_event->Clear(); 211 m_network_clock_event->Clear();
212
248 Service::PSC::Time::SystemClockContext context{}; 213 Service::PSC::Time::SystemClockContext context{};
249 auto res = m_network_clock->GetSystemClockContext(&context); 214 R_ASSERT(m_network_clock->GetSystemClockContext(&context));
250 ASSERT(res == ResultSuccess); 215
251 m_set_sys->SetNetworkSystemClockContext(context); 216 m_set_sys->SetNetworkSystemClockContext(context);
252 217
253 s64 time{}; 218 s64 time{};
@@ -267,7 +232,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
267 } 232 }
268 233
269 m_file_timestamp_worker.SetFilesystemPosixTime(); 234 m_file_timestamp_worker.SetFilesystemPosixTime();
270 } break; 235 break;
236 }
271 237
272 case EventType::UpdateEphemeralSystemClock: { 238 case EventType::UpdateEphemeralSystemClock: {
273 m_ephemeral_clock_event->Clear(); 239 m_ephemeral_clock_event->Clear();
@@ -295,7 +261,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
295 if (!g_ig_report_ephemeral_clock_context_set) { 261 if (!g_ig_report_ephemeral_clock_context_set) {
296 g_ig_report_ephemeral_clock_context_set = true; 262 g_ig_report_ephemeral_clock_context_set = true;
297 } 263 }
298 } break; 264 break;
265 }
299 266
300 case EventType::UpdateSteadyClock: 267 case EventType::UpdateSteadyClock:
301 m_timer_steady_clock->Clear(); 268 m_timer_steady_clock->Clear();
@@ -314,21 +281,20 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
314 m_standard_user_auto_correct_clock_event->Clear(); 281 m_standard_user_auto_correct_clock_event->Clear();
315 282
316 bool automatic_correction{}; 283 bool automatic_correction{};
317 auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( 284 R_ASSERT(m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
318 &automatic_correction); 285 &automatic_correction));
319 ASSERT(res == ResultSuccess);
320 286
321 Service::PSC::Time::SteadyClockTimePoint time_point{}; 287 Service::PSC::Time::SteadyClockTimePoint time_point{};
322 res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point); 288 R_ASSERT(
323 ASSERT(res == ResultSuccess); 289 m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point));
324 290
325 m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction); 291 m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
326 m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); 292 m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
327 } break; 293 break;
294 }
328 295
329 default: 296 default:
330 UNREACHABLE(); 297 UNREACHABLE();
331 break;
332 } 298 }
333 } 299 }
334} 300}
diff --git a/src/core/hle/service/event.cpp b/src/core/hle/service/os/event.cpp
index 375660d72..ec52c17fd 100644
--- a/src/core/hle/service/event.cpp
+++ b/src/core/hle/service/os/event.cpp
@@ -2,8 +2,8 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/kernel/k_event.h" 4#include "core/hle/kernel/k_event.h"
5#include "core/hle/service/event.h"
6#include "core/hle/service/kernel_helpers.h" 5#include "core/hle/service/kernel_helpers.h"
6#include "core/hle/service/os/event.h"
7 7
8namespace Service { 8namespace Service {
9 9
diff --git a/src/core/hle/service/event.h b/src/core/hle/service/os/event.h
index cdbc4635a..cdbc4635a 100644
--- a/src/core/hle/service/event.h
+++ b/src/core/hle/service/os/event.h
diff --git a/src/core/hle/service/os/multi_wait.cpp b/src/core/hle/service/os/multi_wait.cpp
new file mode 100644
index 000000000..7b80d28be
--- /dev/null
+++ b/src/core/hle/service/os/multi_wait.cpp
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_hardware_timer.h"
5#include "core/hle/kernel/k_synchronization_object.h"
6#include "core/hle/kernel/kernel.h"
7#include "core/hle/kernel/svc_common.h"
8#include "core/hle/service/os/multi_wait.h"
9
10namespace Service {
11
12MultiWait::MultiWait() = default;
13MultiWait::~MultiWait() = default;
14
15MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) {
16 return this->TimedWaitImpl(kernel, -1);
17}
18
19MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) {
20 return this->TimedWaitImpl(kernel, 0);
21}
22
23MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) {
24 return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns);
25}
26
27MultiWaitHolder* MultiWait::TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick) {
28 std::array<MultiWaitHolder*, Kernel::Svc::ArgumentHandleCountMax> holders{};
29 std::array<Kernel::KSynchronizationObject*, Kernel::Svc::ArgumentHandleCountMax> objects{};
30
31 s32 out_index = -1;
32 s32 num_objects = 0;
33
34 for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it++) {
35 ASSERT(num_objects < Kernel::Svc::ArgumentHandleCountMax);
36 holders[num_objects] = std::addressof(*it);
37 objects[num_objects] = it->GetNativeHandle();
38 num_objects++;
39 }
40
41 Kernel::KSynchronizationObject::Wait(kernel, std::addressof(out_index), objects.data(),
42 num_objects, timeout_tick);
43
44 if (out_index == -1) {
45 return nullptr;
46 } else {
47 return holders[out_index];
48 }
49}
50
51void MultiWait::MoveAll(MultiWait* other) {
52 while (!other->m_wait_list.empty()) {
53 MultiWaitHolder& holder = other->m_wait_list.front();
54 holder.UnlinkFromMultiWait();
55 holder.LinkToMultiWait(this);
56 }
57}
58
59} // namespace Service
diff --git a/src/core/hle/service/os/multi_wait.h b/src/core/hle/service/os/multi_wait.h
new file mode 100644
index 000000000..340c611b5
--- /dev/null
+++ b/src/core/hle/service/os/multi_wait.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/os/multi_wait_holder.h"
7
8namespace Kernel {
9class KernelCore;
10}
11
12namespace Service {
13
14class MultiWait final {
15public:
16 explicit MultiWait();
17 ~MultiWait();
18
19public:
20 MultiWaitHolder* WaitAny(Kernel::KernelCore& kernel);
21 MultiWaitHolder* TryWaitAny(Kernel::KernelCore& kernel);
22 MultiWaitHolder* TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns);
23 // TODO: SdkReplyAndReceive?
24
25 void MoveAll(MultiWait* other);
26
27private:
28 MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick);
29
30private:
31 friend class MultiWaitHolder;
32 using ListType = Common::IntrusiveListMemberTraits<&MultiWaitHolder::m_list_node>::ListType;
33 ListType m_wait_list{};
34};
35
36} // namespace Service
diff --git a/src/core/hle/service/os/multi_wait_holder.cpp b/src/core/hle/service/os/multi_wait_holder.cpp
new file mode 100644
index 000000000..01efa045b
--- /dev/null
+++ b/src/core/hle/service/os/multi_wait_holder.cpp
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/os/multi_wait.h"
5#include "core/hle/service/os/multi_wait_holder.h"
6
7namespace Service {
8
9void MultiWaitHolder::LinkToMultiWait(MultiWait* multi_wait) {
10 if (m_multi_wait != nullptr) {
11 UNREACHABLE();
12 }
13
14 m_multi_wait = multi_wait;
15 m_multi_wait->m_wait_list.push_back(*this);
16}
17
18void MultiWaitHolder::UnlinkFromMultiWait() {
19 if (m_multi_wait) {
20 m_multi_wait->m_wait_list.erase(m_multi_wait->m_wait_list.iterator_to(*this));
21 m_multi_wait = nullptr;
22 }
23}
24
25} // namespace Service
diff --git a/src/core/hle/service/os/multi_wait_holder.h b/src/core/hle/service/os/multi_wait_holder.h
new file mode 100644
index 000000000..646395a3f
--- /dev/null
+++ b/src/core/hle/service/os/multi_wait_holder.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/intrusive_list.h"
7
8namespace Kernel {
9class KSynchronizationObject;
10} // namespace Kernel
11
12namespace Service {
13
14class MultiWait;
15
16class MultiWaitHolder {
17public:
18 explicit MultiWaitHolder(Kernel::KSynchronizationObject* native_handle)
19 : m_native_handle(native_handle) {}
20
21 void LinkToMultiWait(MultiWait* multi_wait);
22 void UnlinkFromMultiWait();
23
24 void SetUserData(uintptr_t user_data) {
25 m_user_data = user_data;
26 }
27
28 uintptr_t GetUserData() const {
29 return m_user_data;
30 }
31
32 Kernel::KSynchronizationObject* GetNativeHandle() const {
33 return m_native_handle;
34 }
35
36private:
37 friend class MultiWait;
38 Common::IntrusiveListNode m_list_node{};
39 MultiWait* m_multi_wait{};
40 Kernel::KSynchronizationObject* m_native_handle{};
41 uintptr_t m_user_data{};
42};
43
44} // namespace Service
diff --git a/src/core/hle/service/os/multi_wait_utils.h b/src/core/hle/service/os/multi_wait_utils.h
new file mode 100644
index 000000000..96d3a10f3
--- /dev/null
+++ b/src/core/hle/service/os/multi_wait_utils.h
@@ -0,0 +1,109 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/os/multi_wait.h"
7
8namespace Service {
9
10namespace impl {
11
12class AutoMultiWaitHolder {
13private:
14 MultiWaitHolder m_holder;
15
16public:
17 template <typename T>
18 explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) {
19 m_holder.LinkToMultiWait(multi_wait);
20 }
21
22 ~AutoMultiWaitHolder() {
23 m_holder.UnlinkFromMultiWait();
24 }
25
26 std::pair<MultiWaitHolder*, int> ConvertResult(const std::pair<MultiWaitHolder*, int> result,
27 int index) {
28 if (result.first == std::addressof(m_holder)) {
29 return std::make_pair(static_cast<MultiWaitHolder*>(nullptr), index);
30 } else {
31 return result;
32 }
33 }
34};
35
36using WaitAnyFunction = decltype(&MultiWait::WaitAny);
37
38inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
39 MultiWait* multi_wait, WaitAnyFunction func,
40 int) {
41 return std::pair<MultiWaitHolder*, int>((multi_wait->*func)(kernel), -1);
42}
43
44template <typename T, typename... Args>
45inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
46 MultiWait* multi_wait, WaitAnyFunction func,
47 int index, T&& x, Args&&... args) {
48 AutoMultiWaitHolder holder(multi_wait, std::forward<T>(x));
49 return holder.ConvertResult(
50 WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward<Args>(args)...), index);
51}
52
53template <typename... Args>
54inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
55 MultiWait* multi_wait, WaitAnyFunction func,
56 Args&&... args) {
57 return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward<Args>(args)...);
58}
59
60template <typename... Args>
61inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
62 WaitAnyFunction func, Args&&... args) {
63 MultiWait temp_multi_wait;
64 return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0,
65 std::forward<Args>(args)...);
66}
67
68class NotBoolButInt {
69public:
70 constexpr NotBoolButInt(int v) : m_value(v) {}
71 constexpr operator int() const {
72 return m_value;
73 }
74 explicit operator bool() const = delete;
75
76private:
77 int m_value;
78};
79
80} // namespace impl
81
82template <typename... Args>
83 requires(sizeof...(Args) > 0)
84inline std::pair<MultiWaitHolder*, int> WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait,
85 Args&&... args) {
86 return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward<Args>(args)...);
87}
88
89template <typename... Args>
90 requires(sizeof...(Args) > 0)
91inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) {
92 return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward<Args>(args)...).second;
93}
94
95template <typename... Args>
96 requires(sizeof...(Args) > 0)
97inline std::pair<MultiWaitHolder*, int> TryWaitAny(Kernel::KernelCore& kernel,
98 MultiWait* multi_wait, Args&&... args) {
99 return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait,
100 std::forward<Args>(args)...);
101}
102
103template <typename... Args>
104 requires(sizeof...(Args) > 0)
105inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) {
106 return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward<Args>(args)...).second;
107}
108
109} // namespace Service
diff --git a/src/core/hle/service/mutex.cpp b/src/core/hle/service/os/mutex.cpp
index b0ff71d1b..6009f4866 100644
--- a/src/core/hle/service/mutex.cpp
+++ b/src/core/hle/service/os/mutex.cpp
@@ -4,7 +4,7 @@
4#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/kernel/k_event.h" 5#include "core/hle/kernel/k_event.h"
6#include "core/hle/kernel/k_synchronization_object.h" 6#include "core/hle/kernel/k_synchronization_object.h"
7#include "core/hle/service/mutex.h" 7#include "core/hle/service/os/mutex.h"
8 8
9namespace Service { 9namespace Service {
10 10
diff --git a/src/core/hle/service/mutex.h b/src/core/hle/service/os/mutex.h
index 95ac9b117..95ac9b117 100644
--- a/src/core/hle/service/mutex.h
+++ b/src/core/hle/service/os/mutex.h
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index 8ef49387d..8c7f94c8c 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -20,50 +20,91 @@
20 20
21namespace Service { 21namespace Service {
22 22
23constexpr size_t MaximumWaitObjects = 0x40; 23enum class UserDataTag {
24
25enum HandleType {
26 Port, 24 Port,
27 Session, 25 Session,
28 DeferEvent, 26 DeferEvent,
29 Event,
30}; 27};
31 28
32ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_mutex{system} { 29class Port : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Port> {
30public:
31 explicit Port(Kernel::KServerPort* server_port, SessionRequestHandlerFactory&& handler_factory)
32 : MultiWaitHolder(server_port), m_handler_factory(std::move(handler_factory)) {
33 this->SetUserData(static_cast<uintptr_t>(UserDataTag::Port));
34 }
35
36 ~Port() {
37 this->GetNativeHandle()->Close();
38 }
39
40 SessionRequestHandlerPtr CreateHandler() {
41 return m_handler_factory();
42 }
43
44private:
45 const SessionRequestHandlerFactory m_handler_factory;
46};
47
48class Session : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Session> {
49public:
50 explicit Session(Kernel::KServerSession* server_session,
51 std::shared_ptr<SessionRequestManager>&& manager)
52 : MultiWaitHolder(server_session), m_manager(std::move(manager)) {
53 this->SetUserData(static_cast<uintptr_t>(UserDataTag::Session));
54 }
55
56 ~Session() {
57 this->GetNativeHandle()->Close();
58 }
59
60 std::shared_ptr<SessionRequestManager>& GetManager() {
61 return m_manager;
62 }
63
64 std::shared_ptr<HLERequestContext>& GetContext() {
65 return m_context;
66 }
67
68private:
69 std::shared_ptr<SessionRequestManager> m_manager;
70 std::shared_ptr<HLERequestContext> m_context;
71};
72
73ServerManager::ServerManager(Core::System& system) : m_system{system}, m_selection_mutex{system} {
33 // Initialize event. 74 // Initialize event.
34 m_event = Kernel::KEvent::Create(system.Kernel()); 75 m_wakeup_event = Kernel::KEvent::Create(system.Kernel());
35 m_event->Initialize(nullptr); 76 m_wakeup_event->Initialize(nullptr);
36 77
37 // Register event. 78 // Register event.
38 Kernel::KEvent::Register(system.Kernel(), m_event); 79 Kernel::KEvent::Register(system.Kernel(), m_wakeup_event);
80
81 // Link to holder.
82 m_wakeup_holder.emplace(std::addressof(m_wakeup_event->GetReadableEvent()));
83 m_wakeup_holder->LinkToMultiWait(std::addressof(m_deferred_list));
39} 84}
40 85
41ServerManager::~ServerManager() { 86ServerManager::~ServerManager() {
42 // Signal stop. 87 // Signal stop.
43 m_stop_source.request_stop(); 88 m_stop_source.request_stop();
44 m_event->Signal(); 89 m_wakeup_event->Signal();
45 90
46 // Wait for processing to stop. 91 // Wait for processing to stop.
47 m_stopped.Wait(); 92 m_stopped.Wait();
48 m_threads.clear(); 93 m_threads.clear();
49 94
50 // Clean up server ports. 95 // Clean up ports.
51 for (const auto& [port, handler] : m_ports) { 96 for (auto it = m_servers.begin(); it != m_servers.end(); it = m_servers.erase(it)) {
52 port->Close(); 97 delete std::addressof(*it);
53 } 98 }
54 99
55 // Clean up sessions. 100 // Clean up sessions.
56 for (const auto& [session, manager] : m_sessions) { 101 for (auto it = m_sessions.begin(); it != m_sessions.end(); it = m_sessions.erase(it)) {
57 session->Close(); 102 delete std::addressof(*it);
58 }
59
60 for (const auto& request : m_deferrals) {
61 request.session->Close();
62 } 103 }
63 104
64 // Close event. 105 // Close wakeup event.
65 m_event->GetReadableEvent().Close(); 106 m_wakeup_event->GetReadableEvent().Close();
66 m_event->Close(); 107 m_wakeup_event->Close();
67 108
68 if (m_deferral_event) { 109 if (m_deferral_event) {
69 m_deferral_event->GetReadableEvent().Close(); 110 m_deferral_event->GetReadableEvent().Close();
@@ -75,19 +116,19 @@ void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
75 server_manager->m_system.RunServer(std::move(server_manager)); 116 server_manager->m_system.RunServer(std::move(server_manager));
76} 117}
77 118
78Result ServerManager::RegisterSession(Kernel::KServerSession* session, 119Result ServerManager::RegisterSession(Kernel::KServerSession* server_session,
79 std::shared_ptr<SessionRequestManager> manager) { 120 std::shared_ptr<SessionRequestManager> manager) {
80 ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
81
82 // We are taking ownership of the server session, so don't open it. 121 // We are taking ownership of the server session, so don't open it.
122 auto* session = new Session(server_session, std::move(manager));
123
83 // Begin tracking the server session. 124 // Begin tracking the server session.
84 { 125 {
85 std::scoped_lock ll{m_list_mutex}; 126 std::scoped_lock ll{m_deferred_list_mutex};
86 m_sessions.emplace(session, std::move(manager)); 127 m_sessions.push_back(*session);
87 } 128 }
88 129
89 // Signal the wakeup event. 130 // Register to wait on the session.
90 m_event->Signal(); 131 this->LinkToDeferredList(session);
91 132
92 R_SUCCEED(); 133 R_SUCCEED();
93} 134}
@@ -95,21 +136,22 @@ Result ServerManager::RegisterSession(Kernel::KServerSession* session,
95Result ServerManager::RegisterNamedService(const std::string& service_name, 136Result ServerManager::RegisterNamedService(const std::string& service_name,
96 SessionRequestHandlerFactory&& handler_factory, 137 SessionRequestHandlerFactory&& handler_factory,
97 u32 max_sessions) { 138 u32 max_sessions) {
98 ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
99
100 // Add the new server to sm: and get the moved server port. 139 // Add the new server to sm: and get the moved server port.
101 Kernel::KServerPort* server_port{}; 140 Kernel::KServerPort* server_port{};
102 R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name, 141 R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name,
103 max_sessions, handler_factory)); 142 max_sessions, handler_factory));
104 143
144 // We are taking ownership of the server port, so don't open it.
145 auto* server = new Port(server_port, std::move(handler_factory));
146
105 // Begin tracking the server port. 147 // Begin tracking the server port.
106 { 148 {
107 std::scoped_lock ll{m_list_mutex}; 149 std::scoped_lock ll{m_deferred_list_mutex};
108 m_ports.emplace(server_port, std::move(handler_factory)); 150 m_servers.push_back(*server);
109 } 151 }
110 152
111 // Signal the wakeup event. 153 // Register to wait on the server port.
112 m_event->Signal(); 154 this->LinkToDeferredList(server);
113 155
114 R_SUCCEED(); 156 R_SUCCEED();
115} 157}
@@ -127,8 +169,6 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
127Result ServerManager::ManageNamedPort(const std::string& service_name, 169Result ServerManager::ManageNamedPort(const std::string& service_name,
128 SessionRequestHandlerFactory&& handler_factory, 170 SessionRequestHandlerFactory&& handler_factory,
129 u32 max_sessions) { 171 u32 max_sessions) {
130 ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
131
132 // Create a new port. 172 // Create a new port.
133 auto* port = Kernel::KPort::Create(m_system.Kernel()); 173 auto* port = Kernel::KPort::Create(m_system.Kernel());
134 port->Initialize(max_sessions, false, 0); 174 port->Initialize(max_sessions, false, 0);
@@ -149,12 +189,18 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
149 // Open a new reference to the server port. 189 // Open a new reference to the server port.
150 port->GetServerPort().Open(); 190 port->GetServerPort().Open();
151 191
152 // Begin tracking the server port. 192 // Transfer ownership into a new port object.
193 auto* server = new Port(std::addressof(port->GetServerPort()), std::move(handler_factory));
194
195 // Begin tracking the port.
153 { 196 {
154 std::scoped_lock ll{m_list_mutex}; 197 std::scoped_lock ll{m_deferred_list_mutex};
155 m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); 198 m_servers.push_back(*server);
156 } 199 }
157 200
201 // Register to wait on the port.
202 this->LinkToDeferredList(server);
203
158 // We succeeded. 204 // We succeeded.
159 R_SUCCEED(); 205 R_SUCCEED();
160} 206}
@@ -173,6 +219,11 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
173 // Set the output. 219 // Set the output.
174 *out_event = m_deferral_event; 220 *out_event = m_deferral_event;
175 221
222 // Register to wait on the event.
223 m_deferral_holder.emplace(std::addressof(m_deferral_event->GetReadableEvent()));
224 m_deferral_holder->SetUserData(static_cast<uintptr_t>(UserDataTag::DeferEvent));
225 this->LinkToDeferredList(std::addressof(*m_deferral_holder));
226
176 // We succeeded. 227 // We succeeded.
177 R_SUCCEED(); 228 R_SUCCEED();
178} 229}
@@ -191,270 +242,185 @@ Result ServerManager::LoopProcess() {
191 R_RETURN(this->LoopProcessImpl()); 242 R_RETURN(this->LoopProcessImpl());
192} 243}
193 244
194Result ServerManager::LoopProcessImpl() { 245void ServerManager::LinkToDeferredList(MultiWaitHolder* holder) {
195 while (!m_stop_source.stop_requested()) { 246 // Link.
196 R_TRY(this->WaitAndProcessImpl()); 247 {
248 std::scoped_lock lk{m_deferred_list_mutex};
249 holder->LinkToMultiWait(std::addressof(m_deferred_list));
197 } 250 }
198 251
199 R_SUCCEED(); 252 // Signal the wakeup event.
253 m_wakeup_event->Signal();
200} 254}
201 255
202Result ServerManager::WaitAndProcessImpl() { 256void ServerManager::LinkDeferred() {
203 Kernel::KScopedAutoObject<Kernel::KSynchronizationObject> wait_obj; 257 std::scoped_lock lk{m_deferred_list_mutex};
204 HandleType wait_type{}; 258 m_multi_wait.MoveAll(std::addressof(m_deferred_list));
259}
205 260
261MultiWaitHolder* ServerManager::WaitSignaled() {
206 // Ensure we are the only thread waiting for this server. 262 // Ensure we are the only thread waiting for this server.
207 std::unique_lock sl{m_serve_mutex}; 263 std::scoped_lock lk{m_selection_mutex};
208 264
209 // If we're done, return before we start waiting. 265 while (true) {
210 R_SUCCEED_IF(m_stop_source.stop_requested()); 266 this->LinkDeferred();
211 267
212 // Wait for a tracked object to become signaled. 268 // If we're done, return before we start waiting.
213 { 269 if (m_stop_source.stop_requested()) {
214 s32 num_objs{}; 270 return nullptr;
215 std::array<HandleType, MaximumWaitObjects> wait_types{};
216 std::array<Kernel::KSynchronizationObject*, MaximumWaitObjects> wait_objs{};
217
218 const auto AddWaiter{
219 [&](Kernel::KSynchronizationObject* synchronization_object, HandleType type) {
220 // Open a new reference to the object.
221 synchronization_object->Open();
222
223 // Insert into the list.
224 wait_types[num_objs] = type;
225 wait_objs[num_objs++] = synchronization_object;
226 }};
227
228 {
229 std::scoped_lock ll{m_list_mutex};
230
231 // Add all of our ports.
232 for (const auto& [port, handler] : m_ports) {
233 AddWaiter(port, HandleType::Port);
234 }
235
236 // Add all of our sessions.
237 for (const auto& [session, manager] : m_sessions) {
238 AddWaiter(session, HandleType::Session);
239 }
240 } 271 }
241 272
242 // Add the deferral wakeup event. 273 auto* selected = m_multi_wait.WaitAny(m_system.Kernel());
243 if (m_deferral_event != nullptr) { 274 if (selected == std::addressof(*m_wakeup_holder)) {
244 AddWaiter(std::addressof(m_deferral_event->GetReadableEvent()), HandleType::DeferEvent); 275 // Clear and restart if we were woken up.
276 m_wakeup_event->Clear();
277 } else {
278 // Unlink and handle the event.
279 selected->UnlinkFromMultiWait();
280 return selected;
245 } 281 }
282 }
283}
246 284
247 // Add the wakeup event. 285Result ServerManager::Process(MultiWaitHolder* holder) {
248 AddWaiter(std::addressof(m_event->GetReadableEvent()), HandleType::Event); 286 switch (static_cast<UserDataTag>(holder->GetUserData())) {
249 287 case UserDataTag::Session:
250 // Clean up extra references on exit. 288 R_RETURN(this->OnSessionEvent(static_cast<Session*>(holder)));
251 SCOPE_EXIT({ 289 case UserDataTag::Port:
252 for (s32 i = 0; i < num_objs; i++) { 290 R_RETURN(this->OnPortEvent(static_cast<Port*>(holder)));
253 wait_objs[i]->Close(); 291 case UserDataTag::DeferEvent:
254 } 292 R_RETURN(this->OnDeferralEvent());
255 }); 293 default:
256 294 UNREACHABLE();
257 // Wait for a signal. 295 }
258 s32 out_index{-1}; 296}
259 R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index,
260 wait_objs.data(), num_objs, -1)) {
261 R_CATCH(Kernel::ResultSessionClosed) {
262 // On session closed, index is updated and we don't want to return an error.
263 }
264 }
265 R_END_TRY_CATCH;
266 ASSERT(out_index >= 0 && out_index < num_objs);
267 297
268 // Set the output index. 298bool ServerManager::WaitAndProcessImpl() {
269 wait_obj = wait_objs[out_index]; 299 if (auto* signaled_holder = this->WaitSignaled(); signaled_holder != nullptr) {
270 wait_type = wait_types[out_index]; 300 R_ASSERT(this->Process(signaled_holder));
301 return true;
302 } else {
303 return false;
271 } 304 }
305}
272 306
273 // Process what we just received, temporarily removing the object so it is 307Result ServerManager::LoopProcessImpl() {
274 // not processed concurrently by another thread. 308 while (!m_stop_source.stop_requested()) {
275 { 309 this->WaitAndProcessImpl();
276 switch (wait_type) {
277 case HandleType::Port: {
278 // Port signaled.
279 auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>();
280 SessionRequestHandlerFactory handler_factory;
281
282 // Remove from tracking.
283 {
284 std::scoped_lock ll{m_list_mutex};
285 ASSERT(m_ports.contains(port));
286 m_ports.at(port).swap(handler_factory);
287 m_ports.erase(port);
288 }
289
290 // Allow other threads to serve.
291 sl.unlock();
292
293 // Finish.
294 R_RETURN(this->OnPortEvent(port, std::move(handler_factory)));
295 }
296 case HandleType::Session: {
297 // Session signaled.
298 auto* session = wait_obj->DynamicCast<Kernel::KServerSession*>();
299 std::shared_ptr<SessionRequestManager> manager;
300
301 // Remove from tracking.
302 {
303 std::scoped_lock ll{m_list_mutex};
304 ASSERT(m_sessions.contains(session));
305 m_sessions.at(session).swap(manager);
306 m_sessions.erase(session);
307 }
308
309 // Allow other threads to serve.
310 sl.unlock();
311
312 // Finish.
313 R_RETURN(this->OnSessionEvent(session, std::move(manager)));
314 }
315 case HandleType::DeferEvent: {
316 // Clear event.
317 ASSERT(R_SUCCEEDED(m_deferral_event->Clear()));
318
319 // Drain the list of deferrals while we process.
320 std::list<RequestState> deferrals;
321 {
322 std::scoped_lock ll{m_list_mutex};
323 m_deferrals.swap(deferrals);
324 }
325
326 // Allow other threads to serve.
327 sl.unlock();
328
329 // Finish.
330 R_RETURN(this->OnDeferralEvent(std::move(deferrals)));
331 }
332 case HandleType::Event: {
333 // Clear event and finish.
334 R_RETURN(m_event->Clear());
335 }
336 default: {
337 UNREACHABLE();
338 }
339 }
340 } 310 }
311
312 R_SUCCEED();
341} 313}
342 314
343Result ServerManager::OnPortEvent(Kernel::KServerPort* port, 315Result ServerManager::OnPortEvent(Port* server) {
344 SessionRequestHandlerFactory&& handler_factory) {
345 // Accept a new server session. 316 // Accept a new server session.
346 Kernel::KServerSession* session = port->AcceptSession(); 317 auto* server_port = static_cast<Kernel::KServerPort*>(server->GetNativeHandle());
347 ASSERT(session != nullptr); 318 Kernel::KServerSession* server_session = server_port->AcceptSession();
319 ASSERT(server_session != nullptr);
348 320
349 // Create the session manager and install the handler. 321 // Create the session manager and install the handler.
350 auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this); 322 auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this);
351 manager->SetSessionHandler(handler_factory()); 323 manager->SetSessionHandler(server->CreateHandler());
352 324
353 // Track the server session. 325 // Create and register the new session.
354 { 326 this->RegisterSession(server_session, std::move(manager));
355 std::scoped_lock ll{m_list_mutex};
356 m_ports.emplace(port, std::move(handler_factory));
357 m_sessions.emplace(session, std::move(manager));
358 }
359 327
360 // Signal the wakeup event. 328 // Resume tracking the port.
361 m_event->Signal(); 329 this->LinkToDeferredList(server);
362 330
363 // We succeeded. 331 // We succeeded.
364 R_SUCCEED(); 332 R_SUCCEED();
365} 333}
366 334
367Result ServerManager::OnSessionEvent(Kernel::KServerSession* session, 335Result ServerManager::OnSessionEvent(Session* session) {
368 std::shared_ptr<SessionRequestManager>&& manager) { 336 Result res = ResultSuccess;
369 Result rc{ResultSuccess};
370 337
371 // Try to receive a message. 338 // Try to receive a message.
372 std::shared_ptr<HLERequestContext> context; 339 auto* server_session = static_cast<Kernel::KServerSession*>(session->GetNativeHandle());
373 rc = session->ReceiveRequestHLE(&context, manager); 340 res = server_session->ReceiveRequestHLE(&session->GetContext(), session->GetManager());
374 341
375 // If the session has been closed, we're done. 342 // If the session has been closed, we're done.
376 if (rc == Kernel::ResultSessionClosed) { 343 if (res == Kernel::ResultSessionClosed) {
377 // Close the session. 344 this->DestroySession(session);
378 session->Close();
379
380 // Finish.
381 R_SUCCEED(); 345 R_SUCCEED();
382 } 346 }
383 ASSERT(R_SUCCEEDED(rc));
384 347
385 RequestState request{ 348 R_ASSERT(res);
386 .session = session,
387 .context = std::move(context),
388 .manager = std::move(manager),
389 };
390 349
391 // Complete the sync request with deferral handling. 350 // Complete the sync request with deferral handling.
392 R_RETURN(this->CompleteSyncRequest(std::move(request))); 351 R_RETURN(this->CompleteSyncRequest(session));
393} 352}
394 353
395Result ServerManager::CompleteSyncRequest(RequestState&& request) { 354Result ServerManager::CompleteSyncRequest(Session* session) {
396 Result rc{ResultSuccess}; 355 Result res = ResultSuccess;
397 Result service_rc{ResultSuccess}; 356 Result service_res = ResultSuccess;
398 357
399 // Mark the request as not deferred. 358 // Mark the request as not deferred.
400 request.context->SetIsDeferred(false); 359 session->GetContext()->SetIsDeferred(false);
401 360
402 // Complete the request. We have exclusive access to this session. 361 // Complete the request. We have exclusive access to this session.
403 service_rc = request.manager->CompleteSyncRequest(request.session, *request.context); 362 auto* server_session = static_cast<Kernel::KServerSession*>(session->GetNativeHandle());
363 service_res =
364 session->GetManager()->CompleteSyncRequest(server_session, *session->GetContext());
404 365
405 // If we've been deferred, we're done. 366 // If we've been deferred, we're done.
406 if (request.context->GetIsDeferred()) { 367 if (session->GetContext()->GetIsDeferred()) {
407 // Insert into deferral list. 368 // Insert into deferred session list.
408 std::scoped_lock ll{m_list_mutex}; 369 std::scoped_lock ll{m_deferred_list_mutex};
409 m_deferrals.emplace_back(std::move(request)); 370 m_deferred_sessions.push_back(session);
410 371
411 // Finish. 372 // Finish.
412 R_SUCCEED(); 373 R_SUCCEED();
413 } 374 }
414 375
415 // Send the reply. 376 // Send the reply.
416 rc = request.session->SendReplyHLE(); 377 res = server_session->SendReplyHLE();
417 378
418 // If the session has been closed, we're done. 379 // If the session has been closed, we're done.
419 if (rc == Kernel::ResultSessionClosed || service_rc == IPC::ResultSessionClosed) { 380 if (res == Kernel::ResultSessionClosed || service_res == IPC::ResultSessionClosed) {
420 // Close the session. 381 this->DestroySession(session);
421 request.session->Close();
422
423 // Finish.
424 R_SUCCEED(); 382 R_SUCCEED();
425 } 383 }
426 384
427 ASSERT(R_SUCCEEDED(rc)); 385 R_ASSERT(res);
428 ASSERT(R_SUCCEEDED(service_rc)); 386 R_ASSERT(service_res);
429
430 // Reinsert the session.
431 {
432 std::scoped_lock ll{m_list_mutex};
433 m_sessions.emplace(request.session, std::move(request.manager));
434 }
435 387
436 // Signal the wakeup event. 388 // We succeeded, so we can process future messages on this session.
437 m_event->Signal(); 389 this->LinkToDeferredList(session);
438 390
439 // We succeeded.
440 R_SUCCEED(); 391 R_SUCCEED();
441} 392}
442 393
443Result ServerManager::OnDeferralEvent(std::list<RequestState>&& deferrals) { 394Result ServerManager::OnDeferralEvent() {
444 ON_RESULT_FAILURE { 395 // Clear event before grabbing the list.
445 std::scoped_lock ll{m_list_mutex}; 396 m_deferral_event->Clear();
446 m_deferrals.splice(m_deferrals.end(), deferrals);
447 };
448 397
449 while (!deferrals.empty()) { 398 // Get and clear list.
450 RequestState request = deferrals.front(); 399 const auto deferrals = [&] {
451 deferrals.pop_front(); 400 std::scoped_lock lk{m_deferred_list_mutex};
401 return std::move(m_deferred_sessions);
402 }();
452 403
453 // Try again to complete the request. 404 // Relink deferral event.
454 R_TRY(this->CompleteSyncRequest(std::move(request))); 405 this->LinkToDeferredList(std::addressof(*m_deferral_holder));
406
407 // For each session, try again to complete the request.
408 for (auto* session : deferrals) {
409 R_ASSERT(this->CompleteSyncRequest(session));
455 } 410 }
456 411
457 R_SUCCEED(); 412 R_SUCCEED();
458} 413}
459 414
415void ServerManager::DestroySession(Session* session) {
416 // Unlink.
417 {
418 std::scoped_lock lk{m_deferred_list_mutex};
419 m_sessions.erase(m_sessions.iterator_to(*session));
420 }
421
422 // Free the session.
423 delete session;
424}
425
460} // namespace Service 426} // namespace Service
diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h
index c4bc07262..5173ce46e 100644
--- a/src/core/hle/service/server_manager.h
+++ b/src/core/hle/service/server_manager.h
@@ -3,18 +3,17 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <functional>
7#include <list> 6#include <list>
8#include <map>
9#include <mutex> 7#include <mutex>
10#include <string_view> 8#include <optional>
11#include <vector> 9#include <vector>
12 10
13#include "common/polyfill_thread.h" 11#include "common/polyfill_thread.h"
14#include "common/thread.h" 12#include "common/thread.h"
15#include "core/hle/result.h" 13#include "core/hle/result.h"
16#include "core/hle/service/hle_ipc.h" 14#include "core/hle/service/hle_ipc.h"
17#include "core/hle/service/mutex.h" 15#include "core/hle/service/os/multi_wait.h"
16#include "core/hle/service/os/mutex.h"
18 17
19namespace Core { 18namespace Core {
20class System; 19class System;
@@ -24,11 +23,13 @@ namespace Kernel {
24class KEvent; 23class KEvent;
25class KServerPort; 24class KServerPort;
26class KServerSession; 25class KServerSession;
27class KSynchronizationObject;
28} // namespace Kernel 26} // namespace Kernel
29 27
30namespace Service { 28namespace Service {
31 29
30class Port;
31class Session;
32
32class ServerManager { 33class ServerManager {
33public: 34public:
34 explicit ServerManager(Core::System& system); 35 explicit ServerManager(Core::System& system);
@@ -52,34 +53,40 @@ public:
52 static void RunServer(std::unique_ptr<ServerManager>&& server); 53 static void RunServer(std::unique_ptr<ServerManager>&& server);
53 54
54private: 55private:
55 struct RequestState; 56 void LinkToDeferredList(MultiWaitHolder* holder);
56 57 void LinkDeferred();
58 MultiWaitHolder* WaitSignaled();
59 Result Process(MultiWaitHolder* holder);
60 bool WaitAndProcessImpl();
57 Result LoopProcessImpl(); 61 Result LoopProcessImpl();
58 Result WaitAndProcessImpl(); 62
59 Result OnPortEvent(Kernel::KServerPort* port, SessionRequestHandlerFactory&& handler_factory); 63 Result OnPortEvent(Port* port);
60 Result OnSessionEvent(Kernel::KServerSession* session, 64 Result OnSessionEvent(Session* session);
61 std::shared_ptr<SessionRequestManager>&& manager); 65 Result OnDeferralEvent();
62 Result OnDeferralEvent(std::list<RequestState>&& deferrals); 66 Result CompleteSyncRequest(Session* session);
63 Result CompleteSyncRequest(RequestState&& state); 67
68private:
69 void DestroySession(Session* session);
64 70
65private: 71private:
66 Core::System& m_system; 72 Core::System& m_system;
67 Mutex m_serve_mutex; 73 Mutex m_selection_mutex;
68 std::mutex m_list_mutex;
69 74
70 // Guest state tracking 75 // Events
71 std::map<Kernel::KServerPort*, SessionRequestHandlerFactory> m_ports{}; 76 Kernel::KEvent* m_wakeup_event{};
72 std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{};
73 Kernel::KEvent* m_event{};
74 Kernel::KEvent* m_deferral_event{}; 77 Kernel::KEvent* m_deferral_event{};
75 78
76 // Deferral tracking 79 // Deferred wait list
77 struct RequestState { 80 std::mutex m_deferred_list_mutex{};
78 Kernel::KServerSession* session; 81 MultiWait m_deferred_list{};
79 std::shared_ptr<HLERequestContext> context; 82
80 std::shared_ptr<SessionRequestManager> manager; 83 // Guest state tracking
81 }; 84 MultiWait m_multi_wait{};
82 std::list<RequestState> m_deferrals{}; 85 Common::IntrusiveListBaseTraits<Port>::ListType m_servers{};
86 Common::IntrusiveListBaseTraits<Session>::ListType m_sessions{};
87 std::list<Session*> m_deferred_sessions{};
88 std::optional<MultiWaitHolder> m_wakeup_holder{};
89 std::optional<MultiWaitHolder> m_deferral_holder{};
83 90
84 // Host state tracking 91 // Host state tracking
85 Common::Event m_stopped{}; 92 Common::Event m_stopped{};