1 // SPDX-FileCopyrightText: 2011 Lai Jiangshan <laijs (at) cn.fujitsu.com> 2 // 3 // SPDX-License-Identifier: LGPL-2.1-or-later 4 5 /* 6 * Chunk based memory management for Lock-Free RCU Hash Table 7 */ 8 9 #include <stddef.h> 10 #include <urcu/assert.h> 11 #include "rculfhash-internal.h" 12 13 static 14 void cds_lfht_alloc_bucket_table(struct cds_lfht *ht, unsigned long order) 15 { 16 if (order == 0) { 17 ht->tbl_chunk[0] = ht->alloc->calloc(ht->alloc->state, 18 ht->min_nr_alloc_buckets, sizeof(struct cds_lfht_node)); 19 urcu_posix_assert(ht->tbl_chunk[0]); 20 } else if (order > ht->min_alloc_buckets_order) { 21 unsigned long i, len = 1UL << (order - 1 - ht->min_alloc_buckets_order); 22 23 for (i = len; i < 2 * len; i++) { 24 ht->tbl_chunk[i] = ht->alloc->calloc(ht->alloc->state, 25 ht->min_nr_alloc_buckets, sizeof(struct cds_lfht_node)); 26 urcu_posix_assert(ht->tbl_chunk[i]); 27 } 28 } 29 /* Nothing to do for 0 < order && order <= ht->min_alloc_buckets_order */ 30 } 31 32 /* 33 * cds_lfht_free_bucket_table() should be called with decreasing order. 34 * When cds_lfht_free_bucket_table(0) is called, it means the whole 35 * lfht is destroyed. 36 */ 37 static 38 void cds_lfht_free_bucket_table(struct cds_lfht *ht, unsigned long order) 39 { 40 if (order == 0) 41 poison_free(ht->alloc, ht->tbl_chunk[0]); 42 else if (order > ht->min_alloc_buckets_order) { 43 unsigned long i, len = 1UL << (order - 1 - ht->min_alloc_buckets_order); 44 45 for (i = len; i < 2 * len; i++) 46 poison_free(ht->alloc, ht->tbl_chunk[i]); 47 } 48 /* Nothing to do for 0 < order && order <= ht->min_alloc_buckets_order */ 49 } 50 51 static 52 struct cds_lfht_node *bucket_at(struct cds_lfht *ht, unsigned long index) 53 { 54 unsigned long chunk, offset; 55 56 chunk = index >> ht->min_alloc_buckets_order; 57 offset = index & (ht->min_nr_alloc_buckets - 1); 58 return &ht->tbl_chunk[chunk][offset]; 59 } 60 61 static 62 struct cds_lfht *alloc_cds_lfht(unsigned long min_nr_alloc_buckets, 63 unsigned long max_nr_buckets, const struct cds_lfht_alloc *alloc) 64 { 65 unsigned long nr_chunks, cds_lfht_size; 66 67 min_nr_alloc_buckets = max(min_nr_alloc_buckets, 68 max_nr_buckets / MAX_CHUNK_TABLE); 69 nr_chunks = max_nr_buckets / min_nr_alloc_buckets; 70 cds_lfht_size = offsetof(struct cds_lfht, tbl_chunk) + 71 sizeof(struct cds_lfht_node *) * nr_chunks; 72 cds_lfht_size = max(cds_lfht_size, sizeof(struct cds_lfht)); 73 74 return __default_alloc_cds_lfht( 75 &cds_lfht_mm_chunk, alloc, cds_lfht_size, 76 min_nr_alloc_buckets, max_nr_buckets); 77 } 78 79 const struct cds_lfht_mm_type cds_lfht_mm_chunk = { 80 .alloc_cds_lfht = alloc_cds_lfht, 81 .alloc_bucket_table = cds_lfht_alloc_bucket_table, 82 .free_bucket_table = cds_lfht_free_bucket_table, 83 .bucket_at = bucket_at, 84 }; 85