hle: kernel: service_thread: Use std::jthread.

- Fixes a potential deadlock on service thread shutdown.
This commit is contained in:
bunnei 2021-11-28 13:05:18 -08:00
parent a2384a18fa
commit efb5de1c5f
1 changed files with 19 additions and 18 deletions

View File

@ -25,24 +25,27 @@ public:
void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
private: private:
std::vector<std::thread> threads; std::vector<std::jthread> threads;
std::queue<std::function<void()>> requests; std::queue<std::function<void()>> requests;
std::mutex queue_mutex; std::mutex queue_mutex;
std::condition_variable condition; std::condition_variable_any condition;
const std::string service_name; const std::string service_name;
bool stop{};
}; };
ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)
: service_name{name} { : service_name{name} {
for (std::size_t i = 0; i < num_threads; ++i) for (std::size_t i = 0; i < num_threads; ++i) {
threads.emplace_back([this, &kernel] { threads.emplace_back([this, &kernel](std::stop_token stop_token) {
Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str()); Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str());
// Wait for first request before trying to acquire a render context // Wait for first request before trying to acquire a render context
{ {
std::unique_lock lock{queue_mutex}; std::unique_lock lock{queue_mutex};
condition.wait(lock, [this] { return stop || !requests.empty(); }); condition.wait(lock, stop_token, [this] { return !requests.empty(); });
}
if (stop_token.stop_requested()) {
return;
} }
kernel.RegisterHostThread(); kernel.RegisterHostThread();
@ -52,10 +55,16 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
{ {
std::unique_lock lock{queue_mutex}; std::unique_lock lock{queue_mutex};
condition.wait(lock, [this] { return stop || !requests.empty(); }); condition.wait(lock, stop_token, [this] { return !requests.empty(); });
if (stop || requests.empty()) {
if (stop_token.stop_requested()) {
return; return;
} }
if (requests.empty()) {
continue;
}
task = std::move(requests.front()); task = std::move(requests.front());
requests.pop(); requests.pop();
} }
@ -63,6 +72,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
task(); task();
} }
}); });
}
} }
void ServiceThread::Impl::QueueSyncRequest(KSession& session, void ServiceThread::Impl::QueueSyncRequest(KSession& session,
@ -87,16 +97,7 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session,
condition.notify_one(); condition.notify_one();
} }
ServiceThread::Impl::~Impl() { ServiceThread::Impl::~Impl() = default;
{
std::unique_lock lock{queue_mutex};
stop = true;
}
condition.notify_all();
for (std::thread& thread : threads) {
thread.join();
}
}
ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name)
: impl{std::make_unique<Impl>(kernel, num_threads, name)} {} : impl{std::make_unique<Impl>(kernel, num_threads, name)} {}