diff options
| author | liamwhite <liamwhite@users.noreply.github.com> | 2024-02-10 16:00:34 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-10 16:00:34 -0500 | 
| commit | 7c56ecca3f5fd2b70564209d765593c56a500c9e (patch) | |
| tree | c1ebc60262c7103409b59f284bdd176e4c86c5d9 | |
| parent | fe6934593fd7e7b6c61d1fb84d0794d19f024b47 (diff) | |
| parent | 5a64a77df34f7564af98bc53c26ef82d215cd5a5 (diff) | |
Merge pull request #12949 from liamwhite/multi-wait
service: add os types and multi wait API
| -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 | 
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      hle/service/es/es.h      hle/service/eupld/eupld.cpp      hle/service/eupld/eupld.h -    hle/service/event.cpp -    hle/service/event.h      hle/service/fatal/fatal.cpp      hle/service/fatal/fatal.h      hle/service/fatal/fatal_p.cpp @@ -676,8 +674,6 @@ add_library(core STATIC      hle/service/mm/mm_u.h      hle/service/mnpp/mnpp_app.cpp      hle/service/mnpp/mnpp_app.h -    hle/service/mutex.cpp -    hle/service/mutex.h      hle/service/ncm/ncm.cpp      hle/service/ncm/ncm.h      hle/service/nfc/common/amiibo_crypto.cpp @@ -790,6 +786,15 @@ add_library(core STATIC      hle/service/nvnflinger/window.h      hle/service/olsc/olsc.cpp      hle/service/olsc/olsc.h +    hle/service/os/event.cpp +    hle/service/os/event.h +    hle/service/os/multi_wait_holder.cpp +    hle/service/os/multi_wait_holder.h +    hle/service/os/multi_wait_utils.h +    hle/service/os/multi_wait.cpp +    hle/service/os/multi_wait.h +    hle/service/os/mutex.cpp +    hle/service/os/mutex.h      hle/service/pcie/pcie.cpp      hle/service/pcie/pcie.h      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 @@  #include "common/math_util.h"  #include "core/hle/service/apm/apm_controller.h"  #include "core/hle/service/caps/caps_types.h" -#include "core/hle/service/event.h"  #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h"  #include "core/hle/service/service.h"  #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 @@  #include <memory>  #include <mutex> -#include "core/hle/service/event.h"  #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h"  union Result; 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 @@  #include "core/hle/service/glue/time/file_timestamp_worker.h"  #include "core/hle/service/glue/time/standard_steady_clock_resource.h"  #include "core/hle/service/glue/time/worker.h" +#include "core/hle/service/os/multi_wait_utils.h"  #include "core/hle/service/psc/time/common.h"  #include "core/hle/service/psc/time/service_manager.h"  #include "core/hle/service/psc/time/static.h" @@ -143,82 +144,46 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {      Common::SetCurrentThreadName("TimeWorker");      Common::SetCurrentThreadPriority(Common::ThreadPriority::Low); -    enum class EventType { -        Exit = 0, -        IpmModuleService_GetEvent = 1, -        PowerStateChange = 2, -        SignalAlarms = 3, -        UpdateLocalSystemClock = 4, -        UpdateNetworkSystemClock = 5, -        UpdateEphemeralSystemClock = 6, -        UpdateSteadyClock = 7, -        UpdateFileTimestamp = 8, -        AutoCorrect = 9, -        Max = 10, -    }; - -    s32 num_objs{}; -    std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{}; -    std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{}; - -    const auto AddWaiter{ -        [&](Kernel::KSynchronizationObject* synchronization_object, EventType type) { -            // Open a new reference to the object. -            synchronization_object->Open(); - -            // Insert into the list. -            wait_indices[num_objs] = type; -            wait_objs[num_objs++] = synchronization_object; -        }}; -      while (!stop_token.stop_requested()) { -        SCOPE_EXIT({ -            for (s32 i = 0; i < num_objs; i++) { -                wait_objs[i]->Close(); -            } -        }); +        enum class EventType : s32 { +            Exit = 0, +            PowerStateChange = 1, +            SignalAlarms = 2, +            UpdateLocalSystemClock = 3, +            UpdateNetworkSystemClock = 4, +            UpdateEphemeralSystemClock = 5, +            UpdateSteadyClock = 6, +            UpdateFileTimestamp = 7, +            AutoCorrect = 8, +        }; + +        s32 index{}; -        num_objs = {}; -        wait_objs = {};          if (m_pm_state_change_handler.m_priority != 0) { -            AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); -            // TODO -            // AddWaiter(gIPmModuleService::GetEvent(), 1); -            AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange); +            // TODO: gIPmModuleService::GetEvent() 1 +            index = WaitAny(m_system.Kernel(), +                            &m_event->GetReadableEvent(), // 0 +                            &m_alarm_worker.GetEvent()    // 1 +            );          } else { -            AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); -            // TODO -            // AddWaiter(gIPmModuleService::GetEvent(), 1); -            AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange); -            AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms); -            AddWaiter(m_local_clock_event, EventType::UpdateLocalSystemClock); -            AddWaiter(m_network_clock_event, EventType::UpdateNetworkSystemClock); -            AddWaiter(m_ephemeral_clock_event, EventType::UpdateEphemeralSystemClock); -            AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock); -            AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp); -            AddWaiter(m_standard_user_auto_correct_clock_event, EventType::AutoCorrect); +            // TODO: gIPmModuleService::GetEvent() 1 +            index = WaitAny(m_system.Kernel(), +                            &m_event->GetReadableEvent(),                       // 0 +                            &m_alarm_worker.GetEvent(),                         // 1 +                            &m_alarm_worker.GetTimerEvent().GetReadableEvent(), // 2 +                            m_local_clock_event,                                // 3 +                            m_network_clock_event,                              // 4 +                            m_ephemeral_clock_event,                            // 5 +                            &m_timer_steady_clock->GetReadableEvent(),          // 6 +                            &m_timer_file_system->GetReadableEvent(),           // 7 +                            m_standard_user_auto_correct_clock_event            // 8 +            );          } -        s32 out_index{-1}; -        Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), -                                             num_objs, -1); -        ASSERT(out_index >= 0 && out_index < num_objs); - -        if (stop_token.stop_requested()) { -            return; -        } - -        switch (wait_indices[out_index]) { +        switch (static_cast<EventType>(index)) {          case EventType::Exit:              return; -        case EventType::IpmModuleService_GetEvent: -            // TODO -            // IPmModuleService::GetEvent() -            // clear the event -            // Handle power state change event -            break; -          case EventType::PowerStateChange:              m_alarm_worker.GetEvent().Clear();              if (m_pm_state_change_handler.m_priority <= 1) { @@ -235,19 +200,19 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {              m_local_clock_event->Clear();              Service::PSC::Time::SystemClockContext context{}; -            auto res = m_local_clock->GetSystemClockContext(&context); -            ASSERT(res == ResultSuccess); +            R_ASSERT(m_local_clock->GetSystemClockContext(&context));              m_set_sys->SetUserSystemClockContext(context); -              m_file_timestamp_worker.SetFilesystemPosixTime(); -        } break; +            break; +        }          case EventType::UpdateNetworkSystemClock: {              m_network_clock_event->Clear(); +              Service::PSC::Time::SystemClockContext context{}; -            auto res = m_network_clock->GetSystemClockContext(&context); -            ASSERT(res == ResultSuccess); +            R_ASSERT(m_network_clock->GetSystemClockContext(&context)); +              m_set_sys->SetNetworkSystemClockContext(context);              s64 time{}; @@ -267,7 +232,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {              }              m_file_timestamp_worker.SetFilesystemPosixTime(); -        } break; +            break; +        }          case EventType::UpdateEphemeralSystemClock: {              m_ephemeral_clock_event->Clear(); @@ -295,7 +261,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {              if (!g_ig_report_ephemeral_clock_context_set) {                  g_ig_report_ephemeral_clock_context_set = true;              } -        } break; +            break; +        }          case EventType::UpdateSteadyClock:              m_timer_steady_clock->Clear(); @@ -314,21 +281,20 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {              m_standard_user_auto_correct_clock_event->Clear();              bool automatic_correction{}; -            auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( -                &automatic_correction); -            ASSERT(res == ResultSuccess); +            R_ASSERT(m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( +                &automatic_correction));              Service::PSC::Time::SteadyClockTimePoint time_point{}; -            res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point); -            ASSERT(res == ResultSuccess); +            R_ASSERT( +                m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point));              m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);              m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); -        } break; +            break; +        }          default:              UNREACHABLE(); -            break;          }      }  } 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 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include "core/hle/kernel/k_event.h" -#include "core/hle/service/event.h"  #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h"  namespace Service { 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_hardware_timer.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_common.h" +#include "core/hle/service/os/multi_wait.h" + +namespace Service { + +MultiWait::MultiWait() = default; +MultiWait::~MultiWait() = default; + +MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) { +    return this->TimedWaitImpl(kernel, -1); +} + +MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) { +    return this->TimedWaitImpl(kernel, 0); +} + +MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) { +    return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns); +} + +MultiWaitHolder* MultiWait::TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick) { +    std::array<MultiWaitHolder*, Kernel::Svc::ArgumentHandleCountMax> holders{}; +    std::array<Kernel::KSynchronizationObject*, Kernel::Svc::ArgumentHandleCountMax> objects{}; + +    s32 out_index = -1; +    s32 num_objects = 0; + +    for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it++) { +        ASSERT(num_objects < Kernel::Svc::ArgumentHandleCountMax); +        holders[num_objects] = std::addressof(*it); +        objects[num_objects] = it->GetNativeHandle(); +        num_objects++; +    } + +    Kernel::KSynchronizationObject::Wait(kernel, std::addressof(out_index), objects.data(), +                                         num_objects, timeout_tick); + +    if (out_index == -1) { +        return nullptr; +    } else { +        return holders[out_index]; +    } +} + +void MultiWait::MoveAll(MultiWait* other) { +    while (!other->m_wait_list.empty()) { +        MultiWaitHolder& holder = other->m_wait_list.front(); +        holder.UnlinkFromMultiWait(); +        holder.LinkToMultiWait(this); +    } +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/os/multi_wait_holder.h" + +namespace Kernel { +class KernelCore; +} + +namespace Service { + +class MultiWait final { +public: +    explicit MultiWait(); +    ~MultiWait(); + +public: +    MultiWaitHolder* WaitAny(Kernel::KernelCore& kernel); +    MultiWaitHolder* TryWaitAny(Kernel::KernelCore& kernel); +    MultiWaitHolder* TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns); +    // TODO: SdkReplyAndReceive? + +    void MoveAll(MultiWait* other); + +private: +    MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick); + +private: +    friend class MultiWaitHolder; +    using ListType = Common::IntrusiveListMemberTraits<&MultiWaitHolder::m_list_node>::ListType; +    ListType m_wait_list{}; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/os/multi_wait.h" +#include "core/hle/service/os/multi_wait_holder.h" + +namespace Service { + +void MultiWaitHolder::LinkToMultiWait(MultiWait* multi_wait) { +    if (m_multi_wait != nullptr) { +        UNREACHABLE(); +    } + +    m_multi_wait = multi_wait; +    m_multi_wait->m_wait_list.push_back(*this); +} + +void MultiWaitHolder::UnlinkFromMultiWait() { +    if (m_multi_wait) { +        m_multi_wait->m_wait_list.erase(m_multi_wait->m_wait_list.iterator_to(*this)); +        m_multi_wait = nullptr; +    } +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/intrusive_list.h" + +namespace Kernel { +class KSynchronizationObject; +} // namespace Kernel + +namespace Service { + +class MultiWait; + +class MultiWaitHolder { +public: +    explicit MultiWaitHolder(Kernel::KSynchronizationObject* native_handle) +        : m_native_handle(native_handle) {} + +    void LinkToMultiWait(MultiWait* multi_wait); +    void UnlinkFromMultiWait(); + +    void SetUserData(uintptr_t user_data) { +        m_user_data = user_data; +    } + +    uintptr_t GetUserData() const { +        return m_user_data; +    } + +    Kernel::KSynchronizationObject* GetNativeHandle() const { +        return m_native_handle; +    } + +private: +    friend class MultiWait; +    Common::IntrusiveListNode m_list_node{}; +    MultiWait* m_multi_wait{}; +    Kernel::KSynchronizationObject* m_native_handle{}; +    uintptr_t m_user_data{}; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/os/multi_wait.h" + +namespace Service { + +namespace impl { + +class AutoMultiWaitHolder { +private: +    MultiWaitHolder m_holder; + +public: +    template <typename T> +    explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) { +        m_holder.LinkToMultiWait(multi_wait); +    } + +    ~AutoMultiWaitHolder() { +        m_holder.UnlinkFromMultiWait(); +    } + +    std::pair<MultiWaitHolder*, int> ConvertResult(const std::pair<MultiWaitHolder*, int> result, +                                                   int index) { +        if (result.first == std::addressof(m_holder)) { +            return std::make_pair(static_cast<MultiWaitHolder*>(nullptr), index); +        } else { +            return result; +        } +    } +}; + +using WaitAnyFunction = decltype(&MultiWait::WaitAny); + +inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, +                                                    MultiWait* multi_wait, WaitAnyFunction func, +                                                    int) { +    return std::pair<MultiWaitHolder*, int>((multi_wait->*func)(kernel), -1); +} + +template <typename T, typename... Args> +inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, +                                                    MultiWait* multi_wait, WaitAnyFunction func, +                                                    int index, T&& x, Args&&... args) { +    AutoMultiWaitHolder holder(multi_wait, std::forward<T>(x)); +    return holder.ConvertResult( +        WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward<Args>(args)...), index); +} + +template <typename... Args> +inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, +                                                    MultiWait* multi_wait, WaitAnyFunction func, +                                                    Args&&... args) { +    return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward<Args>(args)...); +} + +template <typename... Args> +inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, +                                                    WaitAnyFunction func, Args&&... args) { +    MultiWait temp_multi_wait; +    return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0, +                       std::forward<Args>(args)...); +} + +class NotBoolButInt { +public: +    constexpr NotBoolButInt(int v) : m_value(v) {} +    constexpr operator int() const { +        return m_value; +    } +    explicit operator bool() const = delete; + +private: +    int m_value; +}; + +} // namespace impl + +template <typename... Args> +    requires(sizeof...(Args) > 0) +inline std::pair<MultiWaitHolder*, int> WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait, +                                                Args&&... args) { +    return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward<Args>(args)...); +} + +template <typename... Args> +    requires(sizeof...(Args) > 0) +inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) { +    return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward<Args>(args)...).second; +} + +template <typename... Args> +    requires(sizeof...(Args) > 0) +inline std::pair<MultiWaitHolder*, int> TryWaitAny(Kernel::KernelCore& kernel, +                                                   MultiWait* multi_wait, Args&&... args) { +    return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait, +                             std::forward<Args>(args)...); +} + +template <typename... Args> +    requires(sizeof...(Args) > 0) +inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) { +    return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward<Args>(args)...).second; +} + +} // 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 @@  #include "core/core.h"  #include "core/hle/kernel/k_event.h"  #include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/service/mutex.h" +#include "core/hle/service/os/mutex.h"  namespace Service { 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 @@  namespace Service { -constexpr size_t MaximumWaitObjects = 0x40; - -enum HandleType { +enum class UserDataTag {      Port,      Session,      DeferEvent, -    Event,  }; -ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_mutex{system} { +class Port : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Port> { +public: +    explicit Port(Kernel::KServerPort* server_port, SessionRequestHandlerFactory&& handler_factory) +        : MultiWaitHolder(server_port), m_handler_factory(std::move(handler_factory)) { +        this->SetUserData(static_cast<uintptr_t>(UserDataTag::Port)); +    } + +    ~Port() { +        this->GetNativeHandle()->Close(); +    } + +    SessionRequestHandlerPtr CreateHandler() { +        return m_handler_factory(); +    } + +private: +    const SessionRequestHandlerFactory m_handler_factory; +}; + +class Session : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Session> { +public: +    explicit Session(Kernel::KServerSession* server_session, +                     std::shared_ptr<SessionRequestManager>&& manager) +        : MultiWaitHolder(server_session), m_manager(std::move(manager)) { +        this->SetUserData(static_cast<uintptr_t>(UserDataTag::Session)); +    } + +    ~Session() { +        this->GetNativeHandle()->Close(); +    } + +    std::shared_ptr<SessionRequestManager>& GetManager() { +        return m_manager; +    } + +    std::shared_ptr<HLERequestContext>& GetContext() { +        return m_context; +    } + +private: +    std::shared_ptr<SessionRequestManager> m_manager; +    std::shared_ptr<HLERequestContext> m_context; +}; + +ServerManager::ServerManager(Core::System& system) : m_system{system}, m_selection_mutex{system} {      // Initialize event. -    m_event = Kernel::KEvent::Create(system.Kernel()); -    m_event->Initialize(nullptr); +    m_wakeup_event = Kernel::KEvent::Create(system.Kernel()); +    m_wakeup_event->Initialize(nullptr);      // Register event. -    Kernel::KEvent::Register(system.Kernel(), m_event); +    Kernel::KEvent::Register(system.Kernel(), m_wakeup_event); + +    // Link to holder. +    m_wakeup_holder.emplace(std::addressof(m_wakeup_event->GetReadableEvent())); +    m_wakeup_holder->LinkToMultiWait(std::addressof(m_deferred_list));  }  ServerManager::~ServerManager() {      // Signal stop.      m_stop_source.request_stop(); -    m_event->Signal(); +    m_wakeup_event->Signal();      // Wait for processing to stop.      m_stopped.Wait();      m_threads.clear(); -    // Clean up server ports. -    for (const auto& [port, handler] : m_ports) { -        port->Close(); +    // Clean up ports. +    for (auto it = m_servers.begin(); it != m_servers.end(); it = m_servers.erase(it)) { +        delete std::addressof(*it);      }      // Clean up sessions. -    for (const auto& [session, manager] : m_sessions) { -        session->Close(); -    } - -    for (const auto& request : m_deferrals) { -        request.session->Close(); +    for (auto it = m_sessions.begin(); it != m_sessions.end(); it = m_sessions.erase(it)) { +        delete std::addressof(*it);      } -    // Close event. -    m_event->GetReadableEvent().Close(); -    m_event->Close(); +    // Close wakeup event. +    m_wakeup_event->GetReadableEvent().Close(); +    m_wakeup_event->Close();      if (m_deferral_event) {          m_deferral_event->GetReadableEvent().Close(); @@ -75,19 +116,19 @@ void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {      server_manager->m_system.RunServer(std::move(server_manager));  } -Result ServerManager::RegisterSession(Kernel::KServerSession* session, +Result ServerManager::RegisterSession(Kernel::KServerSession* server_session,                                        std::shared_ptr<SessionRequestManager> manager) { -    ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); -      // We are taking ownership of the server session, so don't open it. +    auto* session = new Session(server_session, std::move(manager)); +      // Begin tracking the server session.      { -        std::scoped_lock ll{m_list_mutex}; -        m_sessions.emplace(session, std::move(manager)); +        std::scoped_lock ll{m_deferred_list_mutex}; +        m_sessions.push_back(*session);      } -    // Signal the wakeup event. -    m_event->Signal(); +    // Register to wait on the session. +    this->LinkToDeferredList(session);      R_SUCCEED();  } @@ -95,21 +136,22 @@ Result ServerManager::RegisterSession(Kernel::KServerSession* session,  Result ServerManager::RegisterNamedService(const std::string& service_name,                                             SessionRequestHandlerFactory&& handler_factory,                                             u32 max_sessions) { -    ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); -      // Add the new server to sm: and get the moved server port.      Kernel::KServerPort* server_port{};      R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name,                                                         max_sessions, handler_factory)); +    // We are taking ownership of the server port, so don't open it. +    auto* server = new Port(server_port, std::move(handler_factory)); +      // Begin tracking the server port.      { -        std::scoped_lock ll{m_list_mutex}; -        m_ports.emplace(server_port, std::move(handler_factory)); +        std::scoped_lock ll{m_deferred_list_mutex}; +        m_servers.push_back(*server);      } -    // Signal the wakeup event. -    m_event->Signal(); +    // Register to wait on the server port. +    this->LinkToDeferredList(server);      R_SUCCEED();  } @@ -127,8 +169,6 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,  Result ServerManager::ManageNamedPort(const std::string& service_name,                                        SessionRequestHandlerFactory&& handler_factory,                                        u32 max_sessions) { -    ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); -      // Create a new port.      auto* port = Kernel::KPort::Create(m_system.Kernel());      port->Initialize(max_sessions, false, 0); @@ -149,12 +189,18 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,      // Open a new reference to the server port.      port->GetServerPort().Open(); -    // Begin tracking the server port. +    // Transfer ownership into a new port object. +    auto* server = new Port(std::addressof(port->GetServerPort()), std::move(handler_factory)); + +    // Begin tracking the port.      { -        std::scoped_lock ll{m_list_mutex}; -        m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); +        std::scoped_lock ll{m_deferred_list_mutex}; +        m_servers.push_back(*server);      } +    // Register to wait on the port. +    this->LinkToDeferredList(server); +      // We succeeded.      R_SUCCEED();  } @@ -173,6 +219,11 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {      // Set the output.      *out_event = m_deferral_event; +    // Register to wait on the event. +    m_deferral_holder.emplace(std::addressof(m_deferral_event->GetReadableEvent())); +    m_deferral_holder->SetUserData(static_cast<uintptr_t>(UserDataTag::DeferEvent)); +    this->LinkToDeferredList(std::addressof(*m_deferral_holder)); +      // We succeeded.      R_SUCCEED();  } @@ -191,270 +242,185 @@ Result ServerManager::LoopProcess() {      R_RETURN(this->LoopProcessImpl());  } -Result ServerManager::LoopProcessImpl() { -    while (!m_stop_source.stop_requested()) { -        R_TRY(this->WaitAndProcessImpl()); +void ServerManager::LinkToDeferredList(MultiWaitHolder* holder) { +    // Link. +    { +        std::scoped_lock lk{m_deferred_list_mutex}; +        holder->LinkToMultiWait(std::addressof(m_deferred_list));      } -    R_SUCCEED(); +    // Signal the wakeup event. +    m_wakeup_event->Signal();  } -Result ServerManager::WaitAndProcessImpl() { -    Kernel::KScopedAutoObject<Kernel::KSynchronizationObject> wait_obj; -    HandleType wait_type{}; +void ServerManager::LinkDeferred() { +    std::scoped_lock lk{m_deferred_list_mutex}; +    m_multi_wait.MoveAll(std::addressof(m_deferred_list)); +} +MultiWaitHolder* ServerManager::WaitSignaled() {      // Ensure we are the only thread waiting for this server. -    std::unique_lock sl{m_serve_mutex}; +    std::scoped_lock lk{m_selection_mutex}; -    // If we're done, return before we start waiting. -    R_SUCCEED_IF(m_stop_source.stop_requested()); +    while (true) { +        this->LinkDeferred(); -    // Wait for a tracked object to become signaled. -    { -        s32 num_objs{}; -        std::array<HandleType, MaximumWaitObjects> wait_types{}; -        std::array<Kernel::KSynchronizationObject*, MaximumWaitObjects> wait_objs{}; - -        const auto AddWaiter{ -            [&](Kernel::KSynchronizationObject* synchronization_object, HandleType type) { -                // Open a new reference to the object. -                synchronization_object->Open(); - -                // Insert into the list. -                wait_types[num_objs] = type; -                wait_objs[num_objs++] = synchronization_object; -            }}; - -        { -            std::scoped_lock ll{m_list_mutex}; - -            // Add all of our ports. -            for (const auto& [port, handler] : m_ports) { -                AddWaiter(port, HandleType::Port); -            } - -            // Add all of our sessions. -            for (const auto& [session, manager] : m_sessions) { -                AddWaiter(session, HandleType::Session); -            } +        // If we're done, return before we start waiting. +        if (m_stop_source.stop_requested()) { +            return nullptr;          } -        // Add the deferral wakeup event. -        if (m_deferral_event != nullptr) { -            AddWaiter(std::addressof(m_deferral_event->GetReadableEvent()), HandleType::DeferEvent); +        auto* selected = m_multi_wait.WaitAny(m_system.Kernel()); +        if (selected == std::addressof(*m_wakeup_holder)) { +            // Clear and restart if we were woken up. +            m_wakeup_event->Clear(); +        } else { +            // Unlink and handle the event. +            selected->UnlinkFromMultiWait(); +            return selected;          } +    } +} -        // Add the wakeup event. -        AddWaiter(std::addressof(m_event->GetReadableEvent()), HandleType::Event); - -        // Clean up extra references on exit. -        SCOPE_EXIT({ -            for (s32 i = 0; i < num_objs; i++) { -                wait_objs[i]->Close(); -            } -        }); - -        // Wait for a signal. -        s32 out_index{-1}; -        R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, -                                                         wait_objs.data(), num_objs, -1)) { -            R_CATCH(Kernel::ResultSessionClosed) { -                // On session closed, index is updated and we don't want to return an error. -            } -        } -        R_END_TRY_CATCH; -        ASSERT(out_index >= 0 && out_index < num_objs); +Result ServerManager::Process(MultiWaitHolder* holder) { +    switch (static_cast<UserDataTag>(holder->GetUserData())) { +    case UserDataTag::Session: +        R_RETURN(this->OnSessionEvent(static_cast<Session*>(holder))); +    case UserDataTag::Port: +        R_RETURN(this->OnPortEvent(static_cast<Port*>(holder))); +    case UserDataTag::DeferEvent: +        R_RETURN(this->OnDeferralEvent()); +    default: +        UNREACHABLE(); +    } +} -        // Set the output index. -        wait_obj = wait_objs[out_index]; -        wait_type = wait_types[out_index]; +bool ServerManager::WaitAndProcessImpl() { +    if (auto* signaled_holder = this->WaitSignaled(); signaled_holder != nullptr) { +        R_ASSERT(this->Process(signaled_holder)); +        return true; +    } else { +        return false;      } +} -    // Process what we just received, temporarily removing the object so it is -    // not processed concurrently by another thread. -    { -        switch (wait_type) { -        case HandleType::Port: { -            // Port signaled. -            auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>(); -            SessionRequestHandlerFactory handler_factory; - -            // Remove from tracking. -            { -                std::scoped_lock ll{m_list_mutex}; -                ASSERT(m_ports.contains(port)); -                m_ports.at(port).swap(handler_factory); -                m_ports.erase(port); -            } - -            // Allow other threads to serve. -            sl.unlock(); - -            // Finish. -            R_RETURN(this->OnPortEvent(port, std::move(handler_factory))); -        } -        case HandleType::Session: { -            // Session signaled. -            auto* session = wait_obj->DynamicCast<Kernel::KServerSession*>(); -            std::shared_ptr<SessionRequestManager> manager; - -            // Remove from tracking. -            { -                std::scoped_lock ll{m_list_mutex}; -                ASSERT(m_sessions.contains(session)); -                m_sessions.at(session).swap(manager); -                m_sessions.erase(session); -            } - -            // Allow other threads to serve. -            sl.unlock(); - -            // Finish. -            R_RETURN(this->OnSessionEvent(session, std::move(manager))); -        } -        case HandleType::DeferEvent: { -            // Clear event. -            ASSERT(R_SUCCEEDED(m_deferral_event->Clear())); - -            // Drain the list of deferrals while we process. -            std::list<RequestState> deferrals; -            { -                std::scoped_lock ll{m_list_mutex}; -                m_deferrals.swap(deferrals); -            } - -            // Allow other threads to serve. -            sl.unlock(); - -            // Finish. -            R_RETURN(this->OnDeferralEvent(std::move(deferrals))); -        } -        case HandleType::Event: { -            // Clear event and finish. -            R_RETURN(m_event->Clear()); -        } -        default: { -            UNREACHABLE(); -        } -        } +Result ServerManager::LoopProcessImpl() { +    while (!m_stop_source.stop_requested()) { +        this->WaitAndProcessImpl();      } + +    R_SUCCEED();  } -Result ServerManager::OnPortEvent(Kernel::KServerPort* port, -                                  SessionRequestHandlerFactory&& handler_factory) { +Result ServerManager::OnPortEvent(Port* server) {      // Accept a new server session. -    Kernel::KServerSession* session = port->AcceptSession(); -    ASSERT(session != nullptr); +    auto* server_port = static_cast<Kernel::KServerPort*>(server->GetNativeHandle()); +    Kernel::KServerSession* server_session = server_port->AcceptSession(); +    ASSERT(server_session != nullptr);      // Create the session manager and install the handler.      auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this); -    manager->SetSessionHandler(handler_factory()); +    manager->SetSessionHandler(server->CreateHandler()); -    // Track the server session. -    { -        std::scoped_lock ll{m_list_mutex}; -        m_ports.emplace(port, std::move(handler_factory)); -        m_sessions.emplace(session, std::move(manager)); -    } +    // Create and register the new session. +    this->RegisterSession(server_session, std::move(manager)); -    // Signal the wakeup event. -    m_event->Signal(); +    // Resume tracking the port. +    this->LinkToDeferredList(server);      // We succeeded.      R_SUCCEED();  } -Result ServerManager::OnSessionEvent(Kernel::KServerSession* session, -                                     std::shared_ptr<SessionRequestManager>&& manager) { -    Result rc{ResultSuccess}; +Result ServerManager::OnSessionEvent(Session* session) { +    Result res = ResultSuccess;      // Try to receive a message. -    std::shared_ptr<HLERequestContext> context; -    rc = session->ReceiveRequestHLE(&context, manager); +    auto* server_session = static_cast<Kernel::KServerSession*>(session->GetNativeHandle()); +    res = server_session->ReceiveRequestHLE(&session->GetContext(), session->GetManager());      // If the session has been closed, we're done. -    if (rc == Kernel::ResultSessionClosed) { -        // Close the session. -        session->Close(); - -        // Finish. +    if (res == Kernel::ResultSessionClosed) { +        this->DestroySession(session);          R_SUCCEED();      } -    ASSERT(R_SUCCEEDED(rc)); -    RequestState request{ -        .session = session, -        .context = std::move(context), -        .manager = std::move(manager), -    }; +    R_ASSERT(res);      // Complete the sync request with deferral handling. -    R_RETURN(this->CompleteSyncRequest(std::move(request))); +    R_RETURN(this->CompleteSyncRequest(session));  } -Result ServerManager::CompleteSyncRequest(RequestState&& request) { -    Result rc{ResultSuccess}; -    Result service_rc{ResultSuccess}; +Result ServerManager::CompleteSyncRequest(Session* session) { +    Result res = ResultSuccess; +    Result service_res = ResultSuccess;      // Mark the request as not deferred. -    request.context->SetIsDeferred(false); +    session->GetContext()->SetIsDeferred(false);      // Complete the request. We have exclusive access to this session. -    service_rc = request.manager->CompleteSyncRequest(request.session, *request.context); +    auto* server_session = static_cast<Kernel::KServerSession*>(session->GetNativeHandle()); +    service_res = +        session->GetManager()->CompleteSyncRequest(server_session, *session->GetContext());      // If we've been deferred, we're done. -    if (request.context->GetIsDeferred()) { -        // Insert into deferral list. -        std::scoped_lock ll{m_list_mutex}; -        m_deferrals.emplace_back(std::move(request)); +    if (session->GetContext()->GetIsDeferred()) { +        // Insert into deferred session list. +        std::scoped_lock ll{m_deferred_list_mutex}; +        m_deferred_sessions.push_back(session);          // Finish.          R_SUCCEED();      }      // Send the reply. -    rc = request.session->SendReplyHLE(); +    res = server_session->SendReplyHLE();      // If the session has been closed, we're done. -    if (rc == Kernel::ResultSessionClosed || service_rc == IPC::ResultSessionClosed) { -        // Close the session. -        request.session->Close(); - -        // Finish. +    if (res == Kernel::ResultSessionClosed || service_res == IPC::ResultSessionClosed) { +        this->DestroySession(session);          R_SUCCEED();      } -    ASSERT(R_SUCCEEDED(rc)); -    ASSERT(R_SUCCEEDED(service_rc)); - -    // Reinsert the session. -    { -        std::scoped_lock ll{m_list_mutex}; -        m_sessions.emplace(request.session, std::move(request.manager)); -    } +    R_ASSERT(res); +    R_ASSERT(service_res); -    // Signal the wakeup event. -    m_event->Signal(); +    // We succeeded, so we can process future messages on this session. +    this->LinkToDeferredList(session); -    // We succeeded.      R_SUCCEED();  } -Result ServerManager::OnDeferralEvent(std::list<RequestState>&& deferrals) { -    ON_RESULT_FAILURE { -        std::scoped_lock ll{m_list_mutex}; -        m_deferrals.splice(m_deferrals.end(), deferrals); -    }; +Result ServerManager::OnDeferralEvent() { +    // Clear event before grabbing the list. +    m_deferral_event->Clear(); -    while (!deferrals.empty()) { -        RequestState request = deferrals.front(); -        deferrals.pop_front(); +    // Get and clear list. +    const auto deferrals = [&] { +        std::scoped_lock lk{m_deferred_list_mutex}; +        return std::move(m_deferred_sessions); +    }(); -        // Try again to complete the request. -        R_TRY(this->CompleteSyncRequest(std::move(request))); +    // Relink deferral event. +    this->LinkToDeferredList(std::addressof(*m_deferral_holder)); + +    // For each session, try again to complete the request. +    for (auto* session : deferrals) { +        R_ASSERT(this->CompleteSyncRequest(session));      }      R_SUCCEED();  } +void ServerManager::DestroySession(Session* session) { +    // Unlink. +    { +        std::scoped_lock lk{m_deferred_list_mutex}; +        m_sessions.erase(m_sessions.iterator_to(*session)); +    } + +    // Free the session. +    delete session; +} +  } // 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 @@  #pragma once -#include <functional>  #include <list> -#include <map>  #include <mutex> -#include <string_view> +#include <optional>  #include <vector>  #include "common/polyfill_thread.h"  #include "common/thread.h"  #include "core/hle/result.h"  #include "core/hle/service/hle_ipc.h" -#include "core/hle/service/mutex.h" +#include "core/hle/service/os/multi_wait.h" +#include "core/hle/service/os/mutex.h"  namespace Core {  class System; @@ -24,11 +23,13 @@ namespace Kernel {  class KEvent;  class KServerPort;  class KServerSession; -class KSynchronizationObject;  } // namespace Kernel  namespace Service { +class Port; +class Session; +  class ServerManager {  public:      explicit ServerManager(Core::System& system); @@ -52,34 +53,40 @@ public:      static void RunServer(std::unique_ptr<ServerManager>&& server);  private: -    struct RequestState; - +    void LinkToDeferredList(MultiWaitHolder* holder); +    void LinkDeferred(); +    MultiWaitHolder* WaitSignaled(); +    Result Process(MultiWaitHolder* holder); +    bool WaitAndProcessImpl();      Result LoopProcessImpl(); -    Result WaitAndProcessImpl(); -    Result OnPortEvent(Kernel::KServerPort* port, SessionRequestHandlerFactory&& handler_factory); -    Result OnSessionEvent(Kernel::KServerSession* session, -                          std::shared_ptr<SessionRequestManager>&& manager); -    Result OnDeferralEvent(std::list<RequestState>&& deferrals); -    Result CompleteSyncRequest(RequestState&& state); + +    Result OnPortEvent(Port* port); +    Result OnSessionEvent(Session* session); +    Result OnDeferralEvent(); +    Result CompleteSyncRequest(Session* session); + +private: +    void DestroySession(Session* session);  private:      Core::System& m_system; -    Mutex m_serve_mutex; -    std::mutex m_list_mutex; +    Mutex m_selection_mutex; -    // Guest state tracking -    std::map<Kernel::KServerPort*, SessionRequestHandlerFactory> m_ports{}; -    std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{}; -    Kernel::KEvent* m_event{}; +    // Events +    Kernel::KEvent* m_wakeup_event{};      Kernel::KEvent* m_deferral_event{}; -    // Deferral tracking -    struct RequestState { -        Kernel::KServerSession* session; -        std::shared_ptr<HLERequestContext> context; -        std::shared_ptr<SessionRequestManager> manager; -    }; -    std::list<RequestState> m_deferrals{}; +    // Deferred wait list +    std::mutex m_deferred_list_mutex{}; +    MultiWait m_deferred_list{}; + +    // Guest state tracking +    MultiWait m_multi_wait{}; +    Common::IntrusiveListBaseTraits<Port>::ListType m_servers{}; +    Common::IntrusiveListBaseTraits<Session>::ListType m_sessions{}; +    std::list<Session*> m_deferred_sessions{}; +    std::optional<MultiWaitHolder> m_wakeup_holder{}; +    std::optional<MultiWaitHolder> m_deferral_holder{};      // Host state tracking      Common::Event m_stopped{}; | 
