merge from dev (bitmap split)
This commit is contained in:
commit
a948724340
@ -29,6 +29,7 @@ set(mi_sources
|
|||||||
src/stats.c
|
src/stats.c
|
||||||
src/random.c
|
src/random.c
|
||||||
src/os.c
|
src/os.c
|
||||||
|
src/bitmap.c
|
||||||
src/arena.c
|
src/arena.c
|
||||||
src/segment.c
|
src/segment.c
|
||||||
src/page.c
|
src/page.c
|
||||||
|
@ -215,6 +215,7 @@
|
|||||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
||||||
<ClInclude Include="..\..\include\mimalloc-override.h" />
|
<ClInclude Include="..\..\include\mimalloc-override.h" />
|
||||||
<ClInclude Include="..\..\include\mimalloc-types.h" />
|
<ClInclude Include="..\..\include\mimalloc-types.h" />
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\alloc-aligned.c">
|
<ClCompile Include="..\..\src\alloc-aligned.c">
|
||||||
@ -232,6 +233,7 @@
|
|||||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||||
<ClCompile Include="..\..\src\alloc.c" />
|
<ClCompile Include="..\..\src\alloc.c" />
|
||||||
<ClCompile Include="..\..\src\arena.c" />
|
<ClCompile Include="..\..\src\arena.c" />
|
||||||
|
<ClCompile Include="..\..\src\bitmap.c" />
|
||||||
<ClCompile Include="..\..\src\heap.c" />
|
<ClCompile Include="..\..\src\heap.c" />
|
||||||
<ClCompile Include="..\..\src\init.c" />
|
<ClCompile Include="..\..\src\init.c" />
|
||||||
<ClCompile Include="..\..\src\options.c" />
|
<ClCompile Include="..\..\src\options.c" />
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h">
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\alloc.c">
|
<ClCompile Include="..\..\src\alloc.c">
|
||||||
@ -73,5 +76,8 @@
|
|||||||
<ClCompile Include="..\..\src\random.c">
|
<ClCompile Include="..\..\src\random.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\bitmap.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -230,6 +230,7 @@
|
|||||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||||
<ClCompile Include="..\..\src\alloc.c" />
|
<ClCompile Include="..\..\src\alloc.c" />
|
||||||
<ClCompile Include="..\..\src\arena.c" />
|
<ClCompile Include="..\..\src\arena.c" />
|
||||||
|
<ClCompile Include="..\..\src\bitmap.c" />
|
||||||
<ClCompile Include="..\..\src\heap.c" />
|
<ClCompile Include="..\..\src\heap.c" />
|
||||||
<ClCompile Include="..\..\src\init.c" />
|
<ClCompile Include="..\..\src\init.c" />
|
||||||
<ClCompile Include="..\..\src\options.c" />
|
<ClCompile Include="..\..\src\options.c" />
|
||||||
@ -252,6 +253,7 @@
|
|||||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-override.h" />
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-override.h" />
|
||||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-types.h" />
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-types.h" />
|
||||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
@ -59,6 +59,9 @@
|
|||||||
<ClCompile Include="..\..\src\random.c">
|
<ClCompile Include="..\..\src\random.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\bitmap.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
||||||
@ -79,5 +82,8 @@
|
|||||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h">
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -215,6 +215,7 @@
|
|||||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
||||||
<ClInclude Include="..\..\include\mimalloc-override.h" />
|
<ClInclude Include="..\..\include\mimalloc-override.h" />
|
||||||
<ClInclude Include="..\..\include\mimalloc-types.h" />
|
<ClInclude Include="..\..\include\mimalloc-types.h" />
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\alloc-aligned.c">
|
<ClCompile Include="..\..\src\alloc-aligned.c">
|
||||||
@ -232,9 +233,7 @@
|
|||||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||||
<ClCompile Include="..\..\src\alloc.c" />
|
<ClCompile Include="..\..\src\alloc.c" />
|
||||||
<ClCompile Include="..\..\src\arena.c" />
|
<ClCompile Include="..\..\src\arena.c" />
|
||||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
<ClCompile Include="..\..\src\bitmap.c" />
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\heap.c" />
|
<ClCompile Include="..\..\src\heap.c" />
|
||||||
<ClCompile Include="..\..\src\init.c" />
|
<ClCompile Include="..\..\src\init.c" />
|
||||||
<ClCompile Include="..\..\src\options.c" />
|
<ClCompile Include="..\..\src\options.c" />
|
||||||
|
@ -37,15 +37,15 @@
|
|||||||
<ClCompile Include="..\..\src\arena.c">
|
<ClCompile Include="..\..\src\arena.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\random.c">
|
<ClCompile Include="..\..\src\random.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\options.c">
|
<ClCompile Include="..\..\src\options.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\bitmap.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
||||||
@ -66,6 +66,9 @@
|
|||||||
<ClInclude Include="..\..\include\mimalloc-types.h">
|
<ClInclude Include="..\..\include\mimalloc-types.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Header Files">
|
<Filter Include="Header Files">
|
||||||
|
@ -220,8 +220,8 @@
|
|||||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||||
<ClCompile Include="..\..\src\alloc.c" />
|
<ClCompile Include="..\..\src\alloc.c" />
|
||||||
<ClCompile Include="..\..\src\arena.c" />
|
<ClCompile Include="..\..\src\arena.c" />
|
||||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
<ClCompile Include="..\..\src\bitmap.c">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\heap.c" />
|
<ClCompile Include="..\..\src\heap.c" />
|
||||||
<ClCompile Include="..\..\src\init.c" />
|
<ClCompile Include="..\..\src\init.c" />
|
||||||
@ -245,6 +245,7 @@
|
|||||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-override.h" />
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-override.h" />
|
||||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-types.h" />
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-types.h" />
|
||||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
@ -43,10 +43,10 @@
|
|||||||
<ClCompile Include="..\..\src\arena.c">
|
<ClCompile Include="..\..\src\arena.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
<ClCompile Include="..\..\src\random.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\random.c">
|
<ClCompile Include="..\..\src\bitmap.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -69,6 +69,9 @@
|
|||||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-types.h">
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-types.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\bitmap.h">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Header Files">
|
<Filter Include="Header Files">
|
||||||
|
@ -109,7 +109,6 @@ void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page); // callback fro
|
|||||||
|
|
||||||
size_t _mi_bin_size(uint8_t bin); // for stats
|
size_t _mi_bin_size(uint8_t bin); // for stats
|
||||||
uint8_t _mi_bin(size_t size); // for stats
|
uint8_t _mi_bin(size_t size); // for stats
|
||||||
uint8_t _mi_bsr(uintptr_t x); // bit-scan-right, used on BSD in "os.c"
|
|
||||||
|
|
||||||
// "heap.c"
|
// "heap.c"
|
||||||
void _mi_heap_destroy_pages(mi_heap_t* heap);
|
void _mi_heap_destroy_pages(mi_heap_t* heap);
|
||||||
@ -859,5 +858,108 @@ static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// Count bits: trailing or leading zeros (with MI_INTPTR_BITS on all zero)
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
|
||||||
|
#include <limits.h> // LONG_MAX
|
||||||
|
#define MI_HAVE_FAST_BITSCAN
|
||||||
|
static inline size_t mi_clz(uintptr_t x) {
|
||||||
|
if (x==0) return MI_INTPTR_BITS;
|
||||||
|
#if (INTPTR_MAX == LONG_MAX)
|
||||||
|
return __builtin_clzl(x);
|
||||||
|
#else
|
||||||
|
return __builtin_clzll(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static inline size_t mi_ctz(uintptr_t x) {
|
||||||
|
if (x==0) return MI_INTPTR_BITS;
|
||||||
|
#if (INTPTR_MAX == LONG_MAX)
|
||||||
|
return __builtin_ctzl(x);
|
||||||
|
#else
|
||||||
|
return __builtin_ctzll(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
|
#include <limits.h> // LONG_MAX
|
||||||
|
#define MI_HAVE_FAST_BITSCAN
|
||||||
|
static inline size_t mi_clz(uintptr_t x) {
|
||||||
|
if (x==0) return MI_INTPTR_BITS;
|
||||||
|
unsigned long idx;
|
||||||
|
#if (INTPTR_MAX == LONG_MAX)
|
||||||
|
_BitScanReverse(&idx, x);
|
||||||
|
#else
|
||||||
|
_BitScanReverse64(&idx, x);
|
||||||
|
#endif
|
||||||
|
return ((MI_INTPTR_BITS - 1) - idx);
|
||||||
|
}
|
||||||
|
static inline size_t mi_ctz(uintptr_t x) {
|
||||||
|
if (x==0) return MI_INTPTR_BITS;
|
||||||
|
unsigned long idx;
|
||||||
|
#if (INTPTR_MAX == LONG_MAX)
|
||||||
|
_BitScanForward(&idx, x);
|
||||||
|
#else
|
||||||
|
_BitScanForward64(&idx, x);
|
||||||
|
#endif
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static inline size_t mi_ctz32(uint32_t x) {
|
||||||
|
// de Bruijn multiplication, see <http://supertech.csail.mit.edu/papers/debruijn.pdf>
|
||||||
|
static const unsigned char debruijn[32] = {
|
||||||
|
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
|
||||||
|
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
|
||||||
|
};
|
||||||
|
if (x==0) return 32;
|
||||||
|
return debruijn[((x & -(int32_t)x) * 0x077CB531UL) >> 27];
|
||||||
|
}
|
||||||
|
static inline size_t mi_clz32(uint32_t x) {
|
||||||
|
// de Bruijn multiplication, see <http://supertech.csail.mit.edu/papers/debruijn.pdf>
|
||||||
|
static const uint8_t debruijn[32] = {
|
||||||
|
31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
|
||||||
|
23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
|
||||||
|
};
|
||||||
|
if (x==0) return 32;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
return debruijn[(uint32_t)(x * 0x07C4ACDDUL) >> 27];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t mi_clz(uintptr_t x) {
|
||||||
|
if (x==0) return MI_INTPTR_BITS;
|
||||||
|
#if (MI_INTPTR_BITS <= 32)
|
||||||
|
return mi_clz32((uint32_t)x);
|
||||||
|
#else
|
||||||
|
size_t count = mi_clz32((uint32_t)(x >> 32));
|
||||||
|
if (count < 32) return count;
|
||||||
|
return (32 + mi_clz32((uint32_t)x));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static inline size_t mi_ctz(uintptr_t x) {
|
||||||
|
if (x==0) return MI_INTPTR_BITS;
|
||||||
|
#if (MI_INTPTR_BITS <= 32)
|
||||||
|
return mi_ctz32((uint32_t)x);
|
||||||
|
#else
|
||||||
|
size_t count = mi_ctz32((uint32_t)x);
|
||||||
|
if (count < 32) return count;
|
||||||
|
return (32 + mi_ctz32((uint32_t)(x>>32)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// "bit scan reverse": Return index of the highest bit (or MI_INTPTR_BITS if `x` is zero)
|
||||||
|
static inline size_t mi_bsr(uintptr_t x) {
|
||||||
|
return (x==0 ? MI_INTPTR_BITS : MI_INTPTR_BITS - 1 - mi_clz(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
36
src/arena.c
36
src/arena.c
@ -28,7 +28,7 @@ The arena allocation needs to be thread safe and we use an atomic bitmap to allo
|
|||||||
#include <string.h> // memset
|
#include <string.h> // memset
|
||||||
#include <errno.h> // ENOMEM
|
#include <errno.h> // ENOMEM
|
||||||
|
|
||||||
#include "bitmap.inc.c" // atomic bitmap
|
#include "bitmap.h" // atomic bitmap
|
||||||
|
|
||||||
|
|
||||||
// os.c
|
// os.c
|
||||||
@ -105,7 +105,7 @@ static size_t mi_block_count_of_size(size_t size) {
|
|||||||
static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx)
|
static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx)
|
||||||
{
|
{
|
||||||
size_t idx = mi_atomic_load_acquire(&arena->search_idx); // start from last search
|
size_t idx = mi_atomic_load_acquire(&arena->search_idx); // start from last search
|
||||||
if (mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) {
|
if (_mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) {
|
||||||
mi_atomic_store_release(&arena->search_idx, idx); // start search from here next time
|
mi_atomic_store_release(&arena->search_idx, idx); // start search from here next time
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -154,11 +154,11 @@ static void* mi_cache_pop(int numa_node, size_t size, size_t alignment, bool com
|
|||||||
mi_bitmap_index_t bitidx = 0;
|
mi_bitmap_index_t bitidx = 0;
|
||||||
bool claimed = false;
|
bool claimed = false;
|
||||||
if (*large) { // large allowed?
|
if (*large) { // large allowed?
|
||||||
claimed = mi_bitmap_try_find_from_claim(cache_available_large, MI_CACHE_FIELDS, start_field, 1, &bitidx);
|
claimed = _mi_bitmap_try_find_from_claim(cache_available_large, MI_CACHE_FIELDS, start_field, 1, &bitidx);
|
||||||
if (claimed) *large = true;
|
if (claimed) *large = true;
|
||||||
}
|
}
|
||||||
if (!claimed) {
|
if (!claimed) {
|
||||||
claimed = mi_bitmap_try_find_from_claim(cache_available, MI_CACHE_FIELDS, start_field, 1, &bitidx);
|
claimed = _mi_bitmap_try_find_from_claim(cache_available, MI_CACHE_FIELDS, start_field, 1, &bitidx);
|
||||||
if (claimed) *large = false;
|
if (claimed) *large = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,8 +189,8 @@ static void* mi_cache_pop(int numa_node, size_t size, size_t alignment, bool com
|
|||||||
*commit_mask = cmask;
|
*commit_mask = cmask;
|
||||||
|
|
||||||
// mark the slot as free again
|
// mark the slot as free again
|
||||||
mi_assert_internal(mi_bitmap_is_claimed(cache_inuse, MI_CACHE_FIELDS, 1, bitidx));
|
mi_assert_internal(_mi_bitmap_is_claimed(cache_inuse, MI_CACHE_FIELDS, 1, bitidx));
|
||||||
mi_bitmap_unclaim(cache_inuse, MI_CACHE_FIELDS, 1, bitidx);
|
_mi_bitmap_unclaim(cache_inuse, MI_CACHE_FIELDS, 1, bitidx);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,19 +231,19 @@ static void mi_cache_purge(mi_os_tld_t* tld) {
|
|||||||
// seems expired, first claim it from available
|
// seems expired, first claim it from available
|
||||||
purged++;
|
purged++;
|
||||||
mi_bitmap_index_t bitidx = mi_bitmap_index_create_from_bit(idx);
|
mi_bitmap_index_t bitidx = mi_bitmap_index_create_from_bit(idx);
|
||||||
if (mi_bitmap_claim(cache_available, MI_CACHE_FIELDS, 1, bitidx, NULL)) {
|
if (_mi_bitmap_claim(cache_available, MI_CACHE_FIELDS, 1, bitidx, NULL)) {
|
||||||
// was available, we claimed it
|
// was available, we claimed it
|
||||||
expire = mi_atomic_loadi64_acquire(&slot->expire);
|
expire = mi_atomic_loadi64_acquire(&slot->expire);
|
||||||
if (expire != 0 && now >= expire) { // safe read
|
if (expire != 0 && now >= expire) { // safe read
|
||||||
// still expired, decommit it
|
// still expired, decommit it
|
||||||
mi_atomic_storei64_relaxed(&slot->expire,(mi_msecs_t)0);
|
mi_atomic_storei64_relaxed(&slot->expire,(mi_msecs_t)0);
|
||||||
mi_assert_internal(!mi_commit_mask_is_empty(slot->commit_mask) && mi_bitmap_is_claimed(cache_available_large, MI_CACHE_FIELDS, 1, bitidx));
|
mi_assert_internal(!mi_commit_mask_is_empty(slot->commit_mask) && _mi_bitmap_is_claimed(cache_available_large, MI_CACHE_FIELDS, 1, bitidx));
|
||||||
_mi_abandoned_await_readers(); // wait until safe to decommit
|
_mi_abandoned_await_readers(); // wait until safe to decommit
|
||||||
// decommit committed parts
|
// decommit committed parts
|
||||||
mi_commit_mask_decommit(&slot->commit_mask, slot->p, MI_SEGMENT_SIZE, tld->stats);
|
mi_commit_mask_decommit(&slot->commit_mask, slot->p, MI_SEGMENT_SIZE, tld->stats);
|
||||||
//_mi_os_decommit(slot->p, MI_SEGMENT_SIZE, tld->stats);
|
//_mi_os_decommit(slot->p, MI_SEGMENT_SIZE, tld->stats);
|
||||||
}
|
}
|
||||||
mi_bitmap_unclaim(cache_available, MI_CACHE_FIELDS, 1, bitidx); // make it available again for a pop
|
_mi_bitmap_unclaim(cache_available, MI_CACHE_FIELDS, 1, bitidx); // make it available again for a pop
|
||||||
}
|
}
|
||||||
if (purged > 4) break; // bound to no more than 4 purge tries per push
|
if (purged > 4) break; // bound to no more than 4 purge tries per push
|
||||||
}
|
}
|
||||||
@ -268,11 +268,11 @@ static bool mi_cache_push(void* start, size_t size, size_t memid, mi_commit_mask
|
|||||||
|
|
||||||
// find an available slot
|
// find an available slot
|
||||||
mi_bitmap_index_t bitidx;
|
mi_bitmap_index_t bitidx;
|
||||||
bool claimed = mi_bitmap_try_find_from_claim(cache_inuse, MI_CACHE_FIELDS, start_field, 1, &bitidx);
|
bool claimed = _mi_bitmap_try_find_from_claim(cache_inuse, MI_CACHE_FIELDS, start_field, 1, &bitidx);
|
||||||
if (!claimed) return false;
|
if (!claimed) return false;
|
||||||
|
|
||||||
mi_assert_internal(mi_bitmap_is_claimed(cache_available, MI_CACHE_FIELDS, 1, bitidx));
|
mi_assert_internal(_mi_bitmap_is_claimed(cache_available, MI_CACHE_FIELDS, 1, bitidx));
|
||||||
mi_assert_internal(mi_bitmap_is_claimed(cache_available_large, MI_CACHE_FIELDS, 1, bitidx));
|
mi_assert_internal(_mi_bitmap_is_claimed(cache_available_large, MI_CACHE_FIELDS, 1, bitidx));
|
||||||
|
|
||||||
// set the slot
|
// set the slot
|
||||||
mi_cache_slot_t* slot = &cache[mi_bitmap_index_bit(bitidx)];
|
mi_cache_slot_t* slot = &cache[mi_bitmap_index_bit(bitidx)];
|
||||||
@ -292,7 +292,7 @@ static bool mi_cache_push(void* start, size_t size, size_t memid, mi_commit_mask
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make it available
|
// make it available
|
||||||
mi_bitmap_unclaim((is_large ? cache_available_large : cache_available), MI_CACHE_FIELDS, 1, bitidx);
|
_mi_bitmap_unclaim((is_large ? cache_available_large : cache_available), MI_CACHE_FIELDS, 1, bitidx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +310,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n
|
|||||||
// claimed it! set the dirty bits (todo: no need for an atomic op here?)
|
// claimed it! set the dirty bits (todo: no need for an atomic op here?)
|
||||||
void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE);
|
void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE);
|
||||||
*memid = mi_arena_id_create(arena_index, bitmap_index);
|
*memid = mi_arena_id_create(arena_index, bitmap_index);
|
||||||
*is_zero = mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL);
|
*is_zero = _mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL);
|
||||||
*large = arena->is_large;
|
*large = arena->is_large;
|
||||||
if (arena->is_committed) {
|
if (arena->is_committed) {
|
||||||
// always committed
|
// always committed
|
||||||
@ -319,7 +319,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n
|
|||||||
else if (*commit) {
|
else if (*commit) {
|
||||||
// arena not committed as a whole, but commit requested: ensure commit now
|
// arena not committed as a whole, but commit requested: ensure commit now
|
||||||
bool any_uncommitted;
|
bool any_uncommitted;
|
||||||
mi_bitmap_claim_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted);
|
_mi_bitmap_claim_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted);
|
||||||
if (any_uncommitted) {
|
if (any_uncommitted) {
|
||||||
bool commit_zero;
|
bool commit_zero;
|
||||||
_mi_os_commit(p, needed_bcount * MI_ARENA_BLOCK_SIZE, &commit_zero, tld->stats);
|
_mi_os_commit(p, needed_bcount * MI_ARENA_BLOCK_SIZE, &commit_zero, tld->stats);
|
||||||
@ -328,7 +328,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// no need to commit, but check if already fully committed
|
// no need to commit, but check if already fully committed
|
||||||
*commit = mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index);
|
*commit = _mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -443,7 +443,7 @@ void _mi_arena_free(void* p, size_t size, size_t memid, mi_commit_mask_t commit_
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const size_t blocks = mi_block_count_of_size(size);
|
const size_t blocks = mi_block_count_of_size(size);
|
||||||
bool ones = mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx);
|
bool ones = _mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx);
|
||||||
if (!ones) {
|
if (!ones) {
|
||||||
_mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size);
|
_mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size);
|
||||||
return;
|
return;
|
||||||
@ -495,7 +495,7 @@ bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_la
|
|||||||
if (post > 0) {
|
if (post > 0) {
|
||||||
// don't use leftover bits at the end
|
// don't use leftover bits at the end
|
||||||
mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post);
|
mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post);
|
||||||
mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL);
|
_mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
mi_arena_add(arena);
|
mi_arena_add(arena);
|
||||||
|
@ -1,147 +1,46 @@
|
|||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
Copyright (c) 2019, Microsoft Research, Daan Leijen
|
Copyright (c) 2019,2020 Microsoft Research, Daan Leijen
|
||||||
This is free software; you can redistribute it and/or modify it under the
|
This is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the MIT license. A copy of the license can be found in the file
|
terms of the MIT license. A copy of the license can be found in the file
|
||||||
"LICENSE" at the root of this distribution.
|
"LICENSE" at the root of this distribution.
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
This file is meant to be included in other files for efficiency.
|
Concurrent bitmap that can set/reset sequences of bits atomically,
|
||||||
It implements a bitmap that can set/reset sequences of bits atomically
|
represeted as an array of fields where each field is a machine word (`uintptr_t`)
|
||||||
and is used to concurrently claim memory ranges.
|
|
||||||
|
|
||||||
A bitmap is an array of fields where each field is a machine word (`uintptr_t`)
|
There are two api's; the standard one cannot have sequences that cross
|
||||||
|
between the bitmap fields (and a sequence must be <= MI_BITMAP_FIELD_BITS).
|
||||||
|
(this is used in region allocation)
|
||||||
|
|
||||||
A current limitation is that the bit sequences cannot cross fields
|
The `_across` postfixed functions do allow sequences that can cross over
|
||||||
and that the sequence must be smaller or equal to the bits in a field.
|
between the fields. (This is used in arena allocation)
|
||||||
---------------------------------------------------------------------------- */
|
---------------------------------------------------------------------------- */
|
||||||
#pragma once
|
|
||||||
#ifndef MI_BITMAP_C
|
|
||||||
#define MI_BITMAP_C
|
|
||||||
|
|
||||||
#include "mimalloc.h"
|
#include "mimalloc.h"
|
||||||
#include "mimalloc-internal.h"
|
#include "mimalloc-internal.h"
|
||||||
|
#include "bitmap.h"
|
||||||
|
|
||||||
/* -----------------------------------------------------------
|
/* -----------------------------------------------------------
|
||||||
Bitmap definition
|
Bitmap definition
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
#define MI_BITMAP_FIELD_BITS (8*MI_INTPTR_SIZE)
|
|
||||||
#define MI_BITMAP_FIELD_FULL (~((uintptr_t)0)) // all bits set
|
|
||||||
|
|
||||||
// An atomic bitmap of `uintptr_t` fields
|
|
||||||
typedef _Atomic(uintptr_t) mi_bitmap_field_t;
|
|
||||||
typedef mi_bitmap_field_t* mi_bitmap_t;
|
|
||||||
|
|
||||||
// A bitmap index is the index of the bit in a bitmap.
|
|
||||||
typedef size_t mi_bitmap_index_t;
|
|
||||||
|
|
||||||
// Create a bit index.
|
|
||||||
static inline mi_bitmap_index_t mi_bitmap_index_create(size_t idx, size_t bitidx) {
|
|
||||||
mi_assert_internal(bitidx < MI_BITMAP_FIELD_BITS);
|
|
||||||
return (idx*MI_BITMAP_FIELD_BITS) + bitidx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a bit index.
|
|
||||||
static inline mi_bitmap_index_t mi_bitmap_index_create_from_bit(size_t full_bitidx) {
|
|
||||||
return mi_bitmap_index_create(full_bitidx / MI_BITMAP_FIELD_BITS, full_bitidx % MI_BITMAP_FIELD_BITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the field index from a bit index.
|
|
||||||
static inline size_t mi_bitmap_index_field(mi_bitmap_index_t bitmap_idx) {
|
|
||||||
return (bitmap_idx / MI_BITMAP_FIELD_BITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the bit index in a bitmap field
|
|
||||||
static inline size_t mi_bitmap_index_bit_in_field(mi_bitmap_index_t bitmap_idx) {
|
|
||||||
return (bitmap_idx % MI_BITMAP_FIELD_BITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the full bit index
|
|
||||||
static inline size_t mi_bitmap_index_bit(mi_bitmap_index_t bitmap_idx) {
|
|
||||||
return bitmap_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// The bit mask for a given number of blocks at a specified bit index.
|
// The bit mask for a given number of blocks at a specified bit index.
|
||||||
static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) {
|
static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) {
|
||||||
mi_assert_internal(count + bitidx <= MI_BITMAP_FIELD_BITS);
|
mi_assert_internal(count + bitidx <= MI_BITMAP_FIELD_BITS);
|
||||||
mi_assert_internal(count > 0);
|
mi_assert_internal(count > 0);
|
||||||
//if (count >= MI_BITMAP_FIELD_BITS) return MI_BITMAP_FIELD_FULL;
|
if (count >= MI_BITMAP_FIELD_BITS) return MI_BITMAP_FIELD_FULL;
|
||||||
//if (count == 0) return 0;
|
|
||||||
return ((((uintptr_t)1 << count) - 1) << bitidx);
|
return ((((uintptr_t)1 << count) - 1) << bitidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -----------------------------------------------------------
|
|
||||||
Use bit scan forward/reverse to quickly find the first zero bit if it is available
|
|
||||||
----------------------------------------------------------- */
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define MI_HAVE_BITSCAN
|
|
||||||
#include <intrin.h>
|
|
||||||
#ifndef MI_64
|
|
||||||
#if MI_INTPTR_SIZE==8
|
|
||||||
#define MI_64(f) f##64
|
|
||||||
#else
|
|
||||||
#define MI_64(f) f
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline size_t mi_bsf(uintptr_t x) {
|
|
||||||
if (x==0) return 8*MI_INTPTR_SIZE;
|
|
||||||
DWORD idx;
|
|
||||||
MI_64(_BitScanForward)(&idx, x);
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
static inline size_t mi_bsr(uintptr_t x) {
|
|
||||||
if (x==0) return 8*MI_INTPTR_SIZE;
|
|
||||||
DWORD idx;
|
|
||||||
MI_64(_BitScanReverse)(&idx, x);
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
#elif defined(__GNUC__) || defined(__clang__)
|
|
||||||
#include <limits.h> // LONG_MAX
|
|
||||||
#define MI_HAVE_BITSCAN
|
|
||||||
#if (INTPTR_MAX == LONG_MAX)
|
|
||||||
# define MI_L(x) x##l
|
|
||||||
#else
|
|
||||||
# define MI_L(x) x##ll
|
|
||||||
#endif
|
|
||||||
static inline size_t mi_bsf(uintptr_t x) {
|
|
||||||
return (x==0 ? 8*MI_INTPTR_SIZE : MI_L(__builtin_ctz)(x));
|
|
||||||
}
|
|
||||||
static inline size_t mi_bsr(uintptr_t x) {
|
|
||||||
return (x==0 ? 8*MI_INTPTR_SIZE : (8*MI_INTPTR_SIZE - 1) - MI_L(__builtin_clz)(x));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* -----------------------------------------------------------
|
/* -----------------------------------------------------------
|
||||||
Claim a bit sequence atomically
|
Claim a bit sequence atomically
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
// Try to atomically claim a sequence of `count` bits at in `idx`
|
|
||||||
// in the bitmap field. Returns `true` on success.
|
|
||||||
static inline bool mi_bitmap_try_claim_field(mi_bitmap_t bitmap, size_t bitmap_fields, const size_t count, mi_bitmap_index_t bitmap_idx) {
|
|
||||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
|
||||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
|
||||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
|
||||||
mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields);
|
|
||||||
mi_assert_internal(bitidx + count <= MI_BITMAP_FIELD_BITS);
|
|
||||||
|
|
||||||
uintptr_t field = mi_atomic_load_relaxed(&bitmap[idx]);
|
|
||||||
if ((field & mask) == 0) { // free?
|
|
||||||
if (mi_atomic_cas_strong_acq_rel(&bitmap[idx], &field, (field|mask))) {
|
|
||||||
// claimed!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Try to atomically claim a sequence of `count` bits in a single
|
// Try to atomically claim a sequence of `count` bits in a single
|
||||||
// field at `idx` in `bitmap`. Returns `true` on success.
|
// field at `idx` in `bitmap`. Returns `true` on success.
|
||||||
static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx)
|
bool _mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx)
|
||||||
{
|
{
|
||||||
mi_assert_internal(bitmap_idx != NULL);
|
mi_assert_internal(bitmap_idx != NULL);
|
||||||
mi_assert_internal(count <= MI_BITMAP_FIELD_BITS);
|
mi_assert_internal(count <= MI_BITMAP_FIELD_BITS);
|
||||||
@ -154,8 +53,8 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx
|
|||||||
const uintptr_t mask = mi_bitmap_mask_(count, 0);
|
const uintptr_t mask = mi_bitmap_mask_(count, 0);
|
||||||
const size_t bitidx_max = MI_BITMAP_FIELD_BITS - count;
|
const size_t bitidx_max = MI_BITMAP_FIELD_BITS - count;
|
||||||
|
|
||||||
#ifdef MI_HAVE_BITSCAN
|
#ifdef MI_HAVE_FAST_BITSCAN
|
||||||
size_t bitidx = mi_bsf(~map); // quickly find the first zero bit if possible
|
size_t bitidx = mi_ctz(~map); // quickly find the first zero bit if possible
|
||||||
#else
|
#else
|
||||||
size_t bitidx = 0; // otherwise start at 0
|
size_t bitidx = 0; // otherwise start at 0
|
||||||
#endif
|
#endif
|
||||||
@ -163,7 +62,8 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx
|
|||||||
|
|
||||||
// scan linearly for a free range of zero bits
|
// scan linearly for a free range of zero bits
|
||||||
while (bitidx <= bitidx_max) {
|
while (bitidx <= bitidx_max) {
|
||||||
if ((map & m) == 0) { // are the mask bits free at bitidx?
|
const uintptr_t mapm = map & m;
|
||||||
|
if (mapm == 0) { // are the mask bits free at bitidx?
|
||||||
mi_assert_internal((m >> bitidx) == mask); // no overflow?
|
mi_assert_internal((m >> bitidx) == mask); // no overflow?
|
||||||
const uintptr_t newmap = map | m;
|
const uintptr_t newmap = map | m;
|
||||||
mi_assert_internal((newmap^map) >> bitidx == mask);
|
mi_assert_internal((newmap^map) >> bitidx == mask);
|
||||||
@ -179,8 +79,8 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// on to the next bit range
|
// on to the next bit range
|
||||||
#ifdef MI_HAVE_BITSCAN
|
#ifdef MI_HAVE_FAST_BITSCAN
|
||||||
const size_t shift = (count == 1 ? 1 : mi_bsr(map & m) - bitidx + 1);
|
const size_t shift = (count == 1 ? 1 : mi_bsr(mapm) - bitidx + 1);
|
||||||
mi_assert_internal(shift > 0 && shift <= count);
|
mi_assert_internal(shift > 0 && shift <= count);
|
||||||
#else
|
#else
|
||||||
const size_t shift = 1;
|
const size_t shift = 1;
|
||||||
@ -196,28 +96,28 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx
|
|||||||
// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success.
|
// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success.
|
||||||
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
||||||
// `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields.
|
// `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields.
|
||||||
static inline bool mi_bitmap_try_find_from_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) {
|
bool _mi_bitmap_try_find_from_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) {
|
||||||
size_t idx = start_field_idx;
|
size_t idx = start_field_idx;
|
||||||
for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) {
|
for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) {
|
||||||
if (idx >= bitmap_fields) idx = 0; // wrap
|
if (idx >= bitmap_fields) idx = 0; // wrap
|
||||||
if (mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) {
|
if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success.
|
// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success.
|
||||||
// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never span fields.
|
// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never span fields.
|
||||||
static inline bool mi_bitmap_try_find_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t count, mi_bitmap_index_t* bitmap_idx) {
|
bool _mi_bitmap_try_find_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t count, mi_bitmap_index_t* bitmap_idx) {
|
||||||
return mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, 0, count, bitmap_idx);
|
return _mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, 0, count, bitmap_idx);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Set `count` bits at `bitmap_idx` to 0 atomically
|
// Set `count` bits at `bitmap_idx` to 0 atomically
|
||||||
// Returns `true` if all `count` bits were 1 previously.
|
// Returns `true` if all `count` bits were 1 previously.
|
||||||
static inline bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
bool _mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
||||||
@ -230,7 +130,7 @@ static inline bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, s
|
|||||||
|
|
||||||
// Set `count` bits at `bitmap_idx` to 1 atomically
|
// Set `count` bits at `bitmap_idx` to 1 atomically
|
||||||
// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit.
|
// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit.
|
||||||
static inline bool mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero) {
|
bool _mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero) {
|
||||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
||||||
@ -242,7 +142,7 @@ static inline bool mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, siz
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns `true` if all `count` bits were 1. `any_ones` is `true` if there was at least one bit set to one.
|
// Returns `true` if all `count` bits were 1. `any_ones` is `true` if there was at least one bit set to one.
|
||||||
static inline bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_ones) {
|
static bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_ones) {
|
||||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
||||||
@ -252,11 +152,11 @@ static inline bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_field
|
|||||||
return ((field & mask) == mask);
|
return ((field & mask) == mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
bool _mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||||
return mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, NULL);
|
return mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||||
bool any_ones;
|
bool any_ones;
|
||||||
mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, &any_ones);
|
mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, &any_ones);
|
||||||
return any_ones;
|
return any_ones;
|
||||||
@ -270,17 +170,17 @@ static inline bool mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fi
|
|||||||
|
|
||||||
// Try to atomically claim a sequence of `count` bits starting from the field
|
// Try to atomically claim a sequence of `count` bits starting from the field
|
||||||
// at `idx` in `bitmap` and crossing into subsequent fields. Returns `true` on success.
|
// at `idx` in `bitmap` and crossing into subsequent fields. Returns `true` on success.
|
||||||
static inline bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t idx, const size_t count, const size_t retries, mi_bitmap_index_t* bitmap_idx)
|
static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t idx, const size_t count, const size_t retries, mi_bitmap_index_t* bitmap_idx)
|
||||||
{
|
{
|
||||||
mi_assert_internal(bitmap_idx != NULL);
|
mi_assert_internal(bitmap_idx != NULL);
|
||||||
|
|
||||||
// check initial trailing zeros
|
// check initial trailing zeros
|
||||||
_Atomic(uintptr_t)* field = &bitmap[idx];
|
_Atomic(uintptr_t)* field = &bitmap[idx];
|
||||||
uintptr_t map = mi_atomic_load_relaxed(field);
|
uintptr_t map = mi_atomic_load_relaxed(field);
|
||||||
const uintptr_t bitidx = (map==0 ? 0 : mi_bsr(map) + 1);
|
const size_t initial = mi_clz(map); // count of initial zeros starting at idx
|
||||||
const size_t initial = MI_BITMAP_FIELD_BITS - bitidx; // count of initial zeros starting at idx
|
mi_assert_internal(initial >= 0 && initial <= MI_BITMAP_FIELD_BITS);
|
||||||
if (initial == 0) return false;
|
if (initial == 0) return false;
|
||||||
if (initial >= count) return mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields
|
if (initial >= count) return _mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields
|
||||||
if (_mi_divide_up(count - initial, MI_BITMAP_FIELD_BITS) >= (bitmap_fields - idx)) return false; // not enough entries
|
if (_mi_divide_up(count - initial, MI_BITMAP_FIELD_BITS) >= (bitmap_fields - idx)) return false; // not enough entries
|
||||||
|
|
||||||
// scan ahead
|
// scan ahead
|
||||||
@ -314,7 +214,7 @@ static inline bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, siz
|
|||||||
|
|
||||||
// intermediate fields
|
// intermediate fields
|
||||||
while (++field < final_field) {
|
while (++field < final_field) {
|
||||||
newmap = mi_bitmap_mask_(MI_BITMAP_FIELD_BITS, 0);
|
newmap = MI_BITMAP_FIELD_FULL;
|
||||||
map = 0;
|
map = 0;
|
||||||
if (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)) { goto rollback; }
|
if (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)) { goto rollback; }
|
||||||
}
|
}
|
||||||
@ -328,14 +228,14 @@ static inline bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, siz
|
|||||||
} while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap));
|
} while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap));
|
||||||
|
|
||||||
// claimed!
|
// claimed!
|
||||||
*bitmap_idx = mi_bitmap_index_create(idx, bitidx);
|
*bitmap_idx = mi_bitmap_index_create(idx, MI_BITMAP_FIELD_BITS - initial);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
rollback:
|
rollback:
|
||||||
// roll back intermediate fields
|
// roll back intermediate fields
|
||||||
while (--field > initial_field) {
|
while (--field > initial_field) {
|
||||||
newmap = 0;
|
newmap = 0;
|
||||||
map = mi_bitmap_mask_(MI_BITMAP_FIELD_BITS, 0);
|
map = MI_BITMAP_FIELD_FULL;
|
||||||
mi_assert_internal(mi_atomic_load_relaxed(field) == map);
|
mi_assert_internal(mi_atomic_load_relaxed(field) == map);
|
||||||
mi_atomic_store_release(field, newmap);
|
mi_atomic_store_release(field, newmap);
|
||||||
}
|
}
|
||||||
@ -358,15 +258,15 @@ rollback:
|
|||||||
|
|
||||||
// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success.
|
// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success.
|
||||||
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
||||||
static inline bool mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) {
|
bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) {
|
||||||
mi_assert_internal(count > 0);
|
mi_assert_internal(count > 0);
|
||||||
if (count==1) return mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, start_field_idx, count, bitmap_idx);
|
if (count==1) return _mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, start_field_idx, count, bitmap_idx);
|
||||||
size_t idx = start_field_idx;
|
size_t idx = start_field_idx;
|
||||||
for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) {
|
for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) {
|
||||||
if (idx >= bitmap_fields) idx = 0; // wrap
|
if (idx >= bitmap_fields) idx = 0; // wrap
|
||||||
// try to claim inside the field
|
// try to claim inside the field
|
||||||
if (count <= MI_BITMAP_FIELD_BITS) {
|
if (count <= MI_BITMAP_FIELD_BITS) {
|
||||||
if (mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) {
|
if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,7 +279,7 @@ static inline bool mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper for masks across fields; returns the mid count, post_mask may be 0
|
// Helper for masks across fields; returns the mid count, post_mask may be 0
|
||||||
static inline size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t bitmap_fields, size_t count, uintptr_t* pre_mask, uintptr_t* mid_mask, uintptr_t* post_mask) {
|
static size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t bitmap_fields, size_t count, uintptr_t* pre_mask, uintptr_t* mid_mask, uintptr_t* post_mask) {
|
||||||
UNUSED_RELEASE(bitmap_fields);
|
UNUSED_RELEASE(bitmap_fields);
|
||||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||||
if (mi_likely(bitidx + count <= MI_BITMAP_FIELD_BITS)) {
|
if (mi_likely(bitidx + count <= MI_BITMAP_FIELD_BITS)) {
|
||||||
@ -405,7 +305,7 @@ static inline size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t
|
|||||||
|
|
||||||
// Set `count` bits at `bitmap_idx` to 0 atomically
|
// Set `count` bits at `bitmap_idx` to 0 atomically
|
||||||
// Returns `true` if all `count` bits were 1 previously.
|
// Returns `true` if all `count` bits were 1 previously.
|
||||||
static inline bool mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
bool _mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||||
size_t idx = mi_bitmap_index_field(bitmap_idx);
|
size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||||
uintptr_t pre_mask;
|
uintptr_t pre_mask;
|
||||||
uintptr_t mid_mask;
|
uintptr_t mid_mask;
|
||||||
@ -428,7 +328,7 @@ static inline bool mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fi
|
|||||||
|
|
||||||
// Set `count` bits at `bitmap_idx` to 1 atomically
|
// Set `count` bits at `bitmap_idx` to 1 atomically
|
||||||
// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit.
|
// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit.
|
||||||
static inline bool mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero) {
|
bool _mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero) {
|
||||||
size_t idx = mi_bitmap_index_field(bitmap_idx);
|
size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||||
uintptr_t pre_mask;
|
uintptr_t pre_mask;
|
||||||
uintptr_t mid_mask;
|
uintptr_t mid_mask;
|
||||||
@ -457,7 +357,7 @@ static inline bool mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fiel
|
|||||||
|
|
||||||
// Returns `true` if all `count` bits were 1.
|
// Returns `true` if all `count` bits were 1.
|
||||||
// `any_ones` is `true` if there was at least one bit set to one.
|
// `any_ones` is `true` if there was at least one bit set to one.
|
||||||
static inline bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_ones) {
|
static bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_ones) {
|
||||||
size_t idx = mi_bitmap_index_field(bitmap_idx);
|
size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||||
uintptr_t pre_mask;
|
uintptr_t pre_mask;
|
||||||
uintptr_t mid_mask;
|
uintptr_t mid_mask;
|
||||||
@ -483,14 +383,14 @@ static inline bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitma
|
|||||||
return all_ones;
|
return all_ones;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||||
return mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, NULL);
|
return mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
/*
|
||||||
|
bool _mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||||
bool any_ones;
|
bool any_ones;
|
||||||
mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, &any_ones);
|
mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, &any_ones);
|
||||||
return any_ones;
|
return any_ones;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
#endif
|
|
106
src/bitmap.h
Normal file
106
src/bitmap.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
Copyright (c) 2019,2020 Microsoft Research, Daan Leijen
|
||||||
|
This is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the MIT license. A copy of the license can be found in the file
|
||||||
|
"LICENSE" at the root of this distribution.
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
Concurrent bitmap that can set/reset sequences of bits atomically,
|
||||||
|
represeted as an array of fields where each field is a machine word (`uintptr_t`)
|
||||||
|
|
||||||
|
There are two api's; the standard one cannot have sequences that cross
|
||||||
|
between the bitmap fields (and a sequence must be <= MI_BITMAP_FIELD_BITS).
|
||||||
|
(this is used in region allocation)
|
||||||
|
|
||||||
|
The `_across` postfixed functions do allow sequences that can cross over
|
||||||
|
between the fields. (This is used in arena allocation)
|
||||||
|
---------------------------------------------------------------------------- */
|
||||||
|
#pragma once
|
||||||
|
#ifndef MI_BITMAP_H
|
||||||
|
#define MI_BITMAP_H
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------
|
||||||
|
Bitmap definition
|
||||||
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define MI_BITMAP_FIELD_BITS (8*MI_INTPTR_SIZE)
|
||||||
|
#define MI_BITMAP_FIELD_FULL (~((uintptr_t)0)) // all bits set
|
||||||
|
|
||||||
|
// An atomic bitmap of `uintptr_t` fields
|
||||||
|
typedef _Atomic(uintptr_t) mi_bitmap_field_t;
|
||||||
|
typedef mi_bitmap_field_t* mi_bitmap_t;
|
||||||
|
|
||||||
|
// A bitmap index is the index of the bit in a bitmap.
|
||||||
|
typedef size_t mi_bitmap_index_t;
|
||||||
|
|
||||||
|
// Create a bit index.
|
||||||
|
static inline mi_bitmap_index_t mi_bitmap_index_create(size_t idx, size_t bitidx) {
|
||||||
|
mi_assert_internal(bitidx < MI_BITMAP_FIELD_BITS);
|
||||||
|
return (idx*MI_BITMAP_FIELD_BITS) + bitidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a bit index.
|
||||||
|
static inline mi_bitmap_index_t mi_bitmap_index_create_from_bit(size_t full_bitidx) {
|
||||||
|
return mi_bitmap_index_create(full_bitidx / MI_BITMAP_FIELD_BITS, full_bitidx % MI_BITMAP_FIELD_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the field index from a bit index.
|
||||||
|
static inline size_t mi_bitmap_index_field(mi_bitmap_index_t bitmap_idx) {
|
||||||
|
return (bitmap_idx / MI_BITMAP_FIELD_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the bit index in a bitmap field
|
||||||
|
static inline size_t mi_bitmap_index_bit_in_field(mi_bitmap_index_t bitmap_idx) {
|
||||||
|
return (bitmap_idx % MI_BITMAP_FIELD_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the full bit index
|
||||||
|
static inline size_t mi_bitmap_index_bit(mi_bitmap_index_t bitmap_idx) {
|
||||||
|
return bitmap_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------
|
||||||
|
Claim a bit sequence atomically
|
||||||
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Try to atomically claim a sequence of `count` bits in a single
|
||||||
|
// field at `idx` in `bitmap`. Returns `true` on success.
|
||||||
|
bool _mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx);
|
||||||
|
|
||||||
|
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
||||||
|
// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields.
|
||||||
|
bool _mi_bitmap_try_find_from_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx);
|
||||||
|
|
||||||
|
// Set `count` bits at `bitmap_idx` to 0 atomically
|
||||||
|
// Returns `true` if all `count` bits were 1 previously.
|
||||||
|
bool _mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx);
|
||||||
|
|
||||||
|
// Set `count` bits at `bitmap_idx` to 1 atomically
|
||||||
|
// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit.
|
||||||
|
bool _mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero);
|
||||||
|
|
||||||
|
bool _mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx);
|
||||||
|
bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx);
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// the `_across` functions work on bitmaps where sequences can cross over
|
||||||
|
// between the fields. This is used in arena allocation
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success.
|
||||||
|
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
||||||
|
bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx);
|
||||||
|
|
||||||
|
// Set `count` bits at `bitmap_idx` to 0 atomically
|
||||||
|
// Returns `true` if all `count` bits were 1 previously.
|
||||||
|
bool _mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx);
|
||||||
|
|
||||||
|
// Set `count` bits at `bitmap_idx` to 1 atomically
|
||||||
|
// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit.
|
||||||
|
bool _mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero);
|
||||||
|
|
||||||
|
bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx);
|
||||||
|
|
||||||
|
#endif
|
2
src/os.c
2
src/os.c
@ -368,7 +368,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
|
|||||||
const int fd = mi_unix_mmap_fd();
|
const int fd = mi_unix_mmap_fd();
|
||||||
#if defined(MAP_ALIGNED) // BSD
|
#if defined(MAP_ALIGNED) // BSD
|
||||||
if (try_alignment > 0) {
|
if (try_alignment > 0) {
|
||||||
size_t n = _mi_bsr(try_alignment);
|
size_t n = mi_bsr(try_alignment);
|
||||||
if (((size_t)1 << n) == try_alignment && n >= 12 && n <= 30) { // alignment is a power of 2 and 4096 <= alignment <= 1GiB
|
if (((size_t)1 << n) == try_alignment && n >= 12 && n <= 30) { // alignment is a power of 2 and 4096 <= alignment <= 1GiB
|
||||||
flags |= MAP_ALIGNED(n);
|
flags |= MAP_ALIGNED(n);
|
||||||
}
|
}
|
||||||
|
@ -49,50 +49,6 @@ static inline bool mi_page_queue_is_special(const mi_page_queue_t* pq) {
|
|||||||
Bins
|
Bins
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
// Bit scan reverse: return the index of the highest bit.
|
|
||||||
static inline uint8_t mi_bsr32(uint32_t x);
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#include <intrin.h>
|
|
||||||
static inline uint8_t mi_bsr32(uint32_t x) {
|
|
||||||
uint32_t idx;
|
|
||||||
_BitScanReverse((DWORD*)&idx, x);
|
|
||||||
return (uint8_t)idx;
|
|
||||||
}
|
|
||||||
#elif defined(__GNUC__) || defined(__clang__)
|
|
||||||
static inline uint8_t mi_bsr32(uint32_t x) {
|
|
||||||
return (31 - __builtin_clz(x));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline uint8_t mi_bsr32(uint32_t x) {
|
|
||||||
// de Bruijn multiplication, see <http://supertech.csail.mit.edu/papers/debruijn.pdf>
|
|
||||||
static const uint8_t debruijn[32] = {
|
|
||||||
31, 0, 22, 1, 28, 23, 18, 2, 29, 26, 24, 10, 19, 7, 3, 12,
|
|
||||||
30, 21, 27, 17, 25, 9, 6, 11, 20, 16, 8, 5, 15, 4, 14, 13,
|
|
||||||
};
|
|
||||||
x |= x >> 1;
|
|
||||||
x |= x >> 2;
|
|
||||||
x |= x >> 4;
|
|
||||||
x |= x >> 8;
|
|
||||||
x |= x >> 16;
|
|
||||||
x++;
|
|
||||||
return debruijn[(x*0x076be629) >> 27];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Bit scan reverse: return the index of the highest bit.
|
|
||||||
uint8_t _mi_bsr(uintptr_t x) {
|
|
||||||
if (x == 0) return 0;
|
|
||||||
#if MI_INTPTR_SIZE==8
|
|
||||||
uint32_t hi = (x >> 32);
|
|
||||||
return (hi == 0 ? mi_bsr32((uint32_t)x) : 32 + mi_bsr32(hi));
|
|
||||||
#elif MI_INTPTR_SIZE==4
|
|
||||||
return mi_bsr32(x);
|
|
||||||
#else
|
|
||||||
# error "define bsr for non-32 or 64-bit platforms"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the bin for a given field size.
|
// Return the bin for a given field size.
|
||||||
// Returns MI_BIN_HUGE if the size is too large.
|
// Returns MI_BIN_HUGE if the size is too large.
|
||||||
// We use `wsize` for the size in "machine word sizes",
|
// We use `wsize` for the size in "machine word sizes",
|
||||||
@ -125,7 +81,7 @@ extern inline uint8_t _mi_bin(size_t size) {
|
|||||||
#endif
|
#endif
|
||||||
wsize--;
|
wsize--;
|
||||||
// find the highest bit
|
// find the highest bit
|
||||||
uint8_t b = mi_bsr32((uint32_t)wsize);
|
uint8_t b = (uint8_t)mi_bsr(wsize); // note: wsize != 0
|
||||||
// and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation).
|
// and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation).
|
||||||
// - adjust with 3 because we use do not round the first 8 sizes
|
// - adjust with 3 because we use do not round the first 8 sizes
|
||||||
// which each get an exact bin
|
// which each get an exact bin
|
||||||
|
26
src/region.c
26
src/region.c
@ -37,7 +37,7 @@ Possible issues:
|
|||||||
|
|
||||||
#include <string.h> // memset
|
#include <string.h> // memset
|
||||||
|
|
||||||
#include "bitmap.inc.c"
|
#include "bitmap.h"
|
||||||
|
|
||||||
// Internal raw OS interface
|
// Internal raw OS interface
|
||||||
size_t _mi_os_large_page_size();
|
size_t _mi_os_large_page_size();
|
||||||
@ -200,7 +200,7 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large,
|
|||||||
mi_atomic_store_release(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0));
|
mi_atomic_store_release(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0));
|
||||||
mi_atomic_store_release(&r->reset, (uintptr_t)0);
|
mi_atomic_store_release(&r->reset, (uintptr_t)0);
|
||||||
*bit_idx = 0;
|
*bit_idx = 0;
|
||||||
mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL);
|
_mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL);
|
||||||
mi_atomic_store_ptr_release(void,&r->start, start);
|
mi_atomic_store_ptr_release(void,&r->start, start);
|
||||||
|
|
||||||
// and share it
|
// and share it
|
||||||
@ -248,7 +248,7 @@ static bool mi_region_try_claim(int numa_node, size_t blocks, bool allow_large,
|
|||||||
// if this region suits our demand (numa node matches, large OS page matches)
|
// if this region suits our demand (numa node matches, large OS page matches)
|
||||||
if (mi_region_is_suitable(r, numa_node, allow_large)) {
|
if (mi_region_is_suitable(r, numa_node, allow_large)) {
|
||||||
// then try to atomically claim a segment(s) in this region
|
// then try to atomically claim a segment(s) in this region
|
||||||
if (mi_bitmap_try_find_claim_field(&r->in_use, 0, blocks, bit_idx)) {
|
if (_mi_bitmap_try_find_claim_field(&r->in_use, 0, blocks, bit_idx)) {
|
||||||
tld->region_idx = idx; // remember the last found position
|
tld->region_idx = idx; // remember the last found position
|
||||||
*region = r;
|
*region = r;
|
||||||
return true;
|
return true;
|
||||||
@ -277,7 +277,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo
|
|||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// found a region and claimed `blocks` at `bit_idx`, initialize them now
|
// found a region and claimed `blocks` at `bit_idx`, initialize them now
|
||||||
mi_assert_internal(region != NULL);
|
mi_assert_internal(region != NULL);
|
||||||
mi_assert_internal(mi_bitmap_is_claimed(®ion->in_use, 1, blocks, bit_idx));
|
mi_assert_internal(_mi_bitmap_is_claimed(®ion->in_use, 1, blocks, bit_idx));
|
||||||
|
|
||||||
mi_region_info_t info;
|
mi_region_info_t info;
|
||||||
info.value = mi_atomic_load_acquire(®ion->info);
|
info.value = mi_atomic_load_acquire(®ion->info);
|
||||||
@ -285,7 +285,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo
|
|||||||
mi_assert_internal(!(info.x.is_large && !*is_large));
|
mi_assert_internal(!(info.x.is_large && !*is_large));
|
||||||
mi_assert_internal(start != NULL);
|
mi_assert_internal(start != NULL);
|
||||||
|
|
||||||
*is_zero = mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL);
|
*is_zero = _mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL);
|
||||||
*is_large = info.x.is_large;
|
*is_large = info.x.is_large;
|
||||||
*memid = mi_memid_create(region, bit_idx);
|
*memid = mi_memid_create(region, bit_idx);
|
||||||
void* p = start + (mi_bitmap_index_bit_in_field(bit_idx) * MI_SEGMENT_SIZE);
|
void* p = start + (mi_bitmap_index_bit_in_field(bit_idx) * MI_SEGMENT_SIZE);
|
||||||
@ -294,7 +294,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo
|
|||||||
if (*commit) {
|
if (*commit) {
|
||||||
// ensure commit
|
// ensure commit
|
||||||
bool any_uncommitted;
|
bool any_uncommitted;
|
||||||
mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted);
|
_mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted);
|
||||||
if (any_uncommitted) {
|
if (any_uncommitted) {
|
||||||
mi_assert_internal(!info.x.is_large);
|
mi_assert_internal(!info.x.is_large);
|
||||||
bool commit_zero;
|
bool commit_zero;
|
||||||
@ -304,12 +304,12 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// no need to commit, but check if already fully committed
|
// no need to commit, but check if already fully committed
|
||||||
*commit = mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx);
|
*commit = _mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx);
|
||||||
}
|
}
|
||||||
mi_assert_internal(!*commit || mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx));
|
mi_assert_internal(!*commit || _mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx));
|
||||||
|
|
||||||
// unreset reset blocks
|
// unreset reset blocks
|
||||||
if (mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)) {
|
if (_mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)) {
|
||||||
// some blocks are still reset
|
// some blocks are still reset
|
||||||
mi_assert_internal(!info.x.is_large);
|
mi_assert_internal(!info.x.is_large);
|
||||||
mi_assert_internal(!mi_option_is_enabled(mi_option_eager_commit) || *commit || mi_option_get(mi_option_eager_commit_delay) > 0);
|
mi_assert_internal(!mi_option_is_enabled(mi_option_eager_commit) || *commit || mi_option_get(mi_option_eager_commit_delay) > 0);
|
||||||
@ -320,7 +320,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo
|
|||||||
if (reset_zero) *is_zero = true;
|
if (reset_zero) *is_zero = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mi_assert_internal(!mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx));
|
mi_assert_internal(!_mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx));
|
||||||
|
|
||||||
#if (MI_DEBUG>=2)
|
#if (MI_DEBUG>=2)
|
||||||
if (*commit) { ((uint8_t*)p)[0] = 0; }
|
if (*commit) { ((uint8_t*)p)[0] = 0; }
|
||||||
@ -409,12 +409,12 @@ void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_re
|
|||||||
|
|
||||||
// committed?
|
// committed?
|
||||||
if (full_commit && (size % MI_SEGMENT_SIZE) == 0) {
|
if (full_commit && (size % MI_SEGMENT_SIZE) == 0) {
|
||||||
mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, NULL);
|
_mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any_reset) {
|
if (any_reset) {
|
||||||
// set the is_reset bits if any pages were reset
|
// set the is_reset bits if any pages were reset
|
||||||
mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, NULL);
|
_mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the blocks to reduce the working set.
|
// reset the blocks to reduce the working set.
|
||||||
@ -423,7 +423,7 @@ void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_re
|
|||||||
mi_option_is_enabled(mi_option_reset_decommits))) // cannot reset halfway committed segments, use only `option_page_reset` instead
|
mi_option_is_enabled(mi_option_reset_decommits))) // cannot reset halfway committed segments, use only `option_page_reset` instead
|
||||||
{
|
{
|
||||||
bool any_unreset;
|
bool any_unreset;
|
||||||
mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, &any_unreset);
|
_mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, &any_unreset);
|
||||||
if (any_unreset) {
|
if (any_unreset) {
|
||||||
_mi_abandoned_await_readers(); // ensure no more pending write (in case reset = decommit)
|
_mi_abandoned_await_readers(); // ensure no more pending write (in case reset = decommit)
|
||||||
_mi_mem_reset(p, blocks * MI_SEGMENT_SIZE, tld);
|
_mi_mem_reset(p, blocks * MI_SEGMENT_SIZE, tld);
|
||||||
|
@ -7,7 +7,6 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
#include "mimalloc.h"
|
#include "mimalloc.h"
|
||||||
#include "mimalloc-internal.h"
|
#include "mimalloc-internal.h"
|
||||||
#include "mimalloc-atomic.h"
|
#include "mimalloc-atomic.h"
|
||||||
#include "bitmap.inc.c" // mi_bsr
|
|
||||||
|
|
||||||
#include <string.h> // memset
|
#include <string.h> // memset
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -49,29 +48,26 @@ static uint8_t* mi_slice_start(const mi_slice_t* slice) {
|
|||||||
Bins
|
Bins
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
// Use bit scan forward to quickly find the first zero bit if it is available
|
// Use bit scan forward to quickly find the first zero bit if it is available
|
||||||
#if !defined(MI_HAVE_BITSCAN)
|
|
||||||
#error "define bsr for your platform"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static size_t mi_slice_bin8(size_t slice_count) {
|
static inline size_t mi_slice_bin8(size_t slice_count) {
|
||||||
if (slice_count<=1) return slice_count;
|
if (slice_count<=1) return slice_count;
|
||||||
mi_assert_internal(slice_count <= MI_SLICES_PER_SEGMENT);
|
mi_assert_internal(slice_count <= MI_SLICES_PER_SEGMENT);
|
||||||
slice_count--;
|
slice_count--;
|
||||||
size_t s = mi_bsr(slice_count);
|
size_t s = mi_bsr(slice_count); // slice_count > 1
|
||||||
if (s <= 2) return slice_count + 1;
|
if (s <= 2) return slice_count + 1;
|
||||||
size_t bin = ((s << 2) | ((slice_count >> (s - 2))&0x03)) - 4;
|
size_t bin = ((s << 2) | ((slice_count >> (s - 2))&0x03)) - 4;
|
||||||
return bin;
|
return bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t mi_slice_bin(size_t slice_count) {
|
static inline size_t mi_slice_bin(size_t slice_count) {
|
||||||
mi_assert_internal(slice_count*MI_SEGMENT_SLICE_SIZE <= MI_SEGMENT_SIZE);
|
mi_assert_internal(slice_count*MI_SEGMENT_SLICE_SIZE <= MI_SEGMENT_SIZE);
|
||||||
mi_assert_internal(mi_slice_bin8(MI_SLICES_PER_SEGMENT) <= MI_SEGMENT_BIN_MAX);
|
mi_assert_internal(mi_slice_bin8(MI_SLICES_PER_SEGMENT) <= MI_SEGMENT_BIN_MAX);
|
||||||
size_t bin = (slice_count==0 ? 0 : mi_slice_bin8(slice_count));
|
size_t bin = mi_slice_bin8(slice_count);
|
||||||
mi_assert_internal(bin <= MI_SEGMENT_BIN_MAX);
|
mi_assert_internal(bin <= MI_SEGMENT_BIN_MAX);
|
||||||
return bin;
|
return bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t mi_slice_index(const mi_slice_t* slice) {
|
static inline size_t mi_slice_index(const mi_slice_t* slice) {
|
||||||
mi_segment_t* segment = _mi_ptr_segment(slice);
|
mi_segment_t* segment = _mi_ptr_segment(slice);
|
||||||
ptrdiff_t index = slice - segment->slices;
|
ptrdiff_t index = slice - segment->slices;
|
||||||
mi_assert_internal(index >= 0 && index < (ptrdiff_t)segment->slice_entries);
|
mi_assert_internal(index >= 0 && index < (ptrdiff_t)segment->slice_entries);
|
||||||
@ -1436,7 +1432,7 @@ static mi_segment_t* _mi_segment_of(const void* p) {
|
|||||||
}
|
}
|
||||||
if (index==0) return NULL;
|
if (index==0) return NULL;
|
||||||
// search downwards for the first segment in case it is an interior pointer
|
// search downwards for the first segment in case it is an interior pointer
|
||||||
// could be slow but searches in MI_INTPTR_SIZE * MI_SEGMENT_SIZE (4GiB) steps trough
|
// could be slow but searches in MI_INTPTR_SIZE * MI_SEGMENT_SIZE (512MiB) steps trough
|
||||||
// valid huge objects
|
// valid huge objects
|
||||||
// note: we could maintain a lowest index to speed up the path for invalid pointers?
|
// note: we could maintain a lowest index to speed up the path for invalid pointers?
|
||||||
size_t lobitidx;
|
size_t lobitidx;
|
||||||
@ -1444,14 +1440,14 @@ static mi_segment_t* _mi_segment_of(const void* p) {
|
|||||||
uintptr_t lobits = mask & (((uintptr_t)1 << bitidx) - 1);
|
uintptr_t lobits = mask & (((uintptr_t)1 << bitidx) - 1);
|
||||||
if (lobits != 0) {
|
if (lobits != 0) {
|
||||||
loindex = index;
|
loindex = index;
|
||||||
lobitidx = _mi_bsr(lobits);
|
lobitidx = mi_bsr(lobits); // lobits != 0
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uintptr_t lomask = mask;
|
uintptr_t lomask = mask;
|
||||||
loindex = index - 1;
|
loindex = index - 1;
|
||||||
while (loindex > 0 && (lomask = mi_atomic_load_relaxed(&mi_segment_map[loindex])) == 0) loindex--;
|
while (loindex > 0 && (lomask = mi_atomic_load_relaxed(&mi_segment_map[loindex])) == 0) loindex--;
|
||||||
if (loindex==0) return NULL;
|
if (loindex==0) return NULL;
|
||||||
lobitidx = _mi_bsr(lomask);
|
lobitidx = mi_bsr(lomask); // lomask != 0
|
||||||
}
|
}
|
||||||
// take difference as the addresses could be larger than the MAX_ADDRESS space.
|
// take difference as the addresses could be larger than the MAX_ADDRESS space.
|
||||||
size_t diff = (((index - loindex) * (8*MI_INTPTR_SIZE)) + bitidx - lobitidx) * MI_SEGMENT_SIZE;
|
size_t diff = (((index - loindex) * (8*MI_INTPTR_SIZE)) + bitidx - lobitidx) * MI_SEGMENT_SIZE;
|
||||||
|
@ -23,7 +23,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
#include "stats.c"
|
#include "stats.c"
|
||||||
#include "random.c"
|
#include "random.c"
|
||||||
#include "os.c"
|
#include "os.c"
|
||||||
//#include "memory.c"
|
#include "bitmap.c"
|
||||||
#include "arena.c"
|
#include "arena.c"
|
||||||
#include "segment.c"
|
#include "segment.c"
|
||||||
#include "page.c"
|
#include "page.c"
|
||||||
|
Loading…
Reference in New Issue
Block a user