Home | History | Annotate | Line # | Download | only in internal
      1  1.1  christos #ifndef JEMALLOC_INTERNAL_EHOOKS_H
      2  1.1  christos #define JEMALLOC_INTERNAL_EHOOKS_H
      3  1.1  christos 
      4  1.1  christos #include "jemalloc/internal/atomic.h"
      5  1.1  christos #include "jemalloc/internal/extent_mmap.h"
      6  1.1  christos 
      7  1.1  christos /*
      8  1.1  christos  * This module is the internal interface to the extent hooks (both
      9  1.1  christos  * user-specified and external).  Eventually, this will give us the flexibility
     10  1.1  christos  * to use multiple different versions of user-visible extent-hook APIs under a
     11  1.1  christos  * single user interface.
     12  1.1  christos  *
     13  1.1  christos  * Current API expansions (not available to anyone but the default hooks yet):
     14  1.1  christos  *   - Head state tracking.  Hooks can decide whether or not to merge two
     15  1.1  christos  *     extents based on whether or not one of them is the head (i.e. was
     16  1.1  christos  *     allocated on its own).  The later extent loses its "head" status.
     17  1.1  christos  */
     18  1.1  christos 
     19  1.1  christos extern const extent_hooks_t ehooks_default_extent_hooks;
     20  1.1  christos 
     21  1.1  christos typedef struct ehooks_s ehooks_t;
     22  1.1  christos struct ehooks_s {
     23  1.1  christos 	/*
     24  1.1  christos 	 * The user-visible id that goes with the ehooks (i.e. that of the base
     25  1.1  christos 	 * they're a part of, the associated arena's index within the arenas
     26  1.1  christos 	 * array).
     27  1.1  christos 	 */
     28  1.1  christos 	unsigned ind;
     29  1.1  christos 	/* Logically an extent_hooks_t *. */
     30  1.1  christos 	atomic_p_t ptr;
     31  1.1  christos };
     32  1.1  christos 
     33  1.1  christos extern const extent_hooks_t ehooks_default_extent_hooks;
     34  1.1  christos 
     35  1.1  christos /*
     36  1.1  christos  * These are not really part of the public API.  Each hook has a fast-path for
     37  1.1  christos  * the default-hooks case that can avoid various small inefficiencies:
     38  1.1  christos  *   - Forgetting tsd and then calling tsd_get within the hook.
     39  1.1  christos  *   - Getting more state than necessary out of the extent_t.
     40  1.1  christos  *   - Doing arena_ind -> arena -> arena_ind lookups.
     41  1.1  christos  * By making the calls to these functions visible to the compiler, it can move
     42  1.1  christos  * those extra bits of computation down below the fast-paths where they get ignored.
     43  1.1  christos  */
     44  1.1  christos void *ehooks_default_alloc_impl(tsdn_t *tsdn, void *new_addr, size_t size,
     45  1.1  christos     size_t alignment, bool *zero, bool *commit, unsigned arena_ind);
     46  1.1  christos bool ehooks_default_dalloc_impl(void *addr, size_t size);
     47  1.1  christos void ehooks_default_destroy_impl(void *addr, size_t size);
     48  1.1  christos bool ehooks_default_commit_impl(void *addr, size_t offset, size_t length);
     49  1.1  christos bool ehooks_default_decommit_impl(void *addr, size_t offset, size_t length);
     50  1.1  christos #ifdef PAGES_CAN_PURGE_LAZY
     51  1.1  christos bool ehooks_default_purge_lazy_impl(void *addr, size_t offset, size_t length);
     52  1.1  christos #endif
     53  1.1  christos #ifdef PAGES_CAN_PURGE_FORCED
     54  1.1  christos bool ehooks_default_purge_forced_impl(void *addr, size_t offset, size_t length);
     55  1.1  christos #endif
     56  1.1  christos bool ehooks_default_split_impl(void);
     57  1.1  christos /*
     58  1.1  christos  * Merge is the only default extent hook we declare -- see the comment in
     59  1.1  christos  * ehooks_merge.
     60  1.1  christos  */
     61  1.1  christos bool ehooks_default_merge(extent_hooks_t *extent_hooks, void *addr_a,
     62  1.1  christos     size_t size_a, void *addr_b, size_t size_b, bool committed,
     63  1.1  christos     unsigned arena_ind);
     64  1.1  christos bool ehooks_default_merge_impl(tsdn_t *tsdn, void *addr_a, void *addr_b);
     65  1.1  christos void ehooks_default_zero_impl(void *addr, size_t size);
     66  1.1  christos void ehooks_default_guard_impl(void *guard1, void *guard2);
     67  1.1  christos void ehooks_default_unguard_impl(void *guard1, void *guard2);
     68  1.1  christos 
     69  1.1  christos /*
     70  1.1  christos  * We don't officially support reentrancy from wtihin the extent hooks.  But
     71  1.1  christos  * various people who sit within throwing distance of the jemalloc team want
     72  1.1  christos  * that functionality in certain limited cases.  The default reentrancy guards
     73  1.1  christos  * assert that we're not reentrant from a0 (since it's the bootstrap arena,
     74  1.1  christos  * where reentrant allocations would be redirected), which we would incorrectly
     75  1.1  christos  * trigger in cases where a0 has extent hooks (those hooks themselves can't be
     76  1.1  christos  * reentrant, then, but there are reasonable uses for such functionality, like
     77  1.1  christos  * putting internal metadata on hugepages).  Therefore, we use the raw
     78  1.1  christos  * reentrancy guards.
     79  1.1  christos  *
     80  1.1  christos  * Eventually, we need to think more carefully about whether and where we
     81  1.1  christos  * support allocating from within extent hooks (and what that means for things
     82  1.1  christos  * like profiling, stats collection, etc.), and document what the guarantee is.
     83  1.1  christos  */
     84  1.1  christos static inline void
     85  1.1  christos ehooks_pre_reentrancy(tsdn_t *tsdn) {
     86  1.1  christos 	tsd_t *tsd = tsdn_null(tsdn) ? tsd_fetch() : tsdn_tsd(tsdn);
     87  1.1  christos 	tsd_pre_reentrancy_raw(tsd);
     88  1.1  christos }
     89  1.1  christos 
     90  1.1  christos static inline void
     91  1.1  christos ehooks_post_reentrancy(tsdn_t *tsdn) {
     92  1.1  christos 	tsd_t *tsd = tsdn_null(tsdn) ? tsd_fetch() : tsdn_tsd(tsdn);
     93  1.1  christos 	tsd_post_reentrancy_raw(tsd);
     94  1.1  christos }
     95  1.1  christos 
     96  1.1  christos /* Beginning of the public API. */
     97  1.1  christos void ehooks_init(ehooks_t *ehooks, extent_hooks_t *extent_hooks, unsigned ind);
     98  1.1  christos 
     99  1.1  christos static inline unsigned
    100  1.1  christos ehooks_ind_get(const ehooks_t *ehooks) {
    101  1.1  christos 	return ehooks->ind;
    102  1.1  christos }
    103  1.1  christos 
    104  1.1  christos static inline void
    105  1.1  christos ehooks_set_extent_hooks_ptr(ehooks_t *ehooks, extent_hooks_t *extent_hooks) {
    106  1.1  christos 	atomic_store_p(&ehooks->ptr, extent_hooks, ATOMIC_RELEASE);
    107  1.1  christos }
    108  1.1  christos 
    109  1.1  christos static inline extent_hooks_t *
    110  1.1  christos ehooks_get_extent_hooks_ptr(ehooks_t *ehooks) {
    111  1.1  christos 	return (extent_hooks_t *)atomic_load_p(&ehooks->ptr, ATOMIC_ACQUIRE);
    112  1.1  christos }
    113  1.1  christos 
    114  1.1  christos static inline bool
    115  1.1  christos ehooks_are_default(ehooks_t *ehooks) {
    116  1.1  christos 	return ehooks_get_extent_hooks_ptr(ehooks) ==
    117  1.1  christos 	    &ehooks_default_extent_hooks;
    118  1.1  christos }
    119  1.1  christos 
    120  1.1  christos /*
    121  1.1  christos  * In some cases, a caller needs to allocate resources before attempting to call
    122  1.1  christos  * a hook.  If that hook is doomed to fail, this is wasteful.  We therefore
    123  1.1  christos  * include some checks for such cases.
    124  1.1  christos  */
    125  1.1  christos static inline bool
    126  1.1  christos ehooks_dalloc_will_fail(ehooks_t *ehooks) {
    127  1.1  christos 	if (ehooks_are_default(ehooks)) {
    128  1.1  christos 		return opt_retain;
    129  1.1  christos 	} else {
    130  1.1  christos 		return ehooks_get_extent_hooks_ptr(ehooks)->dalloc == NULL;
    131  1.1  christos 	}
    132  1.1  christos }
    133  1.1  christos 
    134  1.1  christos static inline bool
    135  1.1  christos ehooks_split_will_fail(ehooks_t *ehooks) {
    136  1.1  christos 	return ehooks_get_extent_hooks_ptr(ehooks)->split == NULL;
    137  1.1  christos }
    138  1.1  christos 
    139  1.1  christos static inline bool
    140  1.1  christos ehooks_merge_will_fail(ehooks_t *ehooks) {
    141  1.1  christos 	return ehooks_get_extent_hooks_ptr(ehooks)->merge == NULL;
    142  1.1  christos }
    143  1.1  christos 
    144  1.1  christos static inline bool
    145  1.1  christos ehooks_guard_will_fail(ehooks_t *ehooks) {
    146  1.1  christos 	/*
    147  1.1  christos 	 * Before the guard hooks are officially introduced, limit the use to
    148  1.1  christos 	 * the default hooks only.
    149  1.1  christos 	 */
    150  1.1  christos 	return !ehooks_are_default(ehooks);
    151  1.1  christos }
    152  1.1  christos 
    153  1.1  christos /*
    154  1.1  christos  * Some hooks are required to return zeroed memory in certain situations.  In
    155  1.1  christos  * debug mode, we do some heuristic checks that they did what they were supposed
    156  1.1  christos  * to.
    157  1.1  christos  *
    158  1.1  christos  * This isn't really ehooks-specific (i.e. anyone can check for zeroed memory).
    159  1.1  christos  * But incorrect zero information indicates an ehook bug.
    160  1.1  christos  */
    161  1.1  christos static inline void
    162  1.1  christos ehooks_debug_zero_check(void *addr, size_t size) {
    163  1.1  christos 	assert(((uintptr_t)addr & PAGE_MASK) == 0);
    164  1.1  christos 	assert((size & PAGE_MASK) == 0);
    165  1.1  christos 	assert(size > 0);
    166  1.1  christos 	if (config_debug) {
    167  1.1  christos 		/* Check the whole first page. */
    168  1.1  christos 		size_t *p = (size_t *)addr;
    169  1.1  christos 		for (size_t i = 0; i < PAGE / sizeof(size_t); i++) {
    170  1.1  christos 			assert(p[i] == 0);
    171  1.1  christos 		}
    172  1.1  christos 		/*
    173  1.1  christos 		 * And 4 spots within.  There's a tradeoff here; the larger
    174  1.1  christos 		 * this number, the more likely it is that we'll catch a bug
    175  1.1  christos 		 * where ehooks return a sparsely non-zero range.  But
    176  1.1  christos 		 * increasing the number of checks also increases the number of
    177  1.1  christos 		 * page faults in debug mode.  FreeBSD does much of their
    178  1.1  christos 		 * day-to-day development work in debug mode, so we don't want
    179  1.1  christos 		 * even the debug builds to be too slow.
    180  1.1  christos 		 */
    181  1.1  christos 		const size_t nchecks = 4;
    182  1.1  christos 		assert(PAGE >= sizeof(size_t) * nchecks);
    183  1.1  christos 		for (size_t i = 0; i < nchecks; ++i) {
    184  1.1  christos 			assert(p[i * (size / sizeof(size_t) / nchecks)] == 0);
    185  1.1  christos 		}
    186  1.1  christos 	}
    187  1.1  christos }
    188  1.1  christos 
    189  1.1  christos 
    190  1.1  christos static inline void *
    191  1.1  christos ehooks_alloc(tsdn_t *tsdn, ehooks_t *ehooks, void *new_addr, size_t size,
    192  1.1  christos     size_t alignment, bool *zero, bool *commit) {
    193  1.1  christos 	bool orig_zero = *zero;
    194  1.1  christos 	void *ret;
    195  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    196  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    197  1.1  christos 		ret = ehooks_default_alloc_impl(tsdn, new_addr, size,
    198  1.1  christos 		    alignment, zero, commit, ehooks_ind_get(ehooks));
    199  1.1  christos 	} else {
    200  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    201  1.1  christos 		ret = extent_hooks->alloc(extent_hooks, new_addr, size,
    202  1.1  christos 		    alignment, zero, commit, ehooks_ind_get(ehooks));
    203  1.1  christos 		ehooks_post_reentrancy(tsdn);
    204  1.1  christos 	}
    205  1.1  christos 	assert(new_addr == NULL || ret == NULL || new_addr == ret);
    206  1.1  christos 	assert(!orig_zero || *zero);
    207  1.1  christos 	if (*zero && ret != NULL) {
    208  1.1  christos 		ehooks_debug_zero_check(ret, size);
    209  1.1  christos 	}
    210  1.1  christos 	return ret;
    211  1.1  christos }
    212  1.1  christos 
    213  1.1  christos static inline bool
    214  1.1  christos ehooks_dalloc(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
    215  1.1  christos     bool committed) {
    216  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    217  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    218  1.1  christos 		return ehooks_default_dalloc_impl(addr, size);
    219  1.1  christos 	} else if (extent_hooks->dalloc == NULL) {
    220  1.1  christos 		return true;
    221  1.1  christos 	} else {
    222  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    223  1.1  christos 		bool err = extent_hooks->dalloc(extent_hooks, addr, size,
    224  1.1  christos 		    committed, ehooks_ind_get(ehooks));
    225  1.1  christos 		ehooks_post_reentrancy(tsdn);
    226  1.1  christos 		return err;
    227  1.1  christos 	}
    228  1.1  christos }
    229  1.1  christos 
    230  1.1  christos static inline void
    231  1.1  christos ehooks_destroy(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
    232  1.1  christos     bool committed) {
    233  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    234  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    235  1.1  christos 		ehooks_default_destroy_impl(addr, size);
    236  1.1  christos 	} else if (extent_hooks->destroy == NULL) {
    237  1.1  christos 		/* Do nothing. */
    238  1.1  christos 	} else {
    239  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    240  1.1  christos 		extent_hooks->destroy(extent_hooks, addr, size, committed,
    241  1.1  christos 		    ehooks_ind_get(ehooks));
    242  1.1  christos 		ehooks_post_reentrancy(tsdn);
    243  1.1  christos 	}
    244  1.1  christos }
    245  1.1  christos 
    246  1.1  christos static inline bool
    247  1.1  christos ehooks_commit(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
    248  1.1  christos     size_t offset, size_t length) {
    249  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    250  1.1  christos 	bool err;
    251  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    252  1.1  christos 		err = ehooks_default_commit_impl(addr, offset, length);
    253  1.1  christos 	} else if (extent_hooks->commit == NULL) {
    254  1.1  christos 		err = true;
    255  1.1  christos 	} else {
    256  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    257  1.1  christos 		err = extent_hooks->commit(extent_hooks, addr, size,
    258  1.1  christos 		    offset, length, ehooks_ind_get(ehooks));
    259  1.1  christos 		ehooks_post_reentrancy(tsdn);
    260  1.1  christos 	}
    261  1.1  christos 	if (!err) {
    262  1.1  christos 		ehooks_debug_zero_check(addr, size);
    263  1.1  christos 	}
    264  1.1  christos 	return err;
    265  1.1  christos }
    266  1.1  christos 
    267  1.1  christos static inline bool
    268  1.1  christos ehooks_decommit(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
    269  1.1  christos     size_t offset, size_t length) {
    270  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    271  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    272  1.1  christos 		return ehooks_default_decommit_impl(addr, offset, length);
    273  1.1  christos 	} else if (extent_hooks->decommit == NULL) {
    274  1.1  christos 		return true;
    275  1.1  christos 	} else {
    276  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    277  1.1  christos 		bool err = extent_hooks->decommit(extent_hooks, addr, size,
    278  1.1  christos 		    offset, length, ehooks_ind_get(ehooks));
    279  1.1  christos 		ehooks_post_reentrancy(tsdn);
    280  1.1  christos 		return err;
    281  1.1  christos 	}
    282  1.1  christos }
    283  1.1  christos 
    284  1.1  christos static inline bool
    285  1.1  christos ehooks_purge_lazy(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
    286  1.1  christos     size_t offset, size_t length) {
    287  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    288  1.1  christos #ifdef PAGES_CAN_PURGE_LAZY
    289  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    290  1.1  christos 		return ehooks_default_purge_lazy_impl(addr, offset, length);
    291  1.1  christos 	}
    292  1.1  christos #endif
    293  1.1  christos 	if (extent_hooks->purge_lazy == NULL) {
    294  1.1  christos 		return true;
    295  1.1  christos 	} else {
    296  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    297  1.1  christos 		bool err = extent_hooks->purge_lazy(extent_hooks, addr, size,
    298  1.1  christos 		    offset, length, ehooks_ind_get(ehooks));
    299  1.1  christos 		ehooks_post_reentrancy(tsdn);
    300  1.1  christos 		return err;
    301  1.1  christos 	}
    302  1.1  christos }
    303  1.1  christos 
    304  1.1  christos static inline bool
    305  1.1  christos ehooks_purge_forced(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
    306  1.1  christos     size_t offset, size_t length) {
    307  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    308  1.1  christos 	/*
    309  1.1  christos 	 * It would be correct to have a ehooks_debug_zero_check call at the end
    310  1.1  christos 	 * of this function; purge_forced is required to zero.  But checking
    311  1.1  christos 	 * would touch the page in question, which may have performance
    312  1.1  christos 	 * consequences (imagine the hooks are using hugepages, with a global
    313  1.1  christos 	 * zero page off).  Even in debug mode, it's usually a good idea to
    314  1.1  christos 	 * avoid cases that can dramatically increase memory consumption.
    315  1.1  christos 	 */
    316  1.1  christos #ifdef PAGES_CAN_PURGE_FORCED
    317  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    318  1.1  christos 		return ehooks_default_purge_forced_impl(addr, offset, length);
    319  1.1  christos 	}
    320  1.1  christos #endif
    321  1.1  christos 	if (extent_hooks->purge_forced == NULL) {
    322  1.1  christos 		return true;
    323  1.1  christos 	} else {
    324  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    325  1.1  christos 		bool err = extent_hooks->purge_forced(extent_hooks, addr, size,
    326  1.1  christos 		    offset, length, ehooks_ind_get(ehooks));
    327  1.1  christos 		ehooks_post_reentrancy(tsdn);
    328  1.1  christos 		return err;
    329  1.1  christos 	}
    330  1.1  christos }
    331  1.1  christos 
    332  1.1  christos static inline bool
    333  1.1  christos ehooks_split(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
    334  1.1  christos     size_t size_a, size_t size_b, bool committed) {
    335  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    336  1.1  christos 	if (ehooks_are_default(ehooks)) {
    337  1.1  christos 		return ehooks_default_split_impl();
    338  1.1  christos 	} else if (extent_hooks->split == NULL) {
    339  1.1  christos 		return true;
    340  1.1  christos 	} else {
    341  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    342  1.1  christos 		bool err = extent_hooks->split(extent_hooks, addr, size, size_a,
    343  1.1  christos 		    size_b, committed, ehooks_ind_get(ehooks));
    344  1.1  christos 		ehooks_post_reentrancy(tsdn);
    345  1.1  christos 		return err;
    346  1.1  christos 	}
    347  1.1  christos }
    348  1.1  christos 
    349  1.1  christos static inline bool
    350  1.1  christos ehooks_merge(tsdn_t *tsdn, ehooks_t *ehooks, void *addr_a, size_t size_a,
    351  1.1  christos     void *addr_b, size_t size_b, bool committed) {
    352  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    353  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    354  1.1  christos 		return ehooks_default_merge_impl(tsdn, addr_a, addr_b);
    355  1.1  christos 	} else if (extent_hooks->merge == NULL) {
    356  1.1  christos 		return true;
    357  1.1  christos 	} else {
    358  1.1  christos 		ehooks_pre_reentrancy(tsdn);
    359  1.1  christos 		bool err = extent_hooks->merge(extent_hooks, addr_a, size_a,
    360  1.1  christos 		    addr_b, size_b, committed, ehooks_ind_get(ehooks));
    361  1.1  christos 		ehooks_post_reentrancy(tsdn);
    362  1.1  christos 		return err;
    363  1.1  christos 	}
    364  1.1  christos }
    365  1.1  christos 
    366  1.1  christos static inline void
    367  1.1  christos ehooks_zero(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size) {
    368  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    369  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    370  1.1  christos 		ehooks_default_zero_impl(addr, size);
    371  1.1  christos 	} else {
    372  1.1  christos 		/*
    373  1.1  christos 		 * It would be correct to try using the user-provided purge
    374  1.1  christos 		 * hooks (since they are required to have zeroed the extent if
    375  1.1  christos 		 * they indicate success), but we don't necessarily know their
    376  1.1  christos 		 * cost.  We'll be conservative and use memset.
    377  1.1  christos 		 */
    378  1.1  christos 		memset(addr, 0, size);
    379  1.1  christos 	}
    380  1.1  christos }
    381  1.1  christos 
    382  1.1  christos static inline bool
    383  1.1  christos ehooks_guard(tsdn_t *tsdn, ehooks_t *ehooks, void *guard1, void *guard2) {
    384  1.1  christos 	bool err;
    385  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    386  1.1  christos 
    387  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    388  1.1  christos 		ehooks_default_guard_impl(guard1, guard2);
    389  1.1  christos 		err = false;
    390  1.1  christos 	} else {
    391  1.1  christos 		err = true;
    392  1.1  christos 	}
    393  1.1  christos 
    394  1.1  christos 	return err;
    395  1.1  christos }
    396  1.1  christos 
    397  1.1  christos static inline bool
    398  1.1  christos ehooks_unguard(tsdn_t *tsdn, ehooks_t *ehooks, void *guard1, void *guard2) {
    399  1.1  christos 	bool err;
    400  1.1  christos 	extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
    401  1.1  christos 
    402  1.1  christos 	if (extent_hooks == &ehooks_default_extent_hooks) {
    403  1.1  christos 		ehooks_default_unguard_impl(guard1, guard2);
    404  1.1  christos 		err = false;
    405  1.1  christos 	} else {
    406  1.1  christos 		err = true;
    407  1.1  christos 	}
    408  1.1  christos 
    409  1.1  christos 	return err;
    410  1.1  christos }
    411  1.1  christos 
    412  1.1  christos #endif /* JEMALLOC_INTERNAL_EHOOKS_H */
    413