From d94d052e6ccca9b0d7aca87afad4f999b2684a63 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Mon, 19 Jun 2023 12:32:28 +0200 Subject: [PATCH] KawPow: fixed data race when building programs `uv_queue_work` can't be called from other threads, only `uv_async_send` is thread-safe. --- .../opencl/runners/tools/OclKawPow.cpp | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/backend/opencl/runners/tools/OclKawPow.cpp b/src/backend/opencl/runners/tools/OclKawPow.cpp index a7e8df3a..4151633c 100644 --- a/src/backend/opencl/runners/tools/OclKawPow.cpp +++ b/src/backend/opencl/runners/tools/OclKawPow.cpp @@ -399,6 +399,9 @@ private: uv_loop_t* m_loop = nullptr; uv_thread_t m_loopThread = {}; uv_async_t m_shutdownAsync = {}; + uv_async_t m_batonAsync = {}; + + std::vector m_batons; static void loop(void* data) { @@ -419,19 +422,37 @@ void KawPowBuilder::build_async(const IOclRunner& runner, uint64_t period, uint3 if (!m_loop) { m_loop = new uv_loop_t{}; uv_loop_init(m_loop); - uv_async_init(m_loop, &m_shutdownAsync, [](uv_async_t* handle) { uv_close(reinterpret_cast(handle), nullptr); }); + + uv_async_init(m_loop, &m_shutdownAsync, [](uv_async_t* handle) + { + KawPowBuilder* builder = reinterpret_cast(handle->data); + uv_close(reinterpret_cast(&builder->m_shutdownAsync), nullptr); + uv_close(reinterpret_cast(&builder->m_batonAsync), nullptr); + }); + + uv_async_init(m_loop, &m_batonAsync, [](uv_async_t* handle) + { + std::vector batons; + { + KawPowBuilder* b = reinterpret_cast(handle->data); + + std::lock_guard lock(b->m_mutex); + batons = std::move(b->m_batons); + } + + for (const KawPowBaton& baton : batons) { + builder.build(baton.runner, baton.period, baton.worksize); + } + }); + + m_shutdownAsync.data = this; + m_batonAsync.data = this; + uv_thread_create(&m_loopThread, loop, this); } - KawPowBaton* baton = new KawPowBaton(runner, period, worksize); - - uv_queue_work(m_loop, &baton->req, - [](uv_work_t* req) { - KawPowBaton* baton = static_cast(req->data); - builder.build(baton->runner, baton->period, baton->worksize); - }, - [](uv_work_t* req, int) { delete static_cast(req->data); } - ); + m_batons.emplace_back(runner, period, worksize); + uv_async_send(&m_batonAsync); }