Fix race in render_creator (#9939)

This commit is contained in:
Eladash 2021-03-18 11:09:42 +02:00 committed by GitHub
parent 43ac33c2b4
commit ad49c54531
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -31,43 +31,49 @@ render_creator::render_creator(QObject *parent) : QObject(parent)
static std::mutex mtx; static std::mutex mtx;
static std::condition_variable cond; static std::condition_variable cond;
static bool thread_running = true; static bool work_done = false;
static bool device_found = false;
static QStringList compatible_gpus; auto enum_thread_v = new named_thread("Vulkan Device Enumeration Thread"sv, [&, adapters = &this->vulkan_adapters]()
auto enum_thread_v = new named_thread("Vulkan Device Enumeration Thread"sv, [&]()
{ {
thread_ctrl::scoped_priority low_prio(-1); thread_ctrl::scoped_priority low_prio(-1);
vk::instance device_enum_context; vk::instance device_enum_context;
std::unique_lock lock(mtx, std::defer_lock);
if (device_enum_context.create("RPCS3", true)) if (device_enum_context.create("RPCS3", true))
{ {
device_enum_context.bind(); device_enum_context.bind();
std::vector<vk::physical_device>& gpus = device_enum_context.enumerate_devices(); std::vector<vk::physical_device>& gpus = device_enum_context.enumerate_devices();
if (!gpus.empty()) lock.lock();
{
device_found = true;
if (!work_done) // The spawning thread gave up, do not attempt to modify vulkan_adapters
{
for (auto& gpu : gpus) for (auto& gpu : gpus)
{ {
compatible_gpus.append(qstr(gpu.get_name())); adapters->append(qstr(gpu.get_name()));
} }
} }
} }
else
{
lock.lock();
}
std::scoped_lock{ mtx }, thread_running = false; work_done = true;
lock.unlock();
cond.notify_all(); cond.notify_all();
}); });
std::unique_ptr<std::remove_pointer_t<decltype(enum_thread_v)>> enum_thread(enum_thread_v); std::unique_ptr<std::remove_pointer_t<decltype(enum_thread_v)>> enum_thread(enum_thread_v);
if ([&]()
{ {
std::unique_lock lck(mtx); std::unique_lock lck(mtx);
cond.wait_for(lck, std::chrono::seconds(10), [&] { return !thread_running; }); cond.wait_for(lck, std::chrono::seconds(10), [&] { return work_done; });
} return !std::exchange(work_done, true); // If thread hasn't done its job yet, it won't anymore
}())
if (thread_running)
{ {
enum_thread.release(); // Detach thread (destructor is not called) enum_thread.release(); // Detach thread (destructor is not called)
@ -88,8 +94,7 @@ render_creator::render_creator(QObject *parent) : QObject(parent)
} }
else else
{ {
supports_vulkan = device_found; supports_vulkan = !vulkan_adapters.isEmpty();
vulkan_adapters = std::move(compatible_gpus);
enum_thread.reset(); // Join thread enum_thread.reset(); // Join thread
} }
#endif #endif