fix idle self-exit allowing pool to drain to 0 threads

_remove_thread_scaling_locked floors min_allowed at 1, preventing
remove_thread/set_threads from ever reducing the pool below 1 thread.
But start_routine_autoscale passed raw _scaling_config.min_threads
to _try_remove_self_if_above without the same floor.  With
min_threads == 0, all idle workers could self-exit, draining the
pool to zero threads and permanently stalling any work enqueued
via non-autoscale enqueue_work (which doesn't call
_maybe_grow_on_pressure).

Apply the same max(min_threads, 1) floor in start_routine_autoscale
to keep the two shrink paths consistent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Antonio S. Musumeci 2026-04-10 22:18:23 -04:00
parent f3b4703ee2
commit 5f50f76b66

View file

@ -514,7 +514,12 @@ ThreadPool::start_routine_autoscale(void *arg_)
//
// name was already copied into a local at function entry,
// so the syslog below is also safe.
std::size_t const min_thr = btp->_scaling_config.min_threads;
// Floor at 1 to match _remove_thread_scaling_locked's
// min_allowed floor. Without this, min_threads == 0
// would let all workers self-exit, draining the pool
// to zero threads and stalling non-autoscale enqueues.
std::size_t const min_thr = std::max(btp->_scaling_config.min_threads,
(std::size_t)1);
if(btp->_try_remove_self_if_above(pthread_self(),min_thr))
{
syslog(LOG_DEBUG,