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