mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-07-04 23:31:19 +01:00
core: hle: server_session: Use separate threads for each service connection.
This commit is contained in:
parent
7dbdda908c
commit
28281ae250
6 changed files with 140 additions and 23 deletions
|
@ -202,6 +202,8 @@ add_library(core STATIC
|
||||||
hle/kernel/server_port.h
|
hle/kernel/server_port.h
|
||||||
hle/kernel/server_session.cpp
|
hle/kernel/server_session.cpp
|
||||||
hle/kernel/server_session.h
|
hle/kernel/server_session.h
|
||||||
|
hle/kernel/service_thread.cpp
|
||||||
|
hle/kernel/service_thread.h
|
||||||
hle/kernel/session.cpp
|
hle/kernel/session.cpp
|
||||||
hle/kernel/session.h
|
hle/kernel/session.h
|
||||||
hle/kernel/shared_memory.cpp
|
hle/kernel/shared_memory.cpp
|
||||||
|
|
|
@ -329,7 +329,7 @@ struct KernelCore::Impl {
|
||||||
std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
|
std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
|
||||||
|
|
||||||
// Number of host threads is a relatively high number to avoid overflowing
|
// Number of host threads is a relatively high number to avoid overflowing
|
||||||
static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
|
static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 1024;
|
||||||
std::atomic<size_t> num_host_threads{0};
|
std::atomic<size_t> num_host_threads{0};
|
||||||
std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
|
std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
|
||||||
register_host_thread_keys{};
|
register_host_thread_keys{};
|
||||||
|
|
|
@ -32,12 +32,9 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
|
||||||
std::string name) {
|
std::string name) {
|
||||||
std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
|
std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
|
||||||
|
|
||||||
session->request_event =
|
|
||||||
Core::Timing::CreateEvent(name, [session](std::uintptr_t, std::chrono::nanoseconds) {
|
|
||||||
session->CompleteSyncRequest();
|
|
||||||
});
|
|
||||||
session->name = std::move(name);
|
session->name = std::move(name);
|
||||||
session->parent = std::move(parent);
|
session->parent = std::move(parent);
|
||||||
|
session->service_thread = std::make_unique<ServiceThread>(kernel);
|
||||||
|
|
||||||
return MakeResult(std::move(session));
|
return MakeResult(std::move(session));
|
||||||
}
|
}
|
||||||
|
@ -142,16 +139,12 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
|
||||||
std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
|
std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
|
||||||
|
|
||||||
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
||||||
request_queue.Push(std::move(context));
|
service_thread->QueueSyncRequest(*this, std::move(context));
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ServerSession::CompleteSyncRequest() {
|
ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
||||||
ASSERT(!request_queue.Empty());
|
|
||||||
|
|
||||||
auto& context = *request_queue.Front();
|
|
||||||
|
|
||||||
ResultCode result = RESULT_SUCCESS;
|
ResultCode result = RESULT_SUCCESS;
|
||||||
// If the session has been converted to a domain, handle the domain request
|
// If the session has been converted to a domain, handle the domain request
|
||||||
if (IsDomain() && context.HasDomainMessageHeader()) {
|
if (IsDomain() && context.HasDomainMessageHeader()) {
|
||||||
|
@ -177,18 +170,13 @@ ResultCode ServerSession::CompleteSyncRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
request_queue.Pop();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
|
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
|
||||||
Core::Memory::Memory& memory,
|
Core::Memory::Memory& memory,
|
||||||
Core::Timing::CoreTiming& core_timing) {
|
Core::Timing::CoreTiming& core_timing) {
|
||||||
const ResultCode result = QueueSyncRequest(std::move(thread), memory);
|
return QueueSyncRequest(std::move(thread), memory);
|
||||||
const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000};
|
|
||||||
core_timing.ScheduleEvent(delay, request_event, {});
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/threadsafe_queue.h"
|
#include "common/threadsafe_queue.h"
|
||||||
|
#include "core/hle/kernel/service_thread.h"
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
@ -43,6 +44,8 @@ class Thread;
|
||||||
* TLS buffer and control is transferred back to it.
|
* TLS buffer and control is transferred back to it.
|
||||||
*/
|
*/
|
||||||
class ServerSession final : public SynchronizationObject {
|
class ServerSession final : public SynchronizationObject {
|
||||||
|
friend class ServiceThread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ServerSession(KernelCore& kernel);
|
explicit ServerSession(KernelCore& kernel);
|
||||||
~ServerSession() override;
|
~ServerSession() override;
|
||||||
|
@ -132,7 +135,7 @@ private:
|
||||||
ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
|
ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
|
||||||
|
|
||||||
/// Completes a sync request from the emulated application.
|
/// Completes a sync request from the emulated application.
|
||||||
ResultCode CompleteSyncRequest();
|
ResultCode CompleteSyncRequest(HLERequestContext& context);
|
||||||
|
|
||||||
/// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
|
/// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
|
||||||
/// object handle.
|
/// object handle.
|
||||||
|
@ -163,11 +166,8 @@ private:
|
||||||
/// The name of this session (optional)
|
/// The name of this session (optional)
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
/// Core timing event used to schedule the service request at some point in the future
|
/// Thread to dispatch service requests
|
||||||
std::shared_ptr<Core::Timing::EventType> request_event;
|
std::unique_ptr<ServiceThread> service_thread;
|
||||||
|
|
||||||
/// Queue of scheduled service requests
|
|
||||||
Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
100
src/core/hle/kernel/service_thread.cpp
Normal file
100
src/core/hle/kernel/service_thread.cpp
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
// Copyright 2020 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/server_session.h"
|
||||||
|
#include "core/hle/kernel/service_thread.h"
|
||||||
|
#include "core/hle/lock.h"
|
||||||
|
#include "video_core/renderer_base.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class ServiceThread::Impl final {
|
||||||
|
public:
|
||||||
|
explicit Impl(KernelCore& kernel);
|
||||||
|
~Impl();
|
||||||
|
|
||||||
|
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
std::queue<std::function<void()>> requests;
|
||||||
|
std::mutex queue_mutex;
|
||||||
|
std::condition_variable condition;
|
||||||
|
bool stop{};
|
||||||
|
};
|
||||||
|
|
||||||
|
ServiceThread::Impl::Impl(KernelCore& kernel) {
|
||||||
|
constexpr std::size_t SizeOfPool{1};
|
||||||
|
for (std::size_t i = 0; i < SizeOfPool; ++i)
|
||||||
|
threads.emplace_back([&] {
|
||||||
|
// Wait for first request before trying to acquire a render context
|
||||||
|
{
|
||||||
|
std::unique_lock lock{queue_mutex};
|
||||||
|
condition.wait(lock, [this] { return stop || !requests.empty(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel.RegisterHostThread();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
std::function<void()> task;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock lock{queue_mutex};
|
||||||
|
condition.wait(lock, [this] { return stop || !requests.empty(); });
|
||||||
|
if (stop && requests.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
task = std::move(requests.front());
|
||||||
|
requests.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
task();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServiceThread::Impl::QueueSyncRequest(ServerSession& session,
|
||||||
|
std::shared_ptr<HLERequestContext>&& context) {
|
||||||
|
{
|
||||||
|
std::unique_lock lock{queue_mutex};
|
||||||
|
requests.emplace([session{SharedFrom(&session)}, context{std::move(context)}]() {
|
||||||
|
session->CompleteSyncRequest(*context);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
condition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceThread::Impl::~Impl() {
|
||||||
|
{
|
||||||
|
std::unique_lock lock{queue_mutex};
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
condition.notify_all();
|
||||||
|
for (std::thread& thread : threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceThread::ServiceThread(KernelCore& kernel) : impl{std::make_unique<Impl>(kernel)} {}
|
||||||
|
|
||||||
|
ServiceThread::~ServiceThread() = default;
|
||||||
|
|
||||||
|
void ServiceThread::QueueSyncRequest(ServerSession& session,
|
||||||
|
std::shared_ptr<HLERequestContext>&& context) {
|
||||||
|
impl->QueueSyncRequest(session, std::move(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
27
src/core/hle/kernel/service_thread.h
Normal file
27
src/core/hle/kernel/service_thread.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2020 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class HLERequestContext;
|
||||||
|
class KernelCore;
|
||||||
|
class ServerSession;
|
||||||
|
|
||||||
|
class ServiceThread final {
|
||||||
|
public:
|
||||||
|
explicit ServiceThread(KernelCore& kernel);
|
||||||
|
~ServiceThread();
|
||||||
|
|
||||||
|
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Kernel
|
Loading…
Reference in a new issue