mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-07-06 19:38:41 +03:00
combine flags and xthread_id
This commit is contained in:
parent
281a513642
commit
b6adbbca0c
7 changed files with 58 additions and 45 deletions
|
@ -272,7 +272,7 @@ void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero)
|
|||
// if p == NULL then behave as malloc.
|
||||
// else if size == 0 then reallocate to a zero-sized block (and don't return NULL, just as mi_malloc(0)).
|
||||
// (this means that returning NULL always indicates an error, and `p` will not have been freed in that case.)
|
||||
const size_t size = _mi_usable_size(p,"mi_realloc"); // also works if p == NULL (with size 0)
|
||||
const size_t size = (p==NULL ? 0 : _mi_usable_size(p,"mi_realloc"));
|
||||
if mi_unlikely(newsize <= size && newsize >= (size / 2) && newsize > 0) { // note: newsize must be > 0 or otherwise we return NULL for realloc(NULL,0)
|
||||
mi_assert_internal(p!=NULL);
|
||||
// todo: do not track as the usable size is still the same in the free; adjust potential padding?
|
||||
|
|
31
src/free.c
31
src/free.c
|
@ -122,6 +122,7 @@ static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, void* p) mi_
|
|||
|
||||
// free a pointer owned by another thread (page parameter comes first for better codegen)
|
||||
static void mi_decl_noinline mi_free_generic_mt(mi_page_t* page, void* p) mi_attr_noexcept {
|
||||
if (p==NULL) return; // a NULL pointer is seen as abandoned (tid==0) with a full flag set
|
||||
mi_block_t* const block = _mi_page_ptr_unalign(page, p); // don't check `has_aligned` flag to avoid a race (issue #865)
|
||||
mi_block_check_unguard(page, block, p);
|
||||
mi_free_block_mt(page, block);
|
||||
|
@ -160,24 +161,24 @@ static inline mi_page_t* mi_checked_ptr_page(const void* p, const char* msg)
|
|||
void mi_free(void* p) mi_attr_noexcept
|
||||
{
|
||||
mi_page_t* const page = mi_checked_ptr_page(p,"mi_free");
|
||||
if mi_unlikely(page==NULL) return;
|
||||
|
||||
const bool is_local = (_mi_prim_thread_id() == mi_page_thread_id(page));
|
||||
const mi_page_flags_t flags = mi_page_flags(page);
|
||||
if mi_likely(is_local) { // thread-local free?
|
||||
if mi_likely(flags == 0) { // and it is not a full page (full pages need to move from the full bin), nor has aligned blocks (aligned blocks need to be unaligned)
|
||||
// thread-local, aligned, and not a full page
|
||||
mi_block_t* const block = (mi_block_t*)p;
|
||||
mi_free_block_local(page, block, true /* track stats */, false /* no need to check if the page is full */);
|
||||
}
|
||||
else {
|
||||
// page is full or contains (inner) aligned blocks; use generic path
|
||||
mi_free_generic_local(page, p);
|
||||
}
|
||||
#if MI_PAGE_MAP_FLAT // if not flat, NULL will point to `_mi_page_empty` and get to `mi_free_generic_mt`
|
||||
if mi_unlikely(page==NULL) return;
|
||||
#endif
|
||||
|
||||
const mi_threadid_t xtid = (_mi_prim_thread_id() ^ mi_page_xthread_id(page));
|
||||
if mi_likely(xtid == 0) { // thread-local free? `tid==mi_page_thread_id(page) && mi_page_flags(page)==0`
|
||||
// thread-local, aligned, and not a full page
|
||||
mi_block_t* const block = (mi_block_t*)p;
|
||||
mi_free_block_local(page, block, true /* track stats */, false /* no need to check if the page is full */);
|
||||
}
|
||||
else if (xtid <= MI_PAGE_FLAG_MASK) { // `tid= = mi_page_thread_id(page) && mi_page_flags(page)!=0`
|
||||
// page is local, but is full or contains (inner) aligned blocks; use generic path
|
||||
mi_free_generic_local(page, p);
|
||||
}
|
||||
else {
|
||||
// free-ing in a page owned by a heap in another thread, or on abandoned page (not belonging to a heap)
|
||||
if mi_likely(flags == 0) {
|
||||
// free-ing in a page owned by a heap in another thread, or on abandoned page (not belonging to a heap)
|
||||
if ((xtid & MI_PAGE_FLAG_MASK) == 0) { // `tid!=mi_page_thread_id(page) && mi_page_flags(page)==0`
|
||||
// blocks are aligned (and not a full page)
|
||||
mi_block_t* const block = (mi_block_t*)p;
|
||||
mi_free_block_mt(page,block);
|
||||
|
|
|
@ -16,7 +16,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||
|
||||
// Empty page used to initialize the small free pages array
|
||||
const mi_page_t _mi_page_empty = {
|
||||
MI_ATOMIC_VAR_INIT(0), // xthread_id
|
||||
MI_ATOMIC_VAR_INIT(MI_PAGE_IN_FULL_QUEUE), // xthread_id (must set flag to catch NULL on a free)
|
||||
NULL, // free
|
||||
0, // used
|
||||
0, // capacity
|
||||
|
@ -25,7 +25,6 @@ const mi_page_t _mi_page_empty = {
|
|||
0, // retire_expire
|
||||
NULL, // local_free
|
||||
MI_ATOMIC_VAR_INIT(0), // xthread_free
|
||||
MI_ATOMIC_VAR_INIT(0), // xflags
|
||||
0, // block_size
|
||||
NULL, // page_start
|
||||
0, // heap tag
|
||||
|
|
|
@ -210,11 +210,9 @@ bool _mi_page_map_init(void) {
|
|||
if (!mi_page_map_memid.initially_committed) {
|
||||
_mi_os_commit(_mi_page_map[0], os_page_size, NULL); // only first OS page
|
||||
}
|
||||
if (!mi_page_map_memid.initially_zero) {
|
||||
_mi_page_map[0][0] = NULL;
|
||||
}
|
||||
|
||||
mi_assert_internal(_mi_ptr_page(NULL)==NULL);
|
||||
_mi_page_map[0][0] = (mi_page_t*)&_mi_page_empty; // caught in `mi_free`
|
||||
|
||||
mi_assert_internal(_mi_ptr_page(NULL)==&_mi_page_empty);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue