#pragma once
#ifndef MIMALLOC_PRIM_H
#define MIMALLOC_PRIM_H
#include "internal.h"
typedef struct mi_os_mem_config_s {
size_t page_size; size_t large_page_size; size_t alloc_granularity; size_t physical_memory_in_kib; size_t virtual_address_bits; bool has_overcommit; bool has_partial_free; bool has_virtual_reserve; bool has_transparent_huge_pages; } mi_os_mem_config_t;
void _mi_prim_mem_init( mi_os_mem_config_t* config );
int _mi_prim_free(void* addr, size_t size );
int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr);
int _mi_prim_commit(void* addr, size_t size, bool* is_zero);
int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit);
int _mi_prim_reset(void* addr, size_t size);
int _mi_prim_reuse(void* addr, size_t size);
int _mi_prim_protect(void* addr, size_t size, bool protect);
int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bool* is_zero, void** addr);
size_t _mi_prim_numa_node(void);
size_t _mi_prim_numa_node_count(void);
mi_msecs_t _mi_prim_clock_now(void);
typedef struct mi_process_info_s {
mi_msecs_t elapsed;
mi_msecs_t utime;
mi_msecs_t stime;
size_t current_rss;
size_t peak_rss;
size_t current_commit;
size_t peak_commit;
size_t page_faults;
} mi_process_info_t;
void _mi_prim_process_info(mi_process_info_t* pinfo);
void _mi_prim_out_stderr( const char* msg );
bool _mi_prim_getenv(const char* name, char* result, size_t result_size);
bool _mi_prim_random_buf(void* buf, size_t buf_len);
void _mi_prim_thread_init_auto_done(void);
void _mi_prim_thread_done_auto_done(void);
void _mi_prim_thread_associate_default_theap(mi_theap_t* theap);
bool _mi_prim_thread_is_in_threadpool(void);
#if (defined(_WIN32)) || \
(defined(__GNUC__) && ( \
(defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \
|| (defined(__APPLE__) && (defined(__x86_64__) || defined(__aarch64__) || defined(__POWERPC__))) \
|| (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \
|| (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \
|| (defined(__OpenBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \
))
static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept {
void* res;
const size_t ofs = (slot*sizeof(void*));
#if defined(_WIN32)
#if (_M_X64 || _M_AMD64) && !defined(_M_ARM64EC)
res = (void*)__readgsqword((unsigned long)ofs); #elif _M_IX86 && !defined(_M_ARM64EC)
res = (void*)__readfsdword((unsigned long)ofs); #else
res = ((void**)NtCurrentTeb())[slot]; MI_UNUSED(ofs);
#endif
#elif defined(__i386__)
__asm__("movl %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); #elif defined(__APPLE__) && defined(__x86_64__)
__asm__("movq %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4)
__asm__("movl %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); #elif defined(__x86_64__)
__asm__("movq %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); #elif defined(__arm__)
void** tcb; MI_UNUSED(ofs);
__asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb));
res = tcb[slot];
#elif defined(__aarch64__)
void** tcb; MI_UNUSED(ofs);
#if defined(__APPLE__)
__asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb));
#else
__asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb));
#endif
res = tcb[slot];
#elif defined(__APPLE__) && defined(__POWERPC__)
MI_UNUSED(ofs);
res = pthread_getspecific(slot);
#else
#define MI_HAS_TLS_SLOT 0
MI_UNUSED(ofs);
res = NULL;
#endif
return res;
}
#ifndef MI_HAS_TLS_SLOT
#define MI_HAS_TLS_SLOT 1
#endif
static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexcept {
const size_t ofs = (slot*sizeof(void*));
#if defined(_WIN32)
((void**)NtCurrentTeb())[slot] = value; MI_UNUSED(ofs);
#elif defined(__i386__)
__asm__("movl %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); #elif defined(__APPLE__) && defined(__x86_64__)
__asm__("movq %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4)
__asm__("movl %1,%%fs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); #elif defined(__x86_64__)
__asm__("movq %1,%%fs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); #elif defined(__arm__)
void** tcb; MI_UNUSED(ofs);
__asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb));
tcb[slot] = value;
#elif defined(__aarch64__)
void** tcb; MI_UNUSED(ofs);
#if defined(__APPLE__)
__asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb));
#else
__asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb));
#endif
tcb[slot] = value;
#elif defined(__APPLE__) && defined(__POWERPC__)
MI_UNUSED(ofs);
pthread_setspecific(slot, value);
#else
MI_UNUSED(ofs); MI_UNUSED(value);
#endif
}
#endif
extern mi_decl_hidden mi_decl_thread mi_theap_t* __mi_theap_main; extern mi_decl_hidden bool _mi_process_is_initialized;
#if !defined(__APPLE__) \
&& !defined(__CYGWIN__) \
&& !defined(MI_LIBC_MUSL) \
&& (!defined(__clang_major__) || __clang_major__ >= 14)
#if (defined(__GNUC__) && (__GNUC__ >= 7) && defined(__aarch64__)) \
|| (defined(__GNUC__) && (__GNUC__ >= 11) && defined(__x86_64__)) \
|| (defined(__clang_major__) && (__clang_major__ >= 14) && (defined(__aarch64__) || defined(__x86_64__)))
#define MI_USE_BUILTIN_THREAD_POINTER 1
#endif
#endif
static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept;
static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept {
const mi_threadid_t tid = __mi_prim_thread_id();
mi_assert_internal(tid > 1);
mi_assert_internal((tid & MI_PAGE_FLAG_MASK) == 0); return tid;
}
#if defined(MI_PRIM_THREAD_ID)
static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept {
return MI_PRIM_THREAD_ID(); }
#elif defined(_WIN32)
static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept {
return (uintptr_t)NtCurrentTeb();
}
#elif MI_USE_BUILTIN_THREAD_POINTER
static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept {
return (uintptr_t)__builtin_thread_pointer();
}
#elif MI_HAS_TLS_SLOT
static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept {
#if defined(__BIONIC__)
return (uintptr_t)mi_prim_tls_slot(1);
#else
return (uintptr_t)mi_prim_tls_slot(0);
#endif
}
#else
static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept {
return (uintptr_t)&__mi_theap_main;
}
#endif
static inline mi_theap_t* _mi_theap_default(void);
static inline mi_theap_t* _mi_theap_cached(void);
#if defined(_WIN32)
#define MI_TLS_MODEL_DYNAMIC_WIN32 1
#elif defined(__APPLE__)
#define MI_TLS_MODEL_FIXED_SLOT 1
#define MI_TLS_MODEL_FIXED_SLOT_DEFAULT 108
#define MI_TLS_MODEL_FIXED_SLOT_CACHED 109
#elif defined(__OpenBSD__) || defined(__ANDROID__)
#define MI_TLS_MODEL_DYNAMIC_PTHREADS 1
#else
#define MI_TLS_MODEL_THREAD_LOCAL 1
#endif
mi_decl_cold mi_decl_noinline mi_theap_t* _mi_theap_empty_get(void);
static inline mi_theap_t* __mi_theap_empty(void) {
#if __GNUC__
__asm(""); return (mi_theap_t*)&_mi_theap_empty;
#else
return _mi_theap_empty_get();
#endif
}
#if MI_TLS_MODEL_THREAD_LOCAL
extern mi_decl_hidden mi_decl_thread mi_theap_t* __mi_theap_default; extern mi_decl_hidden mi_decl_thread mi_theap_t* __mi_theap_cached;
static inline mi_theap_t* _mi_theap_default(void) {
#if defined(MI_TLS_RECURSE_GUARD)
if (mi_unlikely(!_mi_process_is_initialized)) return _mi_theap_empty_get();
#endif
return __mi_theap_default;
}
static inline mi_theap_t* _mi_theap_cached(void) {
return __mi_theap_cached;
}
#elif MI_TLS_MODEL_FIXED_SLOT
#define MI_THEAP_INITASNULL 1
static inline mi_theap_t* _mi_theap_default(void) {
return (mi_theap_t*)mi_prim_tls_slot(MI_TLS_MODEL_FIXED_SLOT_DEFAULT);
}
static inline mi_theap_t* _mi_theap_cached(void) {
return (mi_theap_t*)mi_prim_tls_slot(MI_TLS_MODEL_FIXED_SLOT_CACHED);
}
#elif MI_TLS_MODEL_DYNAMIC_WIN32
#define MI_THEAP_INITASNULL 1
#if MI_SIZE_SIZE==4
#define MI_TLS_EXPANSION_SLOT (0x0F94 / MI_SIZE_SIZE)
#else
#define MI_TLS_EXPANSION_SLOT (0x1780 / MI_SIZE_SIZE)
#endif
extern mi_decl_hidden size_t _mi_theap_default_slot;
extern mi_decl_hidden size_t _mi_theap_cached_slot;
extern mi_decl_hidden size_t _mi_theap_default_expansion_slot;
extern mi_decl_hidden size_t _mi_theap_cached_expansion_slot;
static inline mi_theap_t* _mi_theap_default(void) {
const size_t slot = _mi_theap_default_slot;
mi_theap_t* theap = (mi_theap_t*)mi_prim_tls_slot(slot);
#if !MI_WIN_DIRECT_TLS
if mi_unlikely(slot==MI_TLS_EXPANSION_SLOT) { if mi_likely(theap!=NULL) { theap = ((mi_theap_t**)theap)[_mi_theap_default_expansion_slot];
}
}
#endif
return theap;
}
static inline mi_theap_t* _mi_theap_cached(void) {
const size_t slot = _mi_theap_cached_slot;
mi_theap_t* theap = (mi_theap_t*)mi_prim_tls_slot(slot);
#if !MI_WIN_DIRECT_TLS
if mi_unlikely(slot==MI_TLS_EXPANSION_SLOT) { if mi_likely(theap!=NULL) { theap = ((mi_theap_t**)theap)[_mi_theap_cached_expansion_slot];
}
}
#endif
return theap;
}
#elif MI_TLS_MODEL_DYNAMIC_PTHREADS
#define MI_THEAP_INITASNULL 1
extern mi_decl_hidden pthread_key_t _mi_theap_default_key;
extern mi_decl_hidden pthread_key_t _mi_theap_cached_key;
static inline mi_theap_t* _mi_theap_default(void) {
#if !MI_TLS_MODEL_DYNAMIC_PTHREADS_DEFAULT_ENTRY_IS_NULL
if mi_unlikely(_mi_theap_default_key==0) { return NULL; }
#endif
return (mi_theap_t*)pthread_getspecific(_mi_theap_default_key);
}
static inline mi_theap_t* _mi_theap_cached(void) {
#if !MI_TLS_MODEL_DYNAMIC_PTHREADS_DEFAULT_ENTRY_IS_NULL
if mi_unlikely(_mi_theap_cached_key==0) { return NULL; }
#endif
return (mi_theap_t*)pthread_getspecific(_mi_theap_cached_key);
}
#else
#error "no TLS model is defined for this platform?"
#endif
static inline bool _mi_thread_is_initialized(void) {
return (mi_theap_is_initialized(_mi_theap_default()));
}
static inline mi_theap_t* _mi_heap_theap(const mi_heap_t* heap) {
mi_theap_t* theap = _mi_theap_cached();
#if MI_THEAP_INITASNULL
if mi_likely(theap!=NULL && _mi_theap_heap(theap)==heap) return theap;
#else
if mi_likely(_mi_theap_heap(theap)==heap) return theap;
#endif
return _mi_heap_theap_get_or_init(heap);
}
static inline mi_theap_t* _mi_heap_theap_peek(const mi_heap_t* heap) {
mi_theap_t* theap = _mi_theap_cached();
#if MI_THEAP_INITASNULL
if mi_unlikely(theap==NULL || _mi_theap_heap(theap)!=heap)
#else
if mi_unlikely(_mi_theap_heap(theap)!=heap)
#endif
{
theap = _mi_heap_theap_get_peek(heap); }
mi_assert(theap==NULL || _mi_theap_heap(theap)==heap);
return theap;
}
static inline mi_theap_t* _mi_page_associated_theap_peek(mi_page_t* page) {
mi_heap_t* const heap = page->heap;
mi_theap_t* theap;
if mi_likely(heap==NULL) { theap = __mi_theap_main; } else { theap = _mi_heap_theap_peek(heap); }
mi_assert_internal(theap==NULL || _mi_thread_id()==theap->tld->thread_id);
return theap;
}
#endif