hle: kernel: Move ServiceThread ownership to KernelCore.
- Fixes a circular dependency which prevented threads from being released on shutdown.
This commit is contained in:
parent
f57be2e626
commit
dfdac7d38a
|
@ -8,7 +8,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
#include "core/hle/kernel/physical_core.h"
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
|
#include "core/hle/kernel/service_thread.h"
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/kernel/synchronization.h"
|
#include "core/hle/kernel/synchronization.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
@ -107,6 +108,9 @@ struct KernelCore::Impl {
|
||||||
std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
|
std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
|
||||||
std::thread::id{});
|
std::thread::id{});
|
||||||
std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
|
std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
|
||||||
|
|
||||||
|
// Ensures all service threads gracefully shutdown
|
||||||
|
service_threads.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializePhysicalCores() {
|
void InitializePhysicalCores() {
|
||||||
|
@ -345,6 +349,9 @@ struct KernelCore::Impl {
|
||||||
std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
|
std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
|
||||||
std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
|
std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
|
||||||
|
|
||||||
|
// Threads used for services
|
||||||
|
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
|
||||||
|
|
||||||
std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
|
std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
|
||||||
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
||||||
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
||||||
|
@ -639,4 +646,16 @@ void KernelCore::ExitSVCProfile() {
|
||||||
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
|
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
|
||||||
|
auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
|
||||||
|
impl->service_threads.emplace(service_thread);
|
||||||
|
return service_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
|
||||||
|
if (auto strong_ptr = service_thread.lock()) {
|
||||||
|
impl->service_threads.erase(strong_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -42,6 +42,7 @@ class Process;
|
||||||
class ResourceLimit;
|
class ResourceLimit;
|
||||||
class KScheduler;
|
class KScheduler;
|
||||||
class SharedMemory;
|
class SharedMemory;
|
||||||
|
class ServiceThread;
|
||||||
class Synchronization;
|
class Synchronization;
|
||||||
class Thread;
|
class Thread;
|
||||||
class TimeManager;
|
class TimeManager;
|
||||||
|
@ -227,6 +228,22 @@ public:
|
||||||
|
|
||||||
void ExitSVCProfile();
|
void ExitSVCProfile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an HLE service thread, which are used to execute service routines asynchronously.
|
||||||
|
* While these are allocated per ServerSession, these need to be owned and managed outside of
|
||||||
|
* ServerSession to avoid a circular dependency.
|
||||||
|
* @param name String name for the ServerSession creating this thread, used for debug purposes.
|
||||||
|
* @returns The a weak pointer newly created service thread.
|
||||||
|
*/
|
||||||
|
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases a HLE service thread, instructing KernelCore to free it. This should be called when
|
||||||
|
* the ServerSession associated with the thread is destroyed.
|
||||||
|
* @param service_thread Service thread to release.
|
||||||
|
*/
|
||||||
|
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Object;
|
friend class Object;
|
||||||
friend class Process;
|
friend class Process;
|
||||||
|
|
|
@ -25,7 +25,10 @@
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
ServerSession::~ServerSession() = default;
|
|
||||||
|
ServerSession::~ServerSession() {
|
||||||
|
kernel.ReleaseServiceThread(service_thread);
|
||||||
|
}
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
|
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
|
||||||
std::shared_ptr<Session> parent,
|
std::shared_ptr<Session> parent,
|
||||||
|
@ -34,7 +37,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
|
||||||
|
|
||||||
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, 1, session->name);
|
session->service_thread = kernel.CreateServiceThread(session->name);
|
||||||
|
|
||||||
return MakeResult(std::move(session));
|
return MakeResult(std::move(session));
|
||||||
}
|
}
|
||||||
|
@ -139,7 +142,11 @@ 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);
|
||||||
service_thread->QueueSyncRequest(*this, std::move(context));
|
|
||||||
|
if (auto strong_ptr = service_thread.lock()) {
|
||||||
|
strong_ptr->QueueSyncRequest(*this, std::move(context));
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ private:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
/// Thread to dispatch service requests
|
/// Thread to dispatch service requests
|
||||||
std::unique_ptr<ServiceThread> service_thread;
|
std::weak_ptr<ServiceThread> service_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
Reference in New Issue