diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | src/core/hle/service/am/applet.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/am/applet_data_broker.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/glue/time/worker.cpp | 130 | ||||
| -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.cpp | 59 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait.h | 36 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait_holder.cpp | 25 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait_holder.h | 44 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait_utils.h | 109 | ||||
| -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.cpp | 438 | ||||
| -rw-r--r-- | src/core/hle/service/server_manager.h | 59 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby_p.h | 13 |
16 files changed, 579 insertions, 355 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c7157ff4c..2d5490968 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -573,8 +573,6 @@ add_library(core STATIC | |||
| 573 | hle/service/es/es.h | 573 | hle/service/es/es.h |
| 574 | hle/service/eupld/eupld.cpp | 574 | hle/service/eupld/eupld.cpp |
| 575 | hle/service/eupld/eupld.h | 575 | hle/service/eupld/eupld.h |
| 576 | hle/service/event.cpp | ||
| 577 | hle/service/event.h | ||
| 578 | hle/service/fatal/fatal.cpp | 576 | hle/service/fatal/fatal.cpp |
| 579 | hle/service/fatal/fatal.h | 577 | hle/service/fatal/fatal.h |
| 580 | hle/service/fatal/fatal_p.cpp | 578 | hle/service/fatal/fatal_p.cpp |
| @@ -701,8 +699,6 @@ add_library(core STATIC | |||
| 701 | hle/service/mm/mm_u.h | 699 | hle/service/mm/mm_u.h |
| 702 | hle/service/mnpp/mnpp_app.cpp | 700 | hle/service/mnpp/mnpp_app.cpp |
| 703 | hle/service/mnpp/mnpp_app.h | 701 | hle/service/mnpp/mnpp_app.h |
| 704 | hle/service/mutex.cpp | ||
| 705 | hle/service/mutex.h | ||
| 706 | hle/service/ncm/ncm.cpp | 702 | hle/service/ncm/ncm.cpp |
| 707 | hle/service/ncm/ncm.h | 703 | hle/service/ncm/ncm.h |
| 708 | hle/service/nfc/common/amiibo_crypto.cpp | 704 | hle/service/nfc/common/amiibo_crypto.cpp |
| @@ -815,6 +811,15 @@ add_library(core STATIC | |||
| 815 | hle/service/nvnflinger/window.h | 811 | hle/service/nvnflinger/window.h |
| 816 | hle/service/olsc/olsc.cpp | 812 | hle/service/olsc/olsc.cpp |
| 817 | hle/service/olsc/olsc.h | 813 | hle/service/olsc/olsc.h |
| 814 | hle/service/os/event.cpp | ||
| 815 | hle/service/os/event.h | ||
| 816 | hle/service/os/multi_wait_holder.cpp | ||
| 817 | hle/service/os/multi_wait_holder.h | ||
| 818 | hle/service/os/multi_wait_utils.h | ||
| 819 | hle/service/os/multi_wait.cpp | ||
| 820 | hle/service/os/multi_wait.h | ||
| 821 | hle/service/os/mutex.cpp | ||
| 822 | hle/service/os/mutex.h | ||
| 818 | hle/service/pcie/pcie.cpp | 823 | hle/service/pcie/pcie.cpp |
| 819 | hle/service/pcie/pcie.h | 824 | hle/service/pcie/pcie.h |
| 820 | hle/service/pctl/pctl.cpp | 825 | 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 | ||
| 13 | union Result; | 13 | union 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 | ||
| 8 | namespace Service { | 8 | namespace 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 | |||
| 10 | namespace Service { | ||
| 11 | |||
| 12 | MultiWait::MultiWait() = default; | ||
| 13 | MultiWait::~MultiWait() = default; | ||
| 14 | |||
| 15 | MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) { | ||
| 16 | return this->TimedWaitImpl(kernel, -1); | ||
| 17 | } | ||
| 18 | |||
| 19 | MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) { | ||
| 20 | return this->TimedWaitImpl(kernel, 0); | ||
| 21 | } | ||
| 22 | |||
| 23 | MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) { | ||
| 24 | return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns); | ||
| 25 | } | ||
| 26 | |||
| 27 | MultiWaitHolder* 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 | |||
| 51 | void 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 | |||
| 8 | namespace Kernel { | ||
| 9 | class KernelCore; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | |||
| 14 | class MultiWait final { | ||
| 15 | public: | ||
| 16 | explicit MultiWait(); | ||
| 17 | ~MultiWait(); | ||
| 18 | |||
| 19 | public: | ||
| 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 | |||
| 27 | private: | ||
| 28 | MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick); | ||
| 29 | |||
| 30 | private: | ||
| 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 | |||
| 7 | namespace Service { | ||
| 8 | |||
| 9 | void 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 | |||
| 18 | void 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 | |||
| 8 | namespace Kernel { | ||
| 9 | class KSynchronizationObject; | ||
| 10 | } // namespace Kernel | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | |||
| 14 | class MultiWait; | ||
| 15 | |||
| 16 | class MultiWaitHolder { | ||
| 17 | public: | ||
| 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 | |||
| 36 | private: | ||
| 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 | |||
| 8 | namespace Service { | ||
| 9 | |||
| 10 | namespace impl { | ||
| 11 | |||
| 12 | class AutoMultiWaitHolder { | ||
| 13 | private: | ||
| 14 | MultiWaitHolder m_holder; | ||
| 15 | |||
| 16 | public: | ||
| 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 | |||
| 36 | using WaitAnyFunction = decltype(&MultiWait::WaitAny); | ||
| 37 | |||
| 38 | inline 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 | |||
| 44 | template <typename T, typename... Args> | ||
| 45 | inline 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 | |||
| 53 | template <typename... Args> | ||
| 54 | inline 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 | |||
| 60 | template <typename... Args> | ||
| 61 | inline 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 | |||
| 68 | class NotBoolButInt { | ||
| 69 | public: | ||
| 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 | |||
| 76 | private: | ||
| 77 | int m_value; | ||
| 78 | }; | ||
| 79 | |||
| 80 | } // namespace impl | ||
| 81 | |||
| 82 | template <typename... Args> | ||
| 83 | requires(sizeof...(Args) > 0) | ||
| 84 | inline 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 | |||
| 89 | template <typename... Args> | ||
| 90 | requires(sizeof...(Args) > 0) | ||
| 91 | inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) { | ||
| 92 | return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward<Args>(args)...).second; | ||
| 93 | } | ||
| 94 | |||
| 95 | template <typename... Args> | ||
| 96 | requires(sizeof...(Args) > 0) | ||
| 97 | inline 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 | |||
| 103 | template <typename... Args> | ||
| 104 | requires(sizeof...(Args) > 0) | ||
| 105 | inline 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 | ||
| 9 | namespace Service { | 9 | namespace 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 | ||
| 21 | namespace Service { | 21 | namespace Service { |
| 22 | 22 | ||
| 23 | constexpr size_t MaximumWaitObjects = 0x40; | 23 | enum class UserDataTag { |
| 24 | |||
| 25 | enum HandleType { | ||
| 26 | Port, | 24 | Port, |
| 27 | Session, | 25 | Session, |
| 28 | DeferEvent, | 26 | DeferEvent, |
| 29 | Event, | ||
| 30 | }; | 27 | }; |
| 31 | 28 | ||
| 32 | ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_mutex{system} { | 29 | class Port : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Port> { |
| 30 | public: | ||
| 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 | |||
| 44 | private: | ||
| 45 | const SessionRequestHandlerFactory m_handler_factory; | ||
| 46 | }; | ||
| 47 | |||
| 48 | class Session : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Session> { | ||
| 49 | public: | ||
| 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 | |||
| 68 | private: | ||
| 69 | std::shared_ptr<SessionRequestManager> m_manager; | ||
| 70 | std::shared_ptr<HLERequestContext> m_context; | ||
| 71 | }; | ||
| 72 | |||
| 73 | ServerManager::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 | ||
| 41 | ServerManager::~ServerManager() { | 86 | ServerManager::~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 | ||
| 78 | Result ServerManager::RegisterSession(Kernel::KServerSession* session, | 119 | Result 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, | |||
| 95 | Result ServerManager::RegisterNamedService(const std::string& service_name, | 136 | Result 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, | |||
| 127 | Result ServerManager::ManageNamedPort(const std::string& service_name, | 169 | Result 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 | ||
| 194 | Result ServerManager::LoopProcessImpl() { | 245 | void 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 | ||
| 202 | Result ServerManager::WaitAndProcessImpl() { | 256 | void 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 | ||
| 261 | MultiWaitHolder* 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. | 285 | Result 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. | 298 | bool 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 | 307 | Result 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 | ||
| 343 | Result ServerManager::OnPortEvent(Kernel::KServerPort* port, | 315 | Result 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 | ||
| 367 | Result ServerManager::OnSessionEvent(Kernel::KServerSession* session, | 335 | Result 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 | ||
| 395 | Result ServerManager::CompleteSyncRequest(RequestState&& request) { | 354 | Result 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 | ||
| 443 | Result ServerManager::OnDeferralEvent(std::list<RequestState>&& deferrals) { | 394 | Result 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 | ||
| 415 | void 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 | ||
| 19 | namespace Core { | 18 | namespace Core { |
| 20 | class System; | 19 | class System; |
| @@ -24,11 +23,13 @@ namespace Kernel { | |||
| 24 | class KEvent; | 23 | class KEvent; |
| 25 | class KServerPort; | 24 | class KServerPort; |
| 26 | class KServerSession; | 25 | class KServerSession; |
| 27 | class KSynchronizationObject; | ||
| 28 | } // namespace Kernel | 26 | } // namespace Kernel |
| 29 | 27 | ||
| 30 | namespace Service { | 28 | namespace Service { |
| 31 | 29 | ||
| 30 | class Port; | ||
| 31 | class Session; | ||
| 32 | |||
| 32 | class ServerManager { | 33 | class ServerManager { |
| 33 | public: | 34 | public: |
| 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 | ||
| 54 | private: | 55 | private: |
| 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 | |
| 68 | private: | ||
| 69 | void DestroySession(Session* session); | ||
| 64 | 70 | ||
| 65 | private: | 71 | private: |
| 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{}; |
diff --git a/src/yuzu/multiplayer/lobby_p.h b/src/yuzu/multiplayer/lobby_p.h index 398833e7a..77ec1fcde 100644 --- a/src/yuzu/multiplayer/lobby_p.h +++ b/src/yuzu/multiplayer/lobby_p.h | |||
| @@ -202,12 +202,19 @@ public: | |||
| 202 | case Qt::ForegroundRole: { | 202 | case Qt::ForegroundRole: { |
| 203 | auto members = data(MemberListRole).toList(); | 203 | auto members = data(MemberListRole).toList(); |
| 204 | auto max_players = data(MaxPlayerRole).toInt(); | 204 | auto max_players = data(MaxPlayerRole).toInt(); |
| 205 | const QColor room_full_color(255, 48, 32); | ||
| 206 | const QColor room_almost_full_color(255, 140, 32); | ||
| 207 | const QColor room_has_players_color(32, 160, 32); | ||
| 208 | const QColor room_empty_color(128, 128, 128); | ||
| 209 | |||
| 205 | if (members.size() >= max_players) { | 210 | if (members.size() >= max_players) { |
| 206 | return QBrush(QColor(255, 48, 32)); | 211 | return QBrush(room_full_color); |
| 207 | } else if (members.size() == (max_players - 1)) { | 212 | } else if (members.size() == (max_players - 1)) { |
| 208 | return QBrush(QColor(255, 140, 32)); | 213 | return QBrush(room_almost_full_color); |
| 209 | } else if (members.size() == 0) { | 214 | } else if (members.size() == 0) { |
| 210 | return QBrush(QColor(128, 128, 128)); | 215 | return QBrush(room_empty_color); |
| 216 | } else if (members.size() > 0 && members.size() < (max_players - 1)) { | ||
| 217 | return QBrush(room_has_players_color); | ||
| 211 | } | 218 | } |
| 212 | // FIXME: How to return a value that tells Qt not to modify the | 219 | // FIXME: How to return a value that tells Qt not to modify the |
| 213 | // text color from the default (as if Qt::ForegroundRole wasn't overridden)? | 220 | // text color from the default (as if Qt::ForegroundRole wasn't overridden)? |