From 7ce5364c3537c3f27c63e20bcbd64ee27f01209e Mon Sep 17 00:00:00 2001 From: "Antonio S. Musumeci" Date: Fri, 10 Apr 2026 18:46:48 -0400 Subject: [PATCH] thread_pool: extract _try_claim_removal to deduplicate CAS loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _process_func contained two identical compare_exchange_weak loops for claiming a _remove_count decrement — one in the poison-pill handler and one after task completion. Duplicating the loop risks the two copies diverging during future edits and makes the function harder to follow. Extract the loop into _try_claim_removal() which returns true when a decrement is successfully claimed. Both call sites now delegate to the shared helper. The relaxed memory ordering rationale (the subsequent _remove_self acquires _threads_mutex, providing the happens-before with the scaling-side increment) is documented on the helper. No functional change. Co-Authored-By: Claude Opus 4.6 (1M context) --- vendored/libfuse/include/thread_pool.hpp | 58 ++++++++++++------------ 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/vendored/libfuse/include/thread_pool.hpp b/vendored/libfuse/include/thread_pool.hpp index 94d767e3..e9bc79be 100644 --- a/vendored/libfuse/include/thread_pool.hpp +++ b/vendored/libfuse/include/thread_pool.hpp @@ -94,6 +94,7 @@ private: int _remove_thread_scaling_locked(); void _remove_self(pthread_t t_); bool _try_remove_self_if_above(pthread_t t_, std::size_t min_count_); + bool _try_claim_removal(); void _maybe_grow_on_pressure(); static std::uint64_t _now_usecs(); @@ -391,18 +392,11 @@ ThreadPool::_process_func(Func &func_) // this pill is ours — detach and exit. If the count is zero, // a worker already claimed the decrement via the task- // completion path below; this pill is stale — keep working. - { - std::size_t count = _remove_count.load(std::memory_order_relaxed); - while(count > 0) - { - if(_remove_count.compare_exchange_weak(count,count - 1, - std::memory_order_relaxed)) - { - _remove_self(pthread_self()); - return EXIT; - } - } - } + if(_try_claim_removal()) + { + _remove_self(pthread_self()); + return EXIT; + } return CONTINUE; } @@ -434,24 +428,11 @@ ThreadPool::_process_func(Func &func_) // Workers race to claim a decrement after each task; the winner // detaches itself and exits. During shutdown (_stop set), // _remove_self is a no-op, so the destructor still joins us. - // - // Relaxed ordering is sufficient here: the only side-effect of - // claiming the decrement is _remove_self, which acquires - // _threads_mutex. That mutex provides the necessary happens- - // before relationship between the increment (scaling side) and - // the erase/detach (worker side). - { - std::size_t count = _remove_count.load(std::memory_order_relaxed); - while(count > 0) - { - if(_remove_count.compare_exchange_weak(count,count - 1, - std::memory_order_relaxed)) - { - _remove_self(pthread_self()); - return EXIT; - } - } - } + if(_try_claim_removal()) + { + _remove_self(pthread_self()); + return EXIT; + } return CONTINUE; } @@ -708,6 +689,23 @@ ThreadPool::monitor_routine(void *arg_) } +// Try to claim one pending removal. Returns true if a _remove_count +// decrement was successfully claimed, false if the count was zero. +inline +bool +ThreadPool::_try_claim_removal() +{ + std::size_t count = _remove_count.load(std::memory_order_relaxed); + while(count > 0) + { + if(_remove_count.compare_exchange_weak(count,count - 1, + std::memory_order_relaxed)) + return true; + } + return false; +} + + inline void ThreadPool::_remove_self(pthread_t t_)