diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/service_thread.cpp | 100 | ||||
| -rw-r--r-- | src/core/hle/kernel/service_thread.h | 27 |
6 files changed, 140 insertions, 23 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 59bd3d2a6..87712a3ce 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -202,6 +202,8 @@ add_library(core STATIC | |||
| 202 | hle/kernel/server_port.h | 202 | hle/kernel/server_port.h |
| 203 | hle/kernel/server_session.cpp | 203 | hle/kernel/server_session.cpp |
| 204 | hle/kernel/server_session.h | 204 | hle/kernel/server_session.h |
| 205 | hle/kernel/service_thread.cpp | ||
| 206 | hle/kernel/service_thread.h | ||
| 205 | hle/kernel/session.cpp | 207 | hle/kernel/session.cpp |
| 206 | hle/kernel/session.h | 208 | hle/kernel/session.h |
| 207 | hle/kernel/shared_memory.cpp | 209 | hle/kernel/shared_memory.cpp |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 04cae3a43..1bf4c3355 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -329,7 +329,7 @@ struct KernelCore::Impl { | |||
| 329 | std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; | 329 | std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; |
| 330 | 330 | ||
| 331 | // Number of host threads is a relatively high number to avoid overflowing | 331 | // Number of host threads is a relatively high number to avoid overflowing |
| 332 | static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64; | 332 | static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 1024; |
| 333 | std::atomic<size_t> num_host_threads{0}; | 333 | std::atomic<size_t> num_host_threads{0}; |
| 334 | std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS> | 334 | std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS> |
| 335 | register_host_thread_keys{}; | 335 | register_host_thread_keys{}; |
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index a35c8aa4b..079c3911a 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -32,12 +32,9 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern | |||
| 32 | std::string name) { | 32 | std::string name) { |
| 33 | std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; | 33 | std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; |
| 34 | 34 | ||
| 35 | session->request_event = | ||
| 36 | Core::Timing::CreateEvent(name, [session](std::uintptr_t, std::chrono::nanoseconds) { | ||
| 37 | session->CompleteSyncRequest(); | ||
| 38 | }); | ||
| 39 | session->name = std::move(name); | 35 | session->name = std::move(name); |
| 40 | session->parent = std::move(parent); | 36 | session->parent = std::move(parent); |
| 37 | session->service_thread = std::make_unique<ServiceThread>(kernel); | ||
| 41 | 38 | ||
| 42 | return MakeResult(std::move(session)); | 39 | return MakeResult(std::move(session)); |
| 43 | } | 40 | } |
| @@ -142,16 +139,12 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, | |||
| 142 | std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread)); | 139 | std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread)); |
| 143 | 140 | ||
| 144 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | 141 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); |
| 145 | request_queue.Push(std::move(context)); | 142 | service_thread->QueueSyncRequest(*this, std::move(context)); |
| 146 | 143 | ||
| 147 | return RESULT_SUCCESS; | 144 | return RESULT_SUCCESS; |
| 148 | } | 145 | } |
| 149 | 146 | ||
| 150 | ResultCode ServerSession::CompleteSyncRequest() { | 147 | ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { |
| 151 | ASSERT(!request_queue.Empty()); | ||
| 152 | |||
| 153 | auto& context = *request_queue.Front(); | ||
| 154 | |||
| 155 | ResultCode result = RESULT_SUCCESS; | 148 | ResultCode result = RESULT_SUCCESS; |
| 156 | // If the session has been converted to a domain, handle the domain request | 149 | // If the session has been converted to a domain, handle the domain request |
| 157 | if (IsDomain() && context.HasDomainMessageHeader()) { | 150 | if (IsDomain() && context.HasDomainMessageHeader()) { |
| @@ -177,18 +170,13 @@ ResultCode ServerSession::CompleteSyncRequest() { | |||
| 177 | } | 170 | } |
| 178 | } | 171 | } |
| 179 | 172 | ||
| 180 | request_queue.Pop(); | ||
| 181 | |||
| 182 | return result; | 173 | return result; |
| 183 | } | 174 | } |
| 184 | 175 | ||
| 185 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | 176 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, |
| 186 | Core::Memory::Memory& memory, | 177 | Core::Memory::Memory& memory, |
| 187 | Core::Timing::CoreTiming& core_timing) { | 178 | Core::Timing::CoreTiming& core_timing) { |
| 188 | const ResultCode result = QueueSyncRequest(std::move(thread), memory); | 179 | return QueueSyncRequest(std::move(thread), memory); |
| 189 | const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000}; | ||
| 190 | core_timing.ScheduleEvent(delay, request_event, {}); | ||
| 191 | return result; | ||
| 192 | } | 180 | } |
| 193 | 181 | ||
| 194 | } // namespace Kernel | 182 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index d23e9ec68..8466b03e6 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "common/threadsafe_queue.h" | 12 | #include "common/threadsafe_queue.h" |
| 13 | #include "core/hle/kernel/service_thread.h" | ||
| 13 | #include "core/hle/kernel/synchronization_object.h" | 14 | #include "core/hle/kernel/synchronization_object.h" |
| 14 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 15 | 16 | ||
| @@ -43,6 +44,8 @@ class Thread; | |||
| 43 | * TLS buffer and control is transferred back to it. | 44 | * TLS buffer and control is transferred back to it. |
| 44 | */ | 45 | */ |
| 45 | class ServerSession final : public SynchronizationObject { | 46 | class ServerSession final : public SynchronizationObject { |
| 47 | friend class ServiceThread; | ||
| 48 | |||
| 46 | public: | 49 | public: |
| 47 | explicit ServerSession(KernelCore& kernel); | 50 | explicit ServerSession(KernelCore& kernel); |
| 48 | ~ServerSession() override; | 51 | ~ServerSession() override; |
| @@ -132,7 +135,7 @@ private: | |||
| 132 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); | 135 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); |
| 133 | 136 | ||
| 134 | /// Completes a sync request from the emulated application. | 137 | /// Completes a sync request from the emulated application. |
| 135 | ResultCode CompleteSyncRequest(); | 138 | ResultCode CompleteSyncRequest(HLERequestContext& context); |
| 136 | 139 | ||
| 137 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an | 140 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an |
| 138 | /// object handle. | 141 | /// object handle. |
| @@ -163,11 +166,8 @@ private: | |||
| 163 | /// The name of this session (optional) | 166 | /// The name of this session (optional) |
| 164 | std::string name; | 167 | std::string name; |
| 165 | 168 | ||
| 166 | /// Core timing event used to schedule the service request at some point in the future | 169 | /// Thread to dispatch service requests |
| 167 | std::shared_ptr<Core::Timing::EventType> request_event; | 170 | std::unique_ptr<ServiceThread> service_thread; |
| 168 | |||
| 169 | /// Queue of scheduled service requests | ||
| 170 | Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue; | ||
| 171 | }; | 171 | }; |
| 172 | 172 | ||
| 173 | } // namespace Kernel | 173 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp new file mode 100644 index 000000000..59a6045df --- /dev/null +++ b/src/core/hle/kernel/service_thread.cpp | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <condition_variable> | ||
| 6 | #include <functional> | ||
| 7 | #include <mutex> | ||
| 8 | #include <thread> | ||
| 9 | #include <vector> | ||
| 10 | #include <queue> | ||
| 11 | |||
| 12 | #include "common/assert.h" | ||
| 13 | #include "common/scope_exit.h" | ||
| 14 | #include "core/core.h" | ||
| 15 | #include "core/hle/kernel/kernel.h" | ||
| 16 | #include "core/hle/kernel/server_session.h" | ||
| 17 | #include "core/hle/kernel/service_thread.h" | ||
| 18 | #include "core/hle/lock.h" | ||
| 19 | #include "video_core/renderer_base.h" | ||
| 20 | |||
| 21 | namespace Kernel { | ||
| 22 | |||
| 23 | class ServiceThread::Impl final { | ||
| 24 | public: | ||
| 25 | explicit Impl(KernelCore& kernel); | ||
| 26 | ~Impl(); | ||
| 27 | |||
| 28 | void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); | ||
| 29 | |||
| 30 | private: | ||
| 31 | std::vector<std::thread> threads; | ||
| 32 | std::queue<std::function<void()>> requests; | ||
| 33 | std::mutex queue_mutex; | ||
| 34 | std::condition_variable condition; | ||
| 35 | bool stop{}; | ||
| 36 | }; | ||
| 37 | |||
| 38 | ServiceThread::Impl::Impl(KernelCore& kernel) { | ||
| 39 | constexpr std::size_t SizeOfPool{1}; | ||
| 40 | for (std::size_t i = 0; i < SizeOfPool; ++i) | ||
| 41 | threads.emplace_back([&] { | ||
| 42 | // Wait for first request before trying to acquire a render context | ||
| 43 | { | ||
| 44 | std::unique_lock lock{queue_mutex}; | ||
| 45 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | ||
| 46 | } | ||
| 47 | |||
| 48 | kernel.RegisterHostThread(); | ||
| 49 | |||
| 50 | while (true) { | ||
| 51 | std::function<void()> task; | ||
| 52 | |||
| 53 | { | ||
| 54 | std::unique_lock lock{queue_mutex}; | ||
| 55 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | ||
| 56 | if (stop && requests.empty()) { | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | task = std::move(requests.front()); | ||
| 60 | requests.pop(); | ||
| 61 | } | ||
| 62 | |||
| 63 | task(); | ||
| 64 | } | ||
| 65 | }); | ||
| 66 | } | ||
| 67 | |||
| 68 | void ServiceThread::Impl::QueueSyncRequest(ServerSession& session, | ||
| 69 | std::shared_ptr<HLERequestContext>&& context) { | ||
| 70 | { | ||
| 71 | std::unique_lock lock{queue_mutex}; | ||
| 72 | requests.emplace([session{SharedFrom(&session)}, context{std::move(context)}]() { | ||
| 73 | session->CompleteSyncRequest(*context); | ||
| 74 | return; | ||
| 75 | }); | ||
| 76 | } | ||
| 77 | condition.notify_one(); | ||
| 78 | } | ||
| 79 | |||
| 80 | ServiceThread::Impl::~Impl() { | ||
| 81 | { | ||
| 82 | std::unique_lock lock{queue_mutex}; | ||
| 83 | stop = true; | ||
| 84 | } | ||
| 85 | condition.notify_all(); | ||
| 86 | for (std::thread& thread : threads) { | ||
| 87 | thread.join(); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | ServiceThread::ServiceThread(KernelCore& kernel) : impl{std::make_unique<Impl>(kernel)} {} | ||
| 92 | |||
| 93 | ServiceThread::~ServiceThread() = default; | ||
| 94 | |||
| 95 | void ServiceThread::QueueSyncRequest(ServerSession& session, | ||
| 96 | std::shared_ptr<HLERequestContext>&& context) { | ||
| 97 | impl->QueueSyncRequest(session, std::move(context)); | ||
| 98 | } | ||
| 99 | |||
| 100 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h new file mode 100644 index 000000000..d252490bb --- /dev/null +++ b/src/core/hle/kernel/service_thread.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | class HLERequestContext; | ||
| 12 | class KernelCore; | ||
| 13 | class ServerSession; | ||
| 14 | |||
| 15 | class ServiceThread final { | ||
| 16 | public: | ||
| 17 | explicit ServiceThread(KernelCore& kernel); | ||
| 18 | ~ServiceThread(); | ||
| 19 | |||
| 20 | void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); | ||
| 21 | |||
| 22 | private: | ||
| 23 | class Impl; | ||
| 24 | std::unique_ptr<Impl> impl; | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace Kernel | ||