service: refactor server architecture

Converts services to have their own processes
This commit is contained in:
Liam 2023-02-18 16:26:48 -05:00
parent 23151ff498
commit a936972614
140 changed files with 1388 additions and 1138 deletions

View file

@ -34,14 +34,15 @@
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/service_thread.h"
#include "core/hle/result.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/memory.h"
@ -55,9 +56,7 @@ struct KernelCore::Impl {
static constexpr size_t BlockInfoSlabHeapSize = 4000;
static constexpr size_t ReservedDynamicPageCount = 64;
explicit Impl(Core::System& system_, KernelCore& kernel_)
: service_threads_manager{1, "ServiceThreadsManager"},
service_thread_barrier{2}, system{system_} {}
explicit Impl(Core::System& system_, KernelCore& kernel_) : system{system_} {}
void SetMulticore(bool is_multi) {
is_multicore = is_multi;
@ -98,8 +97,6 @@ struct KernelCore::Impl {
InitializeHackSharedMemory();
RegisterHostThread(nullptr);
default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread");
}
void InitializeCores() {
@ -140,11 +137,6 @@ struct KernelCore::Impl {
preemption_event = nullptr;
for (auto& iter : named_ports) {
iter.second->Close();
}
named_ports.clear();
exclusive_monitor.reset();
// Cleanup persistent kernel objects
@ -207,8 +199,9 @@ struct KernelCore::Impl {
}
void CloseServices() {
// Ensures all service threads gracefully shutdown.
ClearServiceThreads();
// Ensures all servers gracefully shutdown.
std::scoped_lock lk{server_lock};
server_managers.clear();
}
void InitializePhysicalCores() {
@ -761,55 +754,6 @@ struct KernelCore::Impl {
"HidBus:SharedMemory");
}
KClientPort* CreateNamedServicePort(std::string name) {
auto search = service_interface_factory.find(name);
if (search == service_interface_factory.end()) {
UNIMPLEMENTED();
return {};
}
return &search->second(system.ServiceManager(), system);
}
void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
auto search = service_interface_handlers.find(name);
if (search == service_interface_handlers.end()) {
return;
}
search->second(system.ServiceManager(), server_port);
}
Kernel::ServiceThread& CreateServiceThread(KernelCore& kernel, const std::string& name) {
auto* ptr = new ServiceThread(kernel, name);
service_threads_manager.QueueWork(
[this, ptr]() { service_threads.emplace(ptr, std::unique_ptr<ServiceThread>(ptr)); });
return *ptr;
}
void ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
auto* ptr = &service_thread;
if (ptr == default_service_thread) {
// Nothing to do here, the service is using default_service_thread, which will be
// released on shutdown.
return;
}
service_threads_manager.QueueWork([this, ptr]() { service_threads.erase(ptr); });
}
void ClearServiceThreads() {
service_threads_manager.QueueWork([this] {
service_threads.clear();
default_service_thread = nullptr;
service_thread_barrier.Sync();
});
service_thread_barrier.Sync();
}
std::mutex registered_objects_lock;
std::mutex registered_in_use_objects_lock;
@ -839,14 +783,12 @@ struct KernelCore::Impl {
std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
/// Map of named ports managed by the kernel, which can be retrieved using
/// the ConnectToPort SVC.
std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
std::unordered_map<std::string, ServiceInterfaceHandlerFn> service_interface_handlers;
NamedPortTable named_ports;
std::unordered_set<KAutoObject*> registered_objects;
std::unordered_set<KAutoObject*> registered_in_use_objects;
std::mutex server_lock;
std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
@ -881,12 +823,6 @@ struct KernelCore::Impl {
// Memory layout
std::unique_ptr<KMemoryLayout> memory_layout;
// Threads used for services
std::unordered_map<ServiceThread*, std::unique_ptr<ServiceThread>> service_threads;
ServiceThread* default_service_thread{};
Common::ThreadWorker service_threads_manager;
Common::Barrier service_thread_barrier;
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
@ -1050,23 +986,6 @@ void KernelCore::PrepareReschedule(std::size_t id) {
// TODO: Reimplement, this
}
void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) {
impl->service_interface_factory.emplace(std::move(name), factory);
}
void KernelCore::RegisterInterfaceForNamedService(std::string name,
ServiceInterfaceHandlerFn&& handler) {
impl->service_interface_handlers.emplace(std::move(name), handler);
}
KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
return impl->CreateNamedServicePort(std::move(name));
}
void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
impl->RegisterNamedServiceHandler(std::move(name), server_port);
}
void KernelCore::RegisterKernelObject(KAutoObject* object) {
std::scoped_lock lk{impl->registered_objects_lock};
impl->registered_objects.insert(object);
@ -1087,8 +1006,19 @@ void KernelCore::UnregisterInUseObject(KAutoObject* object) {
impl->registered_in_use_objects.erase(object);
}
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
return port != impl->named_ports.cend();
void KernelCore::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) {
auto* manager = server_manager.get();
{
std::scoped_lock lk{impl->server_lock};
if (impl->is_shutting_down) {
return;
}
impl->server_managers.emplace_back(std::move(server_manager));
}
manager->LoopProcess();
}
u32 KernelCore::CreateNewObjectID() {
@ -1127,6 +1057,87 @@ void KernelCore::RegisterHostThread(KThread* existing_thread) {
}
}
static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process,
std::string&& thread_name, std::function<void()>&& func) {
// Reserve a new thread from the process resource limit.
KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax);
ASSERT(thread_reservation.Succeeded());
// Initialize the thread.
KThread* thread = KThread::Create(kernel);
ASSERT(R_SUCCEEDED(KThread::InitializeDummyThread(thread, process)));
// Commit the thread reservation.
thread_reservation.Commit();
return std::jthread(
[&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] {
// Set the thread name.
Common::SetCurrentThreadName(thread_name.c_str());
// Register the thread.
kernel.RegisterHostThread(thread);
// Run the callback.
func();
// Close the thread.
// This will free the process if it is the last reference.
thread->Close();
});
}
std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
std::function<void()> func) {
// Make a new process.
KProcess* process = KProcess::Create(*this);
ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland,
GetSystemResourceLimit())));
// Ensure that we don't hold onto any extra references.
SCOPE_EXIT({ process->Close(); });
// Run the host thread.
return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func));
}
std::jthread KernelCore::RunOnHostCoreThread(std::string&& thread_name,
std::function<void()> func) {
// Get the current process.
KProcess* process = GetCurrentProcessPointer(*this);
// Run the host thread.
return RunHostThreadFunc(*this, process, std::move(thread_name), std::move(func));
}
void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function<void()> func) {
constexpr s32 ServiceThreadPriority = 16;
constexpr s32 ServiceThreadCore = 3;
// Make a new process.
KProcess* process = KProcess::Create(*this);
ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland,
GetSystemResourceLimit())));
// Ensure that we don't hold onto any extra references.
SCOPE_EXIT({ process->Close(); });
// Reserve a new thread from the process resource limit.
KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax);
ASSERT(thread_reservation.Succeeded());
// Initialize the thread.
KThread* thread = KThread::Create(*this);
ASSERT(R_SUCCEEDED(KThread::InitializeServiceThread(
System(), thread, std::move(func), ServiceThreadPriority, ServiceThreadCore, process)));
// Commit the thread reservation.
thread_reservation.Commit();
// Begin running the thread.
ASSERT(R_SUCCEEDED(thread->Run()));
}
u32 KernelCore::GetCurrentHostThreadID() const {
return impl->GetCurrentHostThreadID();
}
@ -1271,18 +1282,6 @@ void KernelCore::ExitSVCProfile() {
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]);
}
Kernel::ServiceThread& KernelCore::CreateServiceThread(const std::string& name) {
return impl->CreateServiceThread(*this, name);
}
Kernel::ServiceThread& KernelCore::GetDefaultServiceThread() const {
return *impl->default_service_thread;
}
void KernelCore::ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
impl->ReleaseServiceThread(service_thread);
}
Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {
return impl->slab_resource_counts;
}