// Abandon a page with used blocks at the end of a thread. // Note: only call if it is ensured that no references exist from // the `page->heap->thread_delayed_free` into this page. // Currently only called through `mi_heap_collect_ex` which ensures this. private static partial void _mi_page_abandon(mi_page_t *page, mi_page_queue_t *pq) { mi_assert_internal((MI_DEBUG > 1) && (page != null)); mi_assert_expensive((MI_DEBUG > 2) && _mi_page_is_valid(page)); mi_assert_internal((MI_DEBUG > 1) && (pq == mi_page_queue_of(page))); mi_assert_internal((MI_DEBUG > 1) && (mi_page_heap(page) != null)); mi_heap_t *pheap = mi_page_heap(page); // remove from our page list mi_segments_tld_t *segments_tld = &pheap->tld->segments; mi_page_queue_remove(pq, page); // page is no longer associated with our heap mi_assert_internal((MI_DEBUG > 1) && (mi_page_thread_free_flag(page) == MI_NEVER_DELAYED_FREE)); mi_page_set_heap(page, null); if (MI_DEBUG > 1) { // check there are no references left.. for (mi_block_t *block = (mi_block_t *)pheap->thread_delayed_free; block != null; block = mi_block_nextx(pheap, block, &pheap->keys.e0)) { mi_assert_internal((MI_DEBUG > 1) && (_mi_ptr_page(block) != page)); } } // and abandon it mi_assert_internal((MI_DEBUG > 1) && (mi_page_heap(page) == null)); _mi_segment_page_abandon(page, segments_tld); }
// Free a page with no more free blocks private static partial void _mi_page_free(mi_page_t *page, mi_page_queue_t *pq, bool force) { mi_assert_internal((MI_DEBUG > 1) && (page != null)); mi_assert_expensive((MI_DEBUG > 2) && _mi_page_is_valid(page)); mi_assert_internal((MI_DEBUG > 1) && (pq == mi_page_queue_of(page))); mi_assert_internal((MI_DEBUG > 1) && mi_page_all_free(page)); mi_assert_internal((MI_DEBUG > 1) && (mi_page_thread_free_flag(page) != MI_DELAYED_FREEING)); // no more aligned blocks in here mi_page_set_has_aligned(page, false); // remove from the page list // (no need to do _mi_heap_delayed_free first as all blocks are already free) mi_segments_tld_t *segments_tld = &mi_page_heap(page)->tld->segments; mi_page_queue_remove(pq, page); // and free it mi_page_set_heap(page, null); _mi_segment_page_free(page, force, segments_tld); }