mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-22 04:03:11 +00:00
Use CLOCK_MONOTONIC for background thread sleep to prevent clock rollback stalls
background_thread_sleep() computed the pthread_cond_timedwait deadline from gettimeofday() (CLOCK_REALTIME). If the wall clock jumps backward (NTP correction, VM snapshot, leap second), the deadline ends up far in the future and the background thread stops purging dirty pages - potentially for hours or days. This was observed in production where NTP corrections caused unbounded RSS growth due to the background thread stalling. Switch deadline computation to nstime_init_update() (which already handles the monotonic vs realtime fallback), and set CLOCK_MONOTONIC on the condvar via pthread_condattr_setclock at both init sites (background_thread_boot1 and background_thread_postfork_child), with fallback to CLOCK_REALTIME if condattr init/setclock fails.
This commit is contained in:
committed by
Guangli Dai
parent
fb5499aa9c
commit
ebacec3a1a
@@ -199,11 +199,8 @@ background_thread_sleep(
|
|||||||
}
|
}
|
||||||
info->npages_to_purge_new = 0;
|
info->npages_to_purge_new = 0;
|
||||||
|
|
||||||
struct timeval tv;
|
|
||||||
/* Specific clock required by timedwait. */
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
nstime_t before_sleep;
|
nstime_t before_sleep;
|
||||||
nstime_init2(&before_sleep, tv.tv_sec, tv.tv_usec * 1000);
|
nstime_init_update(&before_sleep);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) {
|
if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) {
|
||||||
@@ -235,9 +232,8 @@ background_thread_sleep(
|
|||||||
assert(ret == ETIMEDOUT || ret == 0);
|
assert(ret == ETIMEDOUT || ret == 0);
|
||||||
}
|
}
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
nstime_t after_sleep;
|
nstime_t after_sleep;
|
||||||
nstime_init2(&after_sleep, tv.tv_sec, tv.tv_usec * 1000);
|
nstime_init_update(&after_sleep);
|
||||||
if (nstime_compare(&after_sleep, &before_sleep) > 0) {
|
if (nstime_compare(&after_sleep, &before_sleep) > 0) {
|
||||||
nstime_subtract(&after_sleep, &before_sleep);
|
nstime_subtract(&after_sleep, &before_sleep);
|
||||||
nstime_add(&info->tot_sleep_time, &after_sleep);
|
nstime_add(&info->tot_sleep_time, &after_sleep);
|
||||||
@@ -751,7 +747,27 @@ background_thread_postfork_child(tsdn_t *tsdn) {
|
|||||||
background_thread_info_t *info = &background_thread_info[i];
|
background_thread_info_t *info = &background_thread_info[i];
|
||||||
malloc_mutex_lock(tsdn, &info->mtx);
|
malloc_mutex_lock(tsdn, &info->mtx);
|
||||||
info->state = background_thread_stopped;
|
info->state = background_thread_stopped;
|
||||||
|
#if defined(JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE) || defined(JEMALLOC_HAVE_CLOCK_MONOTONIC)
|
||||||
|
int ret;
|
||||||
|
pthread_condattr_t cond_attr;
|
||||||
|
if (pthread_condattr_init(&cond_attr)) {
|
||||||
|
ret = pthread_cond_init(&info->cond, NULL);
|
||||||
|
} else if (pthread_condattr_setclock(&cond_attr,
|
||||||
|
CLOCK_MONOTONIC)) {
|
||||||
|
/*
|
||||||
|
* Fall back to default (CLOCK_REALTIME)
|
||||||
|
* attributes if setclock fails.
|
||||||
|
*/
|
||||||
|
pthread_condattr_destroy(&cond_attr);
|
||||||
|
ret = pthread_cond_init(&info->cond, NULL);
|
||||||
|
} else {
|
||||||
|
ret = pthread_cond_init(&info->cond,
|
||||||
|
&cond_attr);
|
||||||
|
pthread_condattr_destroy(&cond_attr);
|
||||||
|
}
|
||||||
|
#else
|
||||||
int ret = pthread_cond_init(&info->cond, NULL);
|
int ret = pthread_cond_init(&info->cond, NULL);
|
||||||
|
#endif
|
||||||
assert(ret == 0);
|
assert(ret == 0);
|
||||||
background_thread_info_init(tsdn, info);
|
background_thread_info_init(tsdn, info);
|
||||||
malloc_mutex_unlock(tsdn, &info->mtx);
|
malloc_mutex_unlock(tsdn, &info->mtx);
|
||||||
@@ -869,9 +885,28 @@ background_thread_boot1(tsdn_t *tsdn, base_t *base) {
|
|||||||
malloc_mutex_address_ordered)) {
|
malloc_mutex_address_ordered)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#if defined(JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE) || defined(JEMALLOC_HAVE_CLOCK_MONOTONIC)
|
||||||
|
{
|
||||||
|
pthread_condattr_t cond_attr;
|
||||||
|
if (pthread_condattr_init(&cond_attr)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pthread_condattr_setclock(&cond_attr,
|
||||||
|
CLOCK_MONOTONIC)) {
|
||||||
|
pthread_condattr_destroy(&cond_attr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pthread_cond_init(&info->cond, &cond_attr)) {
|
||||||
|
pthread_condattr_destroy(&cond_attr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pthread_condattr_destroy(&cond_attr);
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (pthread_cond_init(&info->cond, NULL)) {
|
if (pthread_cond_init(&info->cond, NULL)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
malloc_mutex_lock(tsdn, &info->mtx);
|
malloc_mutex_lock(tsdn, &info->mtx);
|
||||||
info->state = background_thread_stopped;
|
info->state = background_thread_stopped;
|
||||||
background_thread_info_init(tsdn, info);
|
background_thread_info_init(tsdn, info);
|
||||||
|
|||||||
Reference in New Issue
Block a user