fix heap cleanup when heaps share memory page (#163)

This commit is contained in:
Mattias Jansson
2020-03-25 11:44:45 +01:00
committed by GitHub
parent 5e752e65fe
commit b5f7768ea4
6 changed files with 250 additions and 19 deletions

2
.gitignore vendored
View File

@@ -13,6 +13,8 @@ local.properties
.loadpath
.ninja*
build.ninja
.vs
.vscode
# Generated version
version.c

View File

@@ -0,0 +1,213 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\rpmalloc\rpmalloc.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\rpmalloc\rpmalloc.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{01b8c8be-038d-482f-b016-3a9496ac41b0}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>rpmalloc-test</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>..\..\lib\windows\debug\x86\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>..\..\lib\windows\release\x86\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>..\..\lib\windows\debug\x86-64\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>..\..\lib\windows\release\x86-64\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_ASSERTS=1;ENABLE_STATISTICS=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>false</ExceptionHandling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>false</FunctionLevelLinking>
<EnableParallelCodeGeneration>false</EnableParallelCodeGeneration>
<FloatingPointModel>Fast</FloatingPointModel>
<FloatingPointExceptions>false</FloatingPointExceptions>
<CreateHotpatchableImage>false</CreateHotpatchableImage>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAsManaged>false</CompileAsManaged>
<CompileAsWinRT>false</CompileAsWinRT>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_ASSERTS=1;ENABLE_STATISTICS=1;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>false</ExceptionHandling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FunctionLevelLinking>false</FunctionLevelLinking>
<EnableParallelCodeGeneration>false</EnableParallelCodeGeneration>
<FloatingPointModel>Fast</FloatingPointModel>
<FloatingPointExceptions>false</FloatingPointExceptions>
<CreateHotpatchableImage>false</CreateHotpatchableImage>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAsManaged>false</CompileAsManaged>
<CompileAsWinRT>false</CompileAsWinRT>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>Full</Optimization>
<FunctionLevelLinking>false</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>ENABLE_ASSERTS=1;ENABLE_STATISTICS=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableParallelCodeGeneration>false</EnableParallelCodeGeneration>
<FloatingPointModel>Fast</FloatingPointModel>
<FloatingPointExceptions>false</FloatingPointExceptions>
<CreateHotpatchableImage>false</CreateHotpatchableImage>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<CompileAsManaged>false</CompileAsManaged>
<CompileAsWinRT>false</CompileAsWinRT>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>Full</Optimization>
<FunctionLevelLinking>false</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>ENABLE_ASSERTS=1;ENABLE_STATISTICS=1;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableParallelCodeGeneration>false</EnableParallelCodeGeneration>
<FloatingPointModel>Fast</FloatingPointModel>
<FloatingPointExceptions>false</FloatingPointExceptions>
<CreateHotpatchableImage>false</CreateHotpatchableImage>
<CompileAsManaged>false</CompileAsManaged>
<CompileAsWinRT>false</CompileAsWinRT>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,12 +1,14 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 16
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.202
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpmalloc", "rpmalloc.vcxproj", "{65DC4291-954E-4B91-8889-4F3ADCC9D2D5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{C31980DD-1241-4EF8-A351-69DAF982A7B9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpmalloc-test", "rpmalloc-test.vcxproj", "{01B8C8BE-038D-482F-B016-3A9496AC41B0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -31,6 +33,14 @@ Global
{C31980DD-1241-4EF8-A351-69DAF982A7B9}.Release|x64.Build.0 = Release|x64
{C31980DD-1241-4EF8-A351-69DAF982A7B9}.Release|x86.ActiveCfg = Release|Win32
{C31980DD-1241-4EF8-A351-69DAF982A7B9}.Release|x86.Build.0 = Release|Win32
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Debug|x64.ActiveCfg = Debug|x64
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Debug|x64.Build.0 = Debug|x64
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Debug|x86.ActiveCfg = Debug|Win32
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Debug|x86.Build.0 = Debug|Win32
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Release|x64.ActiveCfg = Release|x64
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Release|x64.Build.0 = Release|x64
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Release|x86.ActiveCfg = Release|Win32
{01B8C8BE-038D-482F-B016-3A9496AC41B0}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -27,8 +27,8 @@
<ClInclude Include="..\..\test\thread.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="rpmalloc.vcxproj">
<Project>{65dc4291-954e-4b91-8889-4f3adcc9d2d5}</Project>
<ProjectReference Include="rpmalloc-test.vcxproj">
<Project>{01b8c8be-038d-482f-b016-3a9496ac41b0}</Project>
</ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@@ -745,7 +745,7 @@ _rpmalloc_mmap_os(size_t size, size_t* offset) {
//Ok to MEM_COMMIT - according to MSDN, "actual physical pages are not allocated unless/until the virtual addresses are actually accessed"
void* ptr = VirtualAlloc(0, size + padding, (_memory_huge_pages ? MEM_LARGE_PAGES : 0) | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!ptr) {
assert(!"Failed to map virtual memory block");
assert(ptr && "Failed to map virtual memory block");
return 0;
}
#else
@@ -1378,17 +1378,14 @@ _rpmalloc_heap_unlink_orphan(atomicptr_t* list, heap_t* heap) {
static void
_rpmalloc_heap_unmap(heap_t* heap) {
if (!heap->master_heap) {
if (!atomic_load32(&heap->child_count)) {
_rpmalloc_heap_unlink_orphan(&_memory_orphan_heaps, heap);
#if RPMALLOC_FIRST_CLASS_HEAPS
_rpmalloc_heap_unlink_orphan(&_memory_first_class_orphan_heaps, heap);
#endif
size_t block_size = (1 + (sizeof(heap_t) >> _memory_page_size_shift)) * _memory_page_size;
if ((heap->finalize > 1) && !atomic_load32(&heap->child_count)) {
size_t heap_size = sizeof(heap_t);
size_t block_size = _memory_page_size * ((heap_size + _memory_page_size - 1) >> _memory_page_size_shift);
_rpmalloc_unmap(heap, block_size, heap->align_offset, block_size);
}
} else {
if (atomic_decr32(&heap->master_heap->child_count) == 0) {
_rpmalloc_heap_global_finalize(heap->master_heap);
_rpmalloc_heap_unmap(heap->master_heap);
}
}
}
@@ -1594,7 +1591,8 @@ static heap_t*
_rpmalloc_heap_allocate_new(void) {
//Map in pages for a new heap
size_t align_offset = 0;
size_t block_size = (1 + (sizeof(heap_t) >> _memory_page_size_shift)) * _memory_page_size;
size_t heap_size = sizeof(heap_t);
size_t block_size = _memory_page_size* ((heap_size + _memory_page_size - 1) >> _memory_page_size_shift);
heap_t* heap = (heap_t*)_rpmalloc_mmap(block_size, &align_offset);
if (!heap)
return heap;
@@ -1603,9 +1601,7 @@ _rpmalloc_heap_allocate_new(void) {
heap->align_offset = align_offset;
//Put extra heaps as orphans, aligning to make sure ABA protection bits fit in pointer low bits
size_t aligned_heap_size = sizeof(heap_t);
if (aligned_heap_size % HEAP_ORPHAN_ABA_SIZE)
aligned_heap_size += HEAP_ORPHAN_ABA_SIZE - (aligned_heap_size % HEAP_ORPHAN_ABA_SIZE);
size_t aligned_heap_size = HEAP_ORPHAN_ABA_SIZE * ((heap_size + HEAP_ORPHAN_ABA_SIZE - 1) / HEAP_ORPHAN_ABA_SIZE);
size_t num_heaps = block_size / aligned_heap_size;
atomic_store32(&heap->child_count, (int32_t)num_heaps - 1);
heap_t* extra_heap = (heap_t*)pointer_offset(heap, aligned_heap_size);
@@ -2525,6 +2521,12 @@ rpmalloc_initialize_config(const rpmalloc_config_t* config) {
_rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass);
}
atomic_store_ptr(&_memory_orphan_heaps, 0);
#if RPMALLOC_FIRST_CLASS_HEAPS
atomic_store_ptr(&_memory_first_class_orphan_heaps, 0);
#endif
memset((void*)_memory_heaps, 0, sizeof(_memory_heaps));
//Initialize this thread
rpmalloc_thread_initialize();
return 0;
@@ -2591,6 +2593,7 @@ rpmalloc_thread_finalize(void) {
heap_t* heap = get_thread_heap_raw();
if (heap)
_rpmalloc_heap_release_raw(heap);
set_thread_heap(0);
#if defined(_MSC_VER) && !defined(__clang__) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
FlsSetValue(fls_key, 0);
#endif

11
test/main.c vendored
View File

@@ -18,6 +18,7 @@
#define pointer_diff(first, second) (ptrdiff_t)((const char*)(first) - (const char*)(second))
static size_t _hardware_threads;
static int _test_failed;
static void
test_initialize(void);
@@ -25,6 +26,8 @@ test_initialize(void);
static int
test_fail_cb(const char* reason, const char* file, int line) {
fprintf(stderr, "FAIL: %s @ %s:%d\n", reason, file, line);
fflush(stderr);
_test_failed = 1;
return -1;
}
@@ -650,7 +653,7 @@ crossallocator_thread(void* argp) {
rpfree(extra_pointers);
while (next_crossthread < end_crossthread) {
while ((next_crossthread < end_crossthread) && !_test_failed) {
if (arg.crossthread_pointers[next_crossthread]) {
rpfree(arg.crossthread_pointers[next_crossthread]);
arg.crossthread_pointers[next_crossthread] = 0;
@@ -794,7 +797,7 @@ test_threaded(void) {
arg.passes = 4000;
#else
arg.loops = 30;
arg.passes = 2000;
arg.passes = 1000;
#endif
arg.init_fini_each_loop = 0;
@@ -841,8 +844,8 @@ test_crossthread(void) {
arg[ithread].loops = 50;
arg[ithread].passes = 1024;
#else
arg[ithread].loops = 10;
arg[ithread].passes = 100;
arg[ithread].loops = 20;
arg[ithread].passes = 200;
#endif
arg[ithread].pointers = rpmalloc(sizeof(void*) * arg[ithread].loops * arg[ithread].passes);
memset(arg[ithread].pointers, 0, sizeof(void*) * arg[ithread].loops * arg[ithread].passes);