Allocate a segment from the OS aligned to `MI_SEGMENT_SIZE` .
| 845 | |
| 846 | // Allocate a segment from the OS aligned to `MI_SEGMENT_SIZE` . |
| 847 | static mi_segment_t* mi_segment_alloc(size_t required, size_t page_alignment, mi_arena_id_t req_arena_id, mi_segments_tld_t* tld, mi_os_tld_t* os_tld, mi_page_t** huge_page) |
| 848 | { |
| 849 | mi_assert_internal((required==0 && huge_page==NULL) || (required>0 && huge_page != NULL)); |
| 850 | |
| 851 | // calculate needed sizes first |
| 852 | size_t info_slices; |
| 853 | size_t pre_size; |
| 854 | size_t segment_slices = mi_segment_calculate_slices(required, &pre_size, &info_slices); |
| 855 | |
| 856 | // Commit eagerly only if not the first N lazy segments (to reduce impact of many threads that allocate just a little) |
| 857 | const bool eager_delay = (// !_mi_os_has_overcommit() && // never delay on overcommit systems |
| 858 | _mi_current_thread_count() > 1 && // do not delay for the first N threads |
| 859 | tld->count < (size_t)mi_option_get(mi_option_eager_commit_delay)); |
| 860 | const bool eager = !eager_delay && mi_option_is_enabled(mi_option_eager_commit); |
| 861 | bool commit = eager || (required > 0); |
| 862 | bool is_zero = false; |
| 863 | |
| 864 | mi_commit_mask_t commit_mask; |
| 865 | mi_commit_mask_t decommit_mask; |
| 866 | mi_commit_mask_create_empty(&commit_mask); |
| 867 | mi_commit_mask_create_empty(&decommit_mask); |
| 868 | |
| 869 | // Allocate the segment from the OS |
| 870 | mi_segment_t* segment = mi_segment_os_alloc(required, page_alignment, eager_delay, req_arena_id, |
| 871 | &segment_slices, &pre_size, &info_slices, &commit_mask, &decommit_mask, |
| 872 | &is_zero, &commit, tld, os_tld); |
| 873 | if (segment == NULL) return NULL; |
| 874 | |
| 875 | // zero the segment info? -- not always needed as it may be zero initialized from the OS |
| 876 | mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); // tsan |
| 877 | if (!is_zero) { |
| 878 | ptrdiff_t ofs = offsetof(mi_segment_t, next); |
| 879 | size_t prefix = offsetof(mi_segment_t, slices) - ofs; |
| 880 | memset((uint8_t*)segment+ofs, 0, prefix + sizeof(mi_slice_t)*(segment_slices+1)); // one more |
| 881 | } |
| 882 | |
| 883 | segment->commit_mask = commit_mask; // on lazy commit, the initial part is always committed |
| 884 | segment->allow_decommit = (mi_option_is_enabled(mi_option_allow_decommit) && !segment->mem_is_pinned && !segment->mem_is_large); |
| 885 | if (segment->allow_decommit) { |
| 886 | segment->decommit_expire = 0; // don't decommit just committed memory // _mi_clock_now() + mi_option_get(mi_option_decommit_delay); |
| 887 | segment->decommit_mask = decommit_mask; |
| 888 | mi_assert_internal(mi_commit_mask_all_set(&segment->commit_mask, &segment->decommit_mask)); |
| 889 | #if MI_DEBUG>2 |
| 890 | const size_t commit_needed = _mi_divide_up(info_slices*MI_SEGMENT_SLICE_SIZE, MI_COMMIT_SIZE); |
| 891 | mi_commit_mask_t commit_needed_mask; |
| 892 | mi_commit_mask_create(0, commit_needed, &commit_needed_mask); |
| 893 | mi_assert_internal(!mi_commit_mask_any_set(&segment->decommit_mask, &commit_needed_mask)); |
| 894 | #endif |
| 895 | } |
| 896 | |
| 897 | // initialize segment info |
| 898 | const size_t slice_entries = (segment_slices > MI_SLICES_PER_SEGMENT ? MI_SLICES_PER_SEGMENT : segment_slices); |
| 899 | segment->segment_slices = segment_slices; |
| 900 | segment->segment_info_slices = info_slices; |
| 901 | segment->thread_id = _mi_thread_id(); |
| 902 | segment->cookie = _mi_ptr_cookie(segment); |
| 903 | segment->slice_entries = slice_entries; |
| 904 | segment->kind = (required == 0 ? MI_SEGMENT_NORMAL : MI_SEGMENT_HUGE); |
no test coverage detected