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_session.cpp
|
||||
hle/kernel/server_session.h
|
||||
hle/kernel/service_thread.cpp
|
||||
hle/kernel/service_thread.h
|
||||
hle/kernel/session.cpp
|
||||
hle/kernel/session.h
|
||||
hle/kernel/shared_memory.cpp
|
||||
|
|
|
@ -329,7 +329,7 @@ struct KernelCore::Impl {
|
|||
std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
|
||||
|
||||
// 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::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
|
||||
register_host_thread_keys{};
|
||||
|
|
|
@ -32,12 +32,9 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
|
|||
std::string name) {
|
||||
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->parent = std::move(parent);
|
||||
session->service_thread = std::make_unique<ServiceThread>(kernel);
|
||||
|
||||
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));
|
||||
|
||||
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
||||
request_queue.Push(std::move(context));
|
||||
service_thread->QueueSyncRequest(*this, std::move(context));
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode ServerSession::CompleteSyncRequest() {
|
||||
ASSERT(!request_queue.Empty());
|
||||
|
||||
auto& context = *request_queue.Front();
|
||||
|
||||
ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
||||
ResultCode result = RESULT_SUCCESS;
|
||||
// If the session has been converted to a domain, handle the domain request
|
||||
if (IsDomain() && context.HasDomainMessageHeader()) {
|
||||
|
@ -177,18 +170,13 @@ ResultCode ServerSession::CompleteSyncRequest() {
|
|||
}
|
||||
}
|
||||
|
||||
request_queue.Pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
|
||||
Core::Memory::Memory& memory,
|
||||
Core::Timing::CoreTiming& core_timing) {
|
||||
const ResultCode result = QueueSyncRequest(std::move(thread), memory);
|
||||
const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000};
|
||||
core_timing.ScheduleEvent(delay, request_event, {});
|
||||
return result;
|
||||
return QueueSyncRequest(std::move(thread), memory);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "core/hle/kernel/service_thread.h"
|
||||
#include "core/hle/kernel/synchronization_object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
|
@ -43,6 +44,8 @@ class Thread;
|
|||
* TLS buffer and control is transferred back to it.
|
||||
*/
|
||||
class ServerSession final : public SynchronizationObject {
|
||||
friend class ServiceThread;
|
||||
|
||||
public:
|
||||
explicit ServerSession(KernelCore& kernel);
|
||||
~ServerSession() override;
|
||||
|
@ -132,7 +135,7 @@ private:
|
|||
ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
|
||||
|
||||
/// 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
|
||||
/// object handle.
|
||||
|
@ -163,11 +166,8 @@ private:
|
|||
/// The name of this session (optional)
|
||||
std::string name;
|
||||
|
||||
/// Core timing event used to schedule the service request at some point in the future
|
||||
std::shared_ptr<Core::Timing::EventType> request_event;
|
||||
|
||||
/// Queue of scheduled service requests
|
||||
Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue;
|
||||
/// Thread to dispatch service requests
|
||||
std::unique_ptr<ServiceThread> service_thread;
|
||||
};
|
||||
|
||||
} // 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