mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
Use condvar for monitor sleep to allow instant shutdown wakeup
The monitor thread used nanosleep for its sample interval, which meant the destructor had to block for up to one full sample period (100ms by default) waiting for the monitor to wake up and notice _stop. Replace nanosleep with pthread_cond_timedwait on a dedicated condvar (_monitor_cond) using CLOCK_MONOTONIC. The destructor now signals the condvar immediately after setting _stop, so the monitor wakes up and exits without waiting for the interval to expire. This also eliminates the EINTR retry loop — pthread_cond_timedwait handles signals internally and returns when either the timeout expires or the condvar is signaled. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a90e13a19d
commit
47a097ee96
1 changed files with 41 additions and 14 deletions
|
|
@ -173,9 +173,11 @@ private:
|
|||
std::atomic<std::uint64_t> _tasks_completed{0};
|
||||
|
||||
// Auto-scaling state
|
||||
bool _autoscale_enabled;
|
||||
ScalingConfig _scaling_config;
|
||||
pthread_t _monitor_thread;
|
||||
bool _autoscale_enabled;
|
||||
ScalingConfig _scaling_config;
|
||||
pthread_t _monitor_thread;
|
||||
pthread_mutex_t _monitor_mutex;
|
||||
pthread_cond_t _monitor_cond;
|
||||
|
||||
std::atomic<std::uint64_t> _last_scale_time_usecs{0};
|
||||
};
|
||||
|
|
@ -200,8 +202,20 @@ ThreadPool::ThreadPool(const unsigned thread_count_,
|
|||
_name(name_),
|
||||
_autoscale_enabled(scaling_config_ != nullptr),
|
||||
_scaling_config(),
|
||||
_monitor_thread()
|
||||
_monitor_thread(),
|
||||
_monitor_mutex(PTHREAD_MUTEX_INITIALIZER),
|
||||
_monitor_cond()
|
||||
{
|
||||
// Use CLOCK_MONOTONIC for the monitor condvar so timed waits
|
||||
// are immune to wall-clock adjustments (NTP, settimeofday).
|
||||
{
|
||||
pthread_condattr_t attr;
|
||||
pthread_condattr_init(&attr);
|
||||
pthread_condattr_setclock(&attr,CLOCK_MONOTONIC);
|
||||
pthread_cond_init(&_monitor_cond,&attr);
|
||||
pthread_condattr_destroy(&attr);
|
||||
}
|
||||
|
||||
if(scaling_config_)
|
||||
_scaling_config = *scaling_config_;
|
||||
|
||||
|
|
@ -298,12 +312,19 @@ ThreadPool::~ThreadPool()
|
|||
{
|
||||
_stop.store(true,std::memory_order_release);
|
||||
|
||||
// Stop monitor thread first
|
||||
// Wake the monitor thread so it exits immediately instead of
|
||||
// sleeping for up to one sample interval.
|
||||
if(_autoscale_enabled)
|
||||
{
|
||||
pthread_mutex_lock(&_monitor_mutex);
|
||||
pthread_cond_signal(&_monitor_cond);
|
||||
pthread_mutex_unlock(&_monitor_mutex);
|
||||
pthread_join(_monitor_thread,NULL);
|
||||
}
|
||||
|
||||
pthread_cond_destroy(&_monitor_cond);
|
||||
pthread_mutex_destroy(&_monitor_mutex);
|
||||
|
||||
// Snapshot threads under lock to close the race with _remove_self.
|
||||
// After _stop is set, _remove_self becomes a no-op, so no thread
|
||||
// will detach or erase itself from this point forward.
|
||||
|
|
@ -518,20 +539,26 @@ ThreadPool::monitor_routine(void *arg_)
|
|||
std::size_t expected_count = btp->thread_count();
|
||||
bool acted_last_cycle = false;
|
||||
|
||||
const struct timespec sleep_ts = {
|
||||
static_cast<time_t>(interval / 1000000),
|
||||
static_cast<long>((interval % 1000000) * 1000)
|
||||
};
|
||||
|
||||
while(!btp->_stop.load(std::memory_order_acquire))
|
||||
{
|
||||
// Sleep for one sample interval, but wake immediately if the
|
||||
// destructor signals _monitor_cond.
|
||||
{
|
||||
struct timespec remaining = sleep_ts;
|
||||
while(nanosleep(&remaining,&remaining) == -1 && errno == EINTR)
|
||||
struct timespec abs_ts;
|
||||
clock_gettime(CLOCK_MONOTONIC,&abs_ts);
|
||||
abs_ts.tv_nsec += (interval % 1000000) * 1000;
|
||||
abs_ts.tv_sec += interval / 1000000;
|
||||
if(abs_ts.tv_nsec >= 1000000000L)
|
||||
{
|
||||
if(btp->_stop.load(std::memory_order_acquire))
|
||||
break;
|
||||
abs_ts.tv_sec += 1;
|
||||
abs_ts.tv_nsec -= 1000000000L;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&btp->_monitor_mutex);
|
||||
pthread_cond_timedwait(&btp->_monitor_cond,
|
||||
&btp->_monitor_mutex,
|
||||
&abs_ts);
|
||||
pthread_mutex_unlock(&btp->_monitor_mutex);
|
||||
}
|
||||
|
||||
if(btp->_stop.load(std::memory_order_acquire))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue