Skip to content

Commit e70abba

Browse files
committed
prevent from deadlock in DP bucket_can_pool()
1 parent 80ee178 commit e70abba

File tree

2 files changed

+36
-31
lines changed

2 files changed

+36
-31
lines changed

src/pool/pool_disjoint.c

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <assert.h>
99
#include <ctype.h>
1010
#include <errno.h>
11+
#include <inttypes.h>
1112
#include <stdlib.h>
1213
#include <string.h>
1314

@@ -20,6 +21,7 @@
2021
#include "provider/provider_tracking.h"
2122
#include "uthash/utlist.h"
2223
#include "utils_common.h"
24+
#include "utils_concurrency.h"
2325
#include "utils_log.h"
2426
#include "utils_math.h"
2527

@@ -34,7 +36,6 @@
3436
// Forward declarations
3537
static void bucket_update_stats(bucket_t *bucket, int in_use, int in_pool);
3638
static bool bucket_can_pool(bucket_t *bucket);
37-
static void bucket_decrement_pool(bucket_t *bucket);
3839
static slab_list_item_t *bucket_get_avail_slab(bucket_t *bucket,
3940
bool *from_pool);
4041

@@ -316,6 +317,7 @@ static void bucket_free_chunk(bucket_t *bucket, void *ptr, slab_t *slab,
316317
assert(slab_it->val != NULL);
317318
pool_unregister_slab(bucket->pool, slab_it->val);
318319
DL_DELETE(bucket->available_slabs, slab_it);
320+
assert(bucket->available_slabs_num > 0);
319321
bucket->available_slabs_num--;
320322
destroy_slab(slab_it->val);
321323
}
@@ -381,10 +383,20 @@ static slab_list_item_t *bucket_get_avail_slab(bucket_t *bucket,
381383
// Allocation from existing slab is treated as from pool for statistics.
382384
*from_pool = true;
383385
if (slab->num_chunks_allocated == 0) {
386+
assert(bucket->chunked_slabs_in_pool > 0);
387+
#ifndef NDEBUG
388+
uint64_t total_size_check;
389+
utils_atomic_load_acquire_u64(&bucket->shared_limits->total_size,
390+
&total_size_check);
391+
assert(total_size_check >= bucket_slab_alloc_size(bucket));
392+
#endif
384393
// If this was an empty slab, it was in the pool.
385394
// Now it is no longer in the pool, so update count.
386395
--bucket->chunked_slabs_in_pool;
387-
bucket_decrement_pool(bucket);
396+
uint64_t size_to_add = bucket_slab_alloc_size(bucket);
397+
utils_fetch_and_sub_u64(&bucket->shared_limits->total_size,
398+
size_to_add);
399+
bucket_update_stats(bucket, 1, -1);
388400
}
389401
}
390402

@@ -420,36 +432,27 @@ static void bucket_update_stats(bucket_t *bucket, int in_use, int in_pool) {
420432
in_pool * bucket_slab_alloc_size(bucket);
421433
}
422434

423-
static void bucket_decrement_pool(bucket_t *bucket) {
424-
bucket_update_stats(bucket, 1, -1);
425-
utils_fetch_and_add64(&bucket->shared_limits->total_size,
426-
-(long long)bucket_slab_alloc_size(bucket));
427-
}
428-
429435
static bool bucket_can_pool(bucket_t *bucket) {
430436
size_t new_free_slabs_in_bucket;
431437

432438
new_free_slabs_in_bucket = bucket->chunked_slabs_in_pool + 1;
433439

434440
// we keep at most params.capacity slabs in the pool
435441
if (bucket_max_pooled_slabs(bucket) >= new_free_slabs_in_bucket) {
436-
size_t pool_size = 0;
437-
utils_atomic_load_acquire(&bucket->shared_limits->total_size,
438-
&pool_size);
439-
while (true) {
440-
size_t new_pool_size = pool_size + bucket_slab_alloc_size(bucket);
441-
442-
if (bucket->shared_limits->max_size < new_pool_size) {
443-
break;
444-
}
445-
446-
if (utils_compare_exchange(&bucket->shared_limits->total_size,
447-
&pool_size, &new_pool_size)) {
448-
++bucket->chunked_slabs_in_pool;
449-
450-
bucket_update_stats(bucket, -1, 1);
451-
return true;
452-
}
442+
443+
uint64_t size_to_add = bucket_slab_alloc_size(bucket);
444+
size_t previous_size = utils_fetch_and_add_u64(
445+
&bucket->shared_limits->total_size, size_to_add);
446+
447+
if (previous_size + size_to_add <= bucket->shared_limits->max_size) {
448+
++bucket->chunked_slabs_in_pool;
449+
bucket_update_stats(bucket, -1, 1);
450+
return true;
451+
} else {
452+
uint64_t old = utils_fetch_and_sub_u64(
453+
&bucket->shared_limits->total_size, size_to_add);
454+
(void)old;
455+
assert(old >= size_to_add);
453456
}
454457
}
455458

@@ -523,7 +526,7 @@ static void disjoint_pool_print_stats(disjoint_pool_t *pool) {
523526
utils_mutex_unlock(&bucket->bucket_lock);
524527
}
525528

526-
LOG_DEBUG("current pool size: %zu",
529+
LOG_DEBUG("current pool size: %" PRIu64,
527530
disjoint_pool_get_limits(pool)->total_size);
528531
LOG_DEBUG("suggested setting=;%c%s:%zu,%zu,64K", (char)tolower(name[0]),
529532
(name + 1), high_bucket_size, high_peak_slabs_in_use);
@@ -864,11 +867,12 @@ umf_result_t disjoint_pool_free(void *pool, void *ptr) {
864867

865868
if (disjoint_pool->params.pool_trace > 2) {
866869
const char *name = disjoint_pool->params.name;
867-
LOG_DEBUG("freed %s %p to %s, current total pool size: %zu, current "
870+
LOG_DEBUG("freed %s %p to %s, current total pool size: %llu, current "
868871
"pool size for %s: %zu",
869872
name, ptr, (to_pool ? "pool" : "provider"),
870-
disjoint_pool_get_limits(disjoint_pool)->total_size, name,
871-
disjoint_pool->params.cur_pool_size);
873+
(unsigned long long)disjoint_pool_get_limits(disjoint_pool)
874+
->total_size,
875+
name, disjoint_pool->params.cur_pool_size);
872876
}
873877

874878
return UMF_RESULT_SUCCESS;
@@ -920,7 +924,8 @@ umf_memory_pool_ops_t *umfDisjointPoolOps(void) {
920924

921925
umf_disjoint_pool_shared_limits_t *
922926
umfDisjointPoolSharedLimitsCreate(size_t max_size) {
923-
umf_disjoint_pool_shared_limits_t *ptr = umf_ba_global_alloc(sizeof(*ptr));
927+
umf_disjoint_pool_shared_limits_t *ptr =
928+
umf_ba_global_aligned_alloc(sizeof(*ptr), 8);
924929
if (ptr == NULL) {
925930
LOG_ERR("cannot allocate memory for disjoint pool shared limits");
926931
return NULL;

src/pool/pool_disjoint_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ typedef struct slab_t {
102102

103103
typedef struct umf_disjoint_pool_shared_limits_t {
104104
size_t max_size;
105-
size_t total_size; // requires atomic access
105+
uint64_t total_size; // requires atomic access
106106
} umf_disjoint_pool_shared_limits_t;
107107

108108
typedef struct umf_disjoint_pool_params_t {

0 commit comments

Comments
 (0)