Possibly free pages and check if free space is available
| 1277 | |
| 1278 | // Possibly free pages and check if free space is available |
| 1279 | static bool mi_segment_check_free(mi_segment_t* segment, size_t slices_needed, size_t block_size, mi_segments_tld_t* tld) |
| 1280 | { |
| 1281 | mi_assert_internal(block_size < MI_HUGE_BLOCK_SIZE); |
| 1282 | mi_assert_internal(mi_segment_is_abandoned(segment)); |
| 1283 | bool has_page = false; |
| 1284 | |
| 1285 | // for all slices |
| 1286 | const mi_slice_t* end; |
| 1287 | mi_slice_t* slice = mi_slices_start_iterate(segment, &end); |
| 1288 | while (slice < end) { |
| 1289 | mi_assert_internal(slice->slice_count > 0); |
| 1290 | mi_assert_internal(slice->slice_offset == 0); |
| 1291 | if (mi_slice_is_used(slice)) { // used page |
| 1292 | // ensure used count is up to date and collect potential concurrent frees |
| 1293 | mi_page_t* const page = mi_slice_to_page(slice); |
| 1294 | _mi_page_free_collect(page, false); |
| 1295 | if (mi_page_all_free(page)) { |
| 1296 | // if this page is all free now, free it without adding to any queues (yet) |
| 1297 | mi_assert_internal(page->next == NULL && page->prev==NULL); |
| 1298 | _mi_stat_decrease(&tld->stats->pages_abandoned, 1); |
| 1299 | segment->abandoned--; |
| 1300 | slice = mi_segment_page_clear(page, tld); // re-assign slice due to coalesce! |
| 1301 | mi_assert_internal(!mi_slice_is_used(slice)); |
| 1302 | if (slice->slice_count >= slices_needed) { |
| 1303 | has_page = true; |
| 1304 | } |
| 1305 | } |
| 1306 | else { |
| 1307 | if (page->xblock_size == block_size && mi_page_has_any_available(page)) { |
| 1308 | // a page has available free blocks of the right size |
| 1309 | has_page = true; |
| 1310 | } |
| 1311 | } |
| 1312 | } |
| 1313 | else { |
| 1314 | // empty span |
| 1315 | if (slice->slice_count >= slices_needed) { |
| 1316 | has_page = true; |
| 1317 | } |
| 1318 | } |
| 1319 | slice = slice + slice->slice_count; |
| 1320 | } |
| 1321 | return has_page; |
| 1322 | } |
| 1323 | |
| 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. |
no test coverage detected