Home | History | Annotate | Line # | Download | only in internal
      1 #ifndef JEMALLOC_INTERNAL_EXTENT_H
      2 #define JEMALLOC_INTERNAL_EXTENT_H
      3 
      4 #include "jemalloc/internal/ecache.h"
      5 #include "jemalloc/internal/ehooks.h"
      6 #include "jemalloc/internal/ph.h"
      7 #include "jemalloc/internal/rtree.h"
      8 
      9 /*
     10  * This module contains the page-level allocator.  It chooses the addresses that
     11  * allocations requested by other modules will inhabit, and updates the global
     12  * metadata to reflect allocation/deallocation/purging decisions.
     13  */
     14 
     15 /*
     16  * When reuse (and split) an active extent, (1U << opt_lg_extent_max_active_fit)
     17  * is the max ratio between the size of the active extent and the new extent.
     18  */
     19 #define LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT 6
     20 extern size_t opt_lg_extent_max_active_fit;
     21 
     22 edata_t *ecache_alloc(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     23     ecache_t *ecache, edata_t *expand_edata, size_t size, size_t alignment,
     24     bool zero, bool guarded);
     25 edata_t *ecache_alloc_grow(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     26     ecache_t *ecache, edata_t *expand_edata, size_t size, size_t alignment,
     27     bool zero, bool guarded);
     28 void ecache_dalloc(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     29     ecache_t *ecache, edata_t *edata);
     30 edata_t *ecache_evict(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     31     ecache_t *ecache, size_t npages_min);
     32 
     33 void extent_gdump_add(tsdn_t *tsdn, const edata_t *edata);
     34 void extent_record(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
     35     edata_t *edata);
     36 void extent_dalloc_gap(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     37     edata_t *edata);
     38 edata_t *extent_alloc_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     39     void *new_addr, size_t size, size_t alignment, bool zero, bool *commit,
     40     bool growing_retained);
     41 void extent_dalloc_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     42     edata_t *edata);
     43 void extent_destroy_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     44     edata_t *edata);
     45 bool extent_commit_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
     46     size_t offset, size_t length);
     47 bool extent_decommit_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
     48     size_t offset, size_t length);
     49 bool extent_purge_lazy_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
     50     size_t offset, size_t length);
     51 bool extent_purge_forced_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
     52     size_t offset, size_t length);
     53 edata_t *extent_split_wrapper(tsdn_t *tsdn, pac_t *pac,
     54     ehooks_t *ehooks, edata_t *edata, size_t size_a, size_t size_b,
     55     bool holding_core_locks);
     56 bool extent_merge_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
     57     edata_t *a, edata_t *b);
     58 bool extent_commit_zero(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
     59     bool commit, bool zero, bool growing_retained);
     60 size_t extent_sn_next(pac_t *pac);
     61 bool extent_boot(void);
     62 
     63 JEMALLOC_ALWAYS_INLINE bool
     64 extent_neighbor_head_state_mergeable(bool edata_is_head,
     65     bool neighbor_is_head, bool forward) {
     66 	/*
     67 	 * Head states checking: disallow merging if the higher addr extent is a
     68 	 * head extent.  This helps preserve first-fit, and more importantly
     69 	 * makes sure no merge across arenas.
     70 	 */
     71 	if (forward) {
     72 		if (neighbor_is_head) {
     73 			return false;
     74 		}
     75 	} else {
     76 		if (edata_is_head) {
     77 			return false;
     78 		}
     79 	}
     80 	return true;
     81 }
     82 
     83 JEMALLOC_ALWAYS_INLINE bool
     84 extent_can_acquire_neighbor(edata_t *edata, rtree_contents_t contents,
     85     extent_pai_t pai, extent_state_t expected_state, bool forward,
     86     bool expanding) {
     87 	edata_t *neighbor = contents.edata;
     88 	if (neighbor == NULL) {
     89 		return false;
     90 	}
     91 	/* It's not safe to access *neighbor yet; must verify states first. */
     92 	bool neighbor_is_head = contents.metadata.is_head;
     93 	if (!extent_neighbor_head_state_mergeable(edata_is_head_get(edata),
     94 	    neighbor_is_head, forward)) {
     95 		return false;
     96 	}
     97 	extent_state_t neighbor_state = contents.metadata.state;
     98 	if (pai == EXTENT_PAI_PAC) {
     99 		if (neighbor_state != expected_state) {
    100 			return false;
    101 		}
    102 		/* From this point, it's safe to access *neighbor. */
    103 		if (!expanding && (edata_committed_get(edata) !=
    104 		    edata_committed_get(neighbor))) {
    105 			/*
    106 			 * Some platforms (e.g. Windows) require an explicit
    107 			 * commit step (and writing to uncommitted memory is not
    108 			 * allowed).
    109 			 */
    110 			return false;
    111 		}
    112 	} else {
    113 		if (neighbor_state == extent_state_active) {
    114 			return false;
    115 		}
    116 		/* From this point, it's safe to access *neighbor. */
    117 	}
    118 
    119 	assert(edata_pai_get(edata) == pai);
    120 	if (edata_pai_get(neighbor) != pai) {
    121 		return false;
    122 	}
    123 	if (opt_retain) {
    124 		assert(edata_arena_ind_get(edata) ==
    125 		    edata_arena_ind_get(neighbor));
    126 	} else {
    127 		if (edata_arena_ind_get(edata) !=
    128 		    edata_arena_ind_get(neighbor)) {
    129 			return false;
    130 		}
    131 	}
    132 	assert(!edata_guarded_get(edata) && !edata_guarded_get(neighbor));
    133 
    134 	return true;
    135 }
    136 
    137 #endif /* JEMALLOC_INTERNAL_EXTENT_H */
    138