Reclaim an abandoned segment; returns NULL if the segment was freed set `right_page_reclaimed` to `true` if it reclaimed a page of the right `block_size` that was not full.
| 1324 | // Reclaim an abandoned segment; returns NULL if the segment was freed |
| 1325 | // set `right_page_reclaimed` to `true` if it reclaimed a page of the right `block_size` that was not full. |
| 1326 | static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, size_t requested_block_size, bool* right_page_reclaimed, mi_segments_tld_t* tld) { |
| 1327 | mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); |
| 1328 | mi_assert_expensive(mi_segment_is_valid(segment, tld)); |
| 1329 | if (right_page_reclaimed != NULL) { *right_page_reclaimed = false; } |
| 1330 | |
| 1331 | segment->thread_id = _mi_thread_id(); |
| 1332 | segment->abandoned_visits = 0; |
| 1333 | mi_segments_track_size((long)mi_segment_size(segment), tld); |
| 1334 | mi_assert_internal(segment->next == NULL); |
| 1335 | _mi_stat_decrease(&tld->stats->segments_abandoned, 1); |
| 1336 | |
| 1337 | // for all slices |
| 1338 | const mi_slice_t* end; |
| 1339 | mi_slice_t* slice = mi_slices_start_iterate(segment, &end); |
| 1340 | while (slice < end) { |
| 1341 | mi_assert_internal(slice->slice_count > 0); |
| 1342 | mi_assert_internal(slice->slice_offset == 0); |
| 1343 | if (mi_slice_is_used(slice)) { |
| 1344 | // in use: reclaim the page in our heap |
| 1345 | mi_page_t* page = mi_slice_to_page(slice); |
| 1346 | mi_assert_internal(!page->is_reset); |
| 1347 | mi_assert_internal(page->is_committed); |
| 1348 | mi_assert_internal(mi_page_thread_free_flag(page)==MI_NEVER_DELAYED_FREE); |
| 1349 | mi_assert_internal(mi_page_heap(page) == NULL); |
| 1350 | mi_assert_internal(page->next == NULL && page->prev==NULL); |
| 1351 | _mi_stat_decrease(&tld->stats->pages_abandoned, 1); |
| 1352 | segment->abandoned--; |
| 1353 | // set the heap again and allow delayed free again |
| 1354 | mi_page_set_heap(page, heap); |
| 1355 | _mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE, true); // override never (after heap is set) |
| 1356 | _mi_page_free_collect(page, false); // ensure used count is up to date |
| 1357 | if (mi_page_all_free(page)) { |
| 1358 | // if everything free by now, free the page |
| 1359 | slice = mi_segment_page_clear(page, tld); // set slice again due to coalesceing |
| 1360 | } |
| 1361 | else { |
| 1362 | // otherwise reclaim it into the heap |
| 1363 | _mi_page_reclaim(heap, page); |
| 1364 | if (requested_block_size == page->xblock_size && mi_page_has_any_available(page)) { |
| 1365 | if (right_page_reclaimed != NULL) { *right_page_reclaimed = true; } |
| 1366 | } |
| 1367 | } |
| 1368 | } |
| 1369 | else { |
| 1370 | // the span is free, add it to our page queues |
| 1371 | slice = mi_segment_span_free_coalesce(slice, tld); // set slice again due to coalesceing |
| 1372 | } |
| 1373 | mi_assert_internal(slice->slice_count>0 && slice->slice_offset==0); |
| 1374 | slice = slice + slice->slice_count; |
| 1375 | } |
| 1376 | |
| 1377 | mi_assert(segment->abandoned == 0); |
| 1378 | if (segment->used == 0) { // due to page_clear |
| 1379 | mi_assert_internal(right_page_reclaimed == NULL || !(*right_page_reclaimed)); |
| 1380 | mi_segment_free(segment, false, tld); |
| 1381 | return NULL; |
| 1382 | } |
| 1383 | else { |
no test coverage detected