Home | History | Annotate | Line # | Download | only in internal
      1  1.1  christos #ifndef JEMALLOC_INTERNAL_EMAP_H
      2  1.1  christos #define JEMALLOC_INTERNAL_EMAP_H
      3  1.1  christos 
      4  1.1  christos #include "jemalloc/internal/base.h"
      5  1.1  christos #include "jemalloc/internal/rtree.h"
      6  1.1  christos 
      7  1.1  christos /*
      8  1.1  christos  * Note: Ends without at semicolon, so that
      9  1.1  christos  *     EMAP_DECLARE_RTREE_CTX;
     10  1.1  christos  * in uses will avoid empty-statement warnings.
     11  1.1  christos  */
     12  1.1  christos #define EMAP_DECLARE_RTREE_CTX						\
     13  1.1  christos     rtree_ctx_t rtree_ctx_fallback;					\
     14  1.1  christos     rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback)
     15  1.1  christos 
     16  1.1  christos typedef struct emap_s emap_t;
     17  1.1  christos struct emap_s {
     18  1.1  christos 	rtree_t rtree;
     19  1.1  christos };
     20  1.1  christos 
     21  1.1  christos /* Used to pass rtree lookup context down the path. */
     22  1.1  christos typedef struct emap_alloc_ctx_t emap_alloc_ctx_t;
     23  1.1  christos struct emap_alloc_ctx_t {
     24  1.1  christos 	szind_t szind;
     25  1.1  christos 	bool slab;
     26  1.1  christos };
     27  1.1  christos 
     28  1.1  christos typedef struct emap_full_alloc_ctx_s emap_full_alloc_ctx_t;
     29  1.1  christos struct emap_full_alloc_ctx_s {
     30  1.1  christos 	szind_t szind;
     31  1.1  christos 	bool slab;
     32  1.1  christos 	edata_t *edata;
     33  1.1  christos };
     34  1.1  christos 
     35  1.1  christos bool emap_init(emap_t *emap, base_t *base, bool zeroed);
     36  1.1  christos 
     37  1.1  christos void emap_remap(tsdn_t *tsdn, emap_t *emap, edata_t *edata, szind_t szind,
     38  1.1  christos     bool slab);
     39  1.1  christos 
     40  1.1  christos void emap_update_edata_state(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
     41  1.1  christos     extent_state_t state);
     42  1.1  christos 
     43  1.1  christos /*
     44  1.1  christos  * The two acquire functions below allow accessing neighbor edatas, if it's safe
     45  1.1  christos  * and valid to do so (i.e. from the same arena, of the same state, etc.).  This
     46  1.1  christos  * is necessary because the ecache locks are state based, and only protect
     47  1.1  christos  * edatas with the same state.  Therefore the neighbor edata's state needs to be
     48  1.1  christos  * verified first, before chasing the edata pointer.  The returned edata will be
     49  1.1  christos  * in an acquired state, meaning other threads will be prevented from accessing
     50  1.1  christos  * it, even if technically the edata can still be discovered from the rtree.
     51  1.1  christos  *
     52  1.1  christos  * This means, at any moment when holding pointers to edata, either one of the
     53  1.1  christos  * state based locks is held (and the edatas are all of the protected state), or
     54  1.1  christos  * the edatas are in an acquired state (e.g. in active or merging state).  The
     55  1.1  christos  * acquire operation itself (changing the edata to an acquired state) is done
     56  1.1  christos  * under the state locks.
     57  1.1  christos  */
     58  1.1  christos edata_t *emap_try_acquire_edata_neighbor(tsdn_t *tsdn, emap_t *emap,
     59  1.1  christos     edata_t *edata, extent_pai_t pai, extent_state_t expected_state,
     60  1.1  christos     bool forward);
     61  1.1  christos edata_t *emap_try_acquire_edata_neighbor_expand(tsdn_t *tsdn, emap_t *emap,
     62  1.1  christos     edata_t *edata, extent_pai_t pai, extent_state_t expected_state);
     63  1.1  christos void emap_release_edata(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
     64  1.1  christos     extent_state_t new_state);
     65  1.1  christos 
     66  1.1  christos /*
     67  1.1  christos  * Associate the given edata with its beginning and end address, setting the
     68  1.1  christos  * szind and slab info appropriately.
     69  1.1  christos  * Returns true on error (i.e. resource exhaustion).
     70  1.1  christos  */
     71  1.1  christos bool emap_register_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
     72  1.1  christos     szind_t szind, bool slab);
     73  1.1  christos 
     74  1.1  christos /*
     75  1.1  christos  * Does the same thing, but with the interior of the range, for slab
     76  1.1  christos  * allocations.
     77  1.1  christos  *
     78  1.1  christos  * You might wonder why we don't just have a single emap_register function that
     79  1.1  christos  * does both depending on the value of 'slab'.  The answer is twofold:
     80  1.1  christos  * - As a practical matter, in places like the extract->split->commit pathway,
     81  1.1  christos  *   we defer the interior operation until we're sure that the commit won't fail
     82  1.1  christos  *   (but we have to register the split boundaries there).
     83  1.1  christos  * - In general, we're trying to move to a world where the page-specific
     84  1.1  christos  *   allocator doesn't know as much about how the pages it allocates will be
     85  1.1  christos  *   used, and passing a 'slab' parameter everywhere makes that more
     86  1.1  christos  *   complicated.
     87  1.1  christos  *
     88  1.1  christos  * Unlike the boundary version, this function can't fail; this is because slabs
     89  1.1  christos  * can't get big enough to touch a new page that neither of the boundaries
     90  1.1  christos  * touched, so no allocation is necessary to fill the interior once the boundary
     91  1.1  christos  * has been touched.
     92  1.1  christos  */
     93  1.1  christos void emap_register_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
     94  1.1  christos     szind_t szind);
     95  1.1  christos 
     96  1.1  christos void emap_deregister_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
     97  1.1  christos void emap_deregister_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
     98  1.1  christos 
     99  1.1  christos typedef struct emap_prepare_s emap_prepare_t;
    100  1.1  christos struct emap_prepare_s {
    101  1.1  christos 	rtree_leaf_elm_t *lead_elm_a;
    102  1.1  christos 	rtree_leaf_elm_t *lead_elm_b;
    103  1.1  christos 	rtree_leaf_elm_t *trail_elm_a;
    104  1.1  christos 	rtree_leaf_elm_t *trail_elm_b;
    105  1.1  christos };
    106  1.1  christos 
    107  1.1  christos /**
    108  1.1  christos  * These functions the emap metadata management for merging, splitting, and
    109  1.1  christos  * reusing extents.  In particular, they set the boundary mappings from
    110  1.1  christos  * addresses to edatas.  If the result is going to be used as a slab, you
    111  1.1  christos  * still need to call emap_register_interior on it, though.
    112  1.1  christos  *
    113  1.1  christos  * Remap simply changes the szind and slab status of an extent's boundary
    114  1.1  christos  * mappings.  If the extent is not a slab, it doesn't bother with updating the
    115  1.1  christos  * end mapping (since lookups only occur in the interior of an extent for
    116  1.1  christos  * slabs).  Since the szind and slab status only make sense for active extents,
    117  1.1  christos  * this should only be called while activating or deactivating an extent.
    118  1.1  christos  *
    119  1.1  christos  * Split and merge have a "prepare" and a "commit" portion.  The prepare portion
    120  1.1  christos  * does the operations that can be done without exclusive access to the extent
    121  1.1  christos  * in question, while the commit variant requires exclusive access to maintain
    122  1.1  christos  * the emap invariants.  The only function that can fail is emap_split_prepare,
    123  1.1  christos  * and it returns true on failure (at which point the caller shouldn't commit).
    124  1.1  christos  *
    125  1.1  christos  * In all cases, "lead" refers to the lower-addressed extent, and trail to the
    126  1.1  christos  * higher-addressed one.  It's the caller's responsibility to set the edata
    127  1.1  christos  * state appropriately.
    128  1.1  christos  */
    129  1.1  christos bool emap_split_prepare(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
    130  1.1  christos     edata_t *edata, size_t size_a, edata_t *trail, size_t size_b);
    131  1.1  christos void emap_split_commit(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
    132  1.1  christos     edata_t *lead, size_t size_a, edata_t *trail, size_t size_b);
    133  1.1  christos void emap_merge_prepare(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
    134  1.1  christos     edata_t *lead, edata_t *trail);
    135  1.1  christos void emap_merge_commit(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
    136  1.1  christos     edata_t *lead, edata_t *trail);
    137  1.1  christos 
    138  1.1  christos /* Assert that the emap's view of the given edata matches the edata's view. */
    139  1.1  christos void emap_do_assert_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
    140  1.1  christos static inline void
    141  1.1  christos emap_assert_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
    142  1.1  christos 	if (config_debug) {
    143  1.1  christos 		emap_do_assert_mapped(tsdn, emap, edata);
    144  1.1  christos 	}
    145  1.1  christos }
    146  1.1  christos 
    147  1.1  christos /* Assert that the given edata isn't in the map. */
    148  1.1  christos void emap_do_assert_not_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
    149  1.1  christos static inline void
    150  1.1  christos emap_assert_not_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
    151  1.1  christos 	if (config_debug) {
    152  1.1  christos 		emap_do_assert_not_mapped(tsdn, emap, edata);
    153  1.1  christos 	}
    154  1.1  christos }
    155  1.1  christos 
    156  1.1  christos JEMALLOC_ALWAYS_INLINE bool
    157  1.1  christos emap_edata_in_transition(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
    158  1.1  christos 	assert(config_debug);
    159  1.1  christos 	emap_assert_mapped(tsdn, emap, edata);
    160  1.1  christos 
    161  1.1  christos 	EMAP_DECLARE_RTREE_CTX;
    162  1.1  christos 	rtree_contents_t contents = rtree_read(tsdn, &emap->rtree, rtree_ctx,
    163  1.1  christos 	    (uintptr_t)edata_base_get(edata));
    164  1.1  christos 
    165  1.1  christos 	return edata_state_in_transition(contents.metadata.state);
    166  1.1  christos }
    167  1.1  christos 
    168  1.1  christos JEMALLOC_ALWAYS_INLINE bool
    169  1.1  christos emap_edata_is_acquired(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
    170  1.1  christos 	if (!config_debug) {
    171  1.1  christos 		/* For assertions only. */
    172  1.1  christos 		return false;
    173  1.1  christos 	}
    174  1.1  christos 
    175  1.1  christos 	/*
    176  1.1  christos 	 * The edata is considered acquired if no other threads will attempt to
    177  1.1  christos 	 * read / write any fields from it.  This includes a few cases:
    178  1.1  christos 	 *
    179  1.1  christos 	 * 1) edata not hooked into emap yet -- This implies the edata just got
    180  1.1  christos 	 * allocated or initialized.
    181  1.1  christos 	 *
    182  1.1  christos 	 * 2) in an active or transition state -- In both cases, the edata can
    183  1.1  christos 	 * be discovered from the emap, however the state tracked in the rtree
    184  1.1  christos 	 * will prevent other threads from accessing the actual edata.
    185  1.1  christos 	 */
    186  1.1  christos 	EMAP_DECLARE_RTREE_CTX;
    187  1.1  christos 	rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, &emap->rtree,
    188  1.1  christos 	    rtree_ctx, (uintptr_t)edata_base_get(edata), /* dependent */ true,
    189  1.1  christos 	    /* init_missing */ false);
    190  1.1  christos 	if (elm == NULL) {
    191  1.1  christos 		return true;
    192  1.1  christos 	}
    193  1.1  christos 	rtree_contents_t contents = rtree_leaf_elm_read(tsdn, &emap->rtree, elm,
    194  1.1  christos 	    /* dependent */ true);
    195  1.1  christos 	if (contents.edata == NULL ||
    196  1.1  christos 	    contents.metadata.state == extent_state_active ||
    197  1.1  christos 	    edata_state_in_transition(contents.metadata.state)) {
    198  1.1  christos 		return true;
    199  1.1  christos 	}
    200  1.1  christos 
    201  1.1  christos 	return false;
    202  1.1  christos }
    203  1.1  christos 
    204  1.1  christos JEMALLOC_ALWAYS_INLINE void
    205  1.1  christos extent_assert_can_coalesce(const edata_t *inner, const edata_t *outer) {
    206  1.1  christos 	assert(edata_arena_ind_get(inner) == edata_arena_ind_get(outer));
    207  1.1  christos 	assert(edata_pai_get(inner) == edata_pai_get(outer));
    208  1.1  christos 	assert(edata_committed_get(inner) == edata_committed_get(outer));
    209  1.1  christos 	assert(edata_state_get(inner) == extent_state_active);
    210  1.1  christos 	assert(edata_state_get(outer) == extent_state_merging);
    211  1.1  christos 	assert(!edata_guarded_get(inner) && !edata_guarded_get(outer));
    212  1.1  christos 	assert(edata_base_get(inner) == edata_past_get(outer) ||
    213  1.1  christos 	    edata_base_get(outer) == edata_past_get(inner));
    214  1.1  christos }
    215  1.1  christos 
    216  1.1  christos JEMALLOC_ALWAYS_INLINE void
    217  1.1  christos extent_assert_can_expand(const edata_t *original, const edata_t *expand) {
    218  1.1  christos 	assert(edata_arena_ind_get(original) == edata_arena_ind_get(expand));
    219  1.1  christos 	assert(edata_pai_get(original) == edata_pai_get(expand));
    220  1.1  christos 	assert(edata_state_get(original) == extent_state_active);
    221  1.1  christos 	assert(edata_state_get(expand) == extent_state_merging);
    222  1.1  christos 	assert(edata_past_get(original) == edata_base_get(expand));
    223  1.1  christos }
    224  1.1  christos 
    225  1.1  christos JEMALLOC_ALWAYS_INLINE edata_t *
    226  1.1  christos emap_edata_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr) {
    227  1.1  christos 	EMAP_DECLARE_RTREE_CTX;
    228  1.1  christos 
    229  1.1  christos 	return rtree_read(tsdn, &emap->rtree, rtree_ctx, (uintptr_t)ptr).edata;
    230  1.1  christos }
    231  1.1  christos 
    232  1.1  christos /* Fills in alloc_ctx with the info in the map. */
    233  1.1  christos JEMALLOC_ALWAYS_INLINE void
    234  1.1  christos emap_alloc_ctx_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
    235  1.1  christos     emap_alloc_ctx_t *alloc_ctx) {
    236  1.1  christos 	EMAP_DECLARE_RTREE_CTX;
    237  1.1  christos 
    238  1.1  christos 	rtree_metadata_t metadata = rtree_metadata_read(tsdn, &emap->rtree,
    239  1.1  christos 	    rtree_ctx, (uintptr_t)ptr);
    240  1.1  christos 	alloc_ctx->szind = metadata.szind;
    241  1.1  christos 	alloc_ctx->slab = metadata.slab;
    242  1.1  christos }
    243  1.1  christos 
    244  1.1  christos /* The pointer must be mapped. */
    245  1.1  christos JEMALLOC_ALWAYS_INLINE void
    246  1.1  christos emap_full_alloc_ctx_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
    247  1.1  christos     emap_full_alloc_ctx_t *full_alloc_ctx) {
    248  1.1  christos 	EMAP_DECLARE_RTREE_CTX;
    249  1.1  christos 
    250  1.1  christos 	rtree_contents_t contents = rtree_read(tsdn, &emap->rtree, rtree_ctx,
    251  1.1  christos 	    (uintptr_t)ptr);
    252  1.1  christos 	full_alloc_ctx->edata = contents.edata;
    253  1.1  christos 	full_alloc_ctx->szind = contents.metadata.szind;
    254  1.1  christos 	full_alloc_ctx->slab = contents.metadata.slab;
    255  1.1  christos }
    256  1.1  christos 
    257  1.1  christos /*
    258  1.1  christos  * The pointer is allowed to not be mapped.
    259  1.1  christos  *
    260  1.1  christos  * Returns true when the pointer is not present.
    261  1.1  christos  */
    262  1.1  christos JEMALLOC_ALWAYS_INLINE bool
    263  1.1  christos emap_full_alloc_ctx_try_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
    264  1.1  christos     emap_full_alloc_ctx_t *full_alloc_ctx) {
    265  1.1  christos 	EMAP_DECLARE_RTREE_CTX;
    266  1.1  christos 
    267  1.1  christos 	rtree_contents_t contents;
    268  1.1  christos 	bool err = rtree_read_independent(tsdn, &emap->rtree, rtree_ctx,
    269  1.1  christos 	    (uintptr_t)ptr, &contents);
    270  1.1  christos 	if (err) {
    271  1.1  christos 		return true;
    272  1.1  christos 	}
    273  1.1  christos 	full_alloc_ctx->edata = contents.edata;
    274  1.1  christos 	full_alloc_ctx->szind = contents.metadata.szind;
    275  1.1  christos 	full_alloc_ctx->slab = contents.metadata.slab;
    276  1.1  christos 	return false;
    277  1.1  christos }
    278  1.1  christos 
    279  1.1  christos /*
    280  1.1  christos  * Only used on the fastpath of free.  Returns true when cannot be fulfilled by
    281  1.1  christos  * fast path, e.g. when the metadata key is not cached.
    282  1.1  christos  */
    283  1.1  christos JEMALLOC_ALWAYS_INLINE bool
    284  1.1  christos emap_alloc_ctx_try_lookup_fast(tsd_t *tsd, emap_t *emap, const void *ptr,
    285  1.1  christos     emap_alloc_ctx_t *alloc_ctx) {
    286  1.1  christos 	/* Use the unsafe getter since this may gets called during exit. */
    287  1.1  christos 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctxp_get_unsafe(tsd);
    288  1.1  christos 
    289  1.1  christos 	rtree_metadata_t metadata;
    290  1.1  christos 	bool err = rtree_metadata_try_read_fast(tsd_tsdn(tsd), &emap->rtree,
    291  1.1  christos 	    rtree_ctx, (uintptr_t)ptr, &metadata);
    292  1.1  christos 	if (err) {
    293  1.1  christos 		return true;
    294  1.1  christos 	}
    295  1.1  christos 	alloc_ctx->szind = metadata.szind;
    296  1.1  christos 	alloc_ctx->slab = metadata.slab;
    297  1.1  christos 	return false;
    298  1.1  christos }
    299  1.1  christos 
    300  1.1  christos /*
    301  1.1  christos  * We want to do batch lookups out of the cache bins, which use
    302  1.1  christos  * cache_bin_ptr_array_get to access the i'th element of the bin (since they
    303  1.1  christos  * invert usual ordering in deciding what to flush).  This lets the emap avoid
    304  1.1  christos  * caring about its caller's ordering.
    305  1.1  christos  */
    306  1.1  christos typedef const void *(*emap_ptr_getter)(void *ctx, size_t ind);
    307  1.1  christos /*
    308  1.1  christos  * This allows size-checking assertions, which we can only do while we're in the
    309  1.1  christos  * process of edata lookups.
    310  1.1  christos  */
    311  1.1  christos typedef void (*emap_metadata_visitor)(void *ctx, emap_full_alloc_ctx_t *alloc_ctx);
    312  1.1  christos 
    313  1.1  christos typedef union emap_batch_lookup_result_u emap_batch_lookup_result_t;
    314  1.1  christos union emap_batch_lookup_result_u {
    315  1.1  christos 	edata_t *edata;
    316  1.1  christos 	rtree_leaf_elm_t *rtree_leaf;
    317  1.1  christos };
    318  1.1  christos 
    319  1.1  christos JEMALLOC_ALWAYS_INLINE void
    320  1.1  christos emap_edata_lookup_batch(tsd_t *tsd, emap_t *emap, size_t nptrs,
    321  1.1  christos     emap_ptr_getter ptr_getter, void *ptr_getter_ctx,
    322  1.1  christos     emap_metadata_visitor metadata_visitor, void *metadata_visitor_ctx,
    323  1.1  christos     emap_batch_lookup_result_t *result) {
    324  1.1  christos 	/* Avoids null-checking tsdn in the loop below. */
    325  1.1  christos 	util_assume(tsd != NULL);
    326  1.1  christos 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctxp_get(tsd);
    327  1.1  christos 
    328  1.1  christos 	for (size_t i = 0; i < nptrs; i++) {
    329  1.1  christos 		const void *ptr = ptr_getter(ptr_getter_ctx, i);
    330  1.1  christos 		/*
    331  1.1  christos 		 * Reuse the edatas array as a temp buffer, lying a little about
    332  1.1  christos 		 * the types.
    333  1.1  christos 		 */
    334  1.1  christos 		result[i].rtree_leaf = rtree_leaf_elm_lookup(tsd_tsdn(tsd),
    335  1.1  christos 		    &emap->rtree, rtree_ctx, (uintptr_t)ptr,
    336  1.1  christos 		    /* dependent */ true, /* init_missing */ false);
    337  1.1  christos 	}
    338  1.1  christos 
    339  1.1  christos 	for (size_t i = 0; i < nptrs; i++) {
    340  1.1  christos 		rtree_leaf_elm_t *elm = result[i].rtree_leaf;
    341  1.1  christos 		rtree_contents_t contents = rtree_leaf_elm_read(tsd_tsdn(tsd),
    342  1.1  christos 		    &emap->rtree, elm, /* dependent */ true);
    343  1.1  christos 		result[i].edata = contents.edata;
    344  1.1  christos 		emap_full_alloc_ctx_t alloc_ctx;
    345  1.1  christos 		/*
    346  1.1  christos 		 * Not all these fields are read in practice by the metadata
    347  1.1  christos 		 * visitor.  But the compiler can easily optimize away the ones
    348  1.1  christos 		 * that aren't, so no sense in being incomplete.
    349  1.1  christos 		 */
    350  1.1  christos 		alloc_ctx.szind = contents.metadata.szind;
    351  1.1  christos 		alloc_ctx.slab = contents.metadata.slab;
    352  1.1  christos 		alloc_ctx.edata = contents.edata;
    353  1.1  christos 		metadata_visitor(metadata_visitor_ctx, &alloc_ctx);
    354  1.1  christos 	}
    355  1.1  christos }
    356  1.1  christos 
    357  1.1  christos #endif /* JEMALLOC_INTERNAL_EMAP_H */
    358