From 7fcc49004d18e4091ba31c071acd7b824876966a Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 16 Jan 2020 01:09:35 +0300 Subject: [PATCH] lf_fifo: fix UB and fix size() Simplify internal counter to atomic. Make size() return correct difference between push and pop pointers. --- Utilities/lockless.h | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Utilities/lockless.h b/Utilities/lockless.h index af73c9772e..cf8c0602fd 100644 --- a/Utilities/lockless.h +++ b/Utilities/lockless.h @@ -54,51 +54,46 @@ public: template class lf_fifo : public lf_array { - struct alignas(8) ctrl_t - { - u32 push; - u32 pop; - }; - - atomic_t m_ctrl{}; + // LSB 32-bit: push, MSB 32-bit: pop + atomic_t m_ctrl{}; public: constexpr lf_fifo() = default; - // Get current "push" position + // Get number of elements in the queue u32 size() const { - return m_ctrl.load().push; + const u64 ctrl = m_ctrl.load(); + return static_cast(ctrl - (ctrl >> 32)); } // Acquire the place for one or more elements. u32 push_begin(u32 count = 1) { - return std::bit_cast*>(&m_ctrl)->fetch_add(count); // Hack + return m_ctrl.fetch_add(count); } // Get current "pop" position u32 peek() const { - return m_ctrl.load().pop; + return static_cast(m_ctrl >> 32); } // Acknowledge processed element, return number of the next one. // Perform clear if possible, zero is returned in this case. u32 pop_end(u32 count = 1) { - return m_ctrl.atomic_op([&](ctrl_t& ctrl) + return m_ctrl.atomic_op([&](u64& ctrl) { - ctrl.pop += count; + ctrl += u64{count} << 32; - if (ctrl.pop == ctrl.push) + if (ctrl >> 32 == static_cast(ctrl)) { // Clean if possible - ctrl.push = 0; - ctrl.pop = 0; + ctrl = 0; } - return ctrl.pop; + return static_cast(ctrl >> 32); }); } };