Introduce header layering (#503)
See src/snmalloc/README.md for an explanation of the layers. Some other cleanups on the way: Fine-grained stats support is now gone. It's been broken for two years, it depends on iostream (which then causes linker failures with libstdc++) and it's collecting the wrong stats for the new design. After discussion with @mjp41, it's better to remove it and introduce new stats support later, rather than keep broken code in the main branch. Tracing was controlled with a preprocessor macro, now there's also a CMake option.
This commit is contained in:
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -287,7 +287,7 @@ jobs:
|
||||
git diff --exit-code
|
||||
- name: Run clang-tidy
|
||||
run: |
|
||||
clang-tidy-9 src/override/malloc.cc -header-filter="`pwd`/*" -warnings-as-errors='*' -export-fixes=tidy.fail -- -std=c++17 -mcx16 -DSNMALLOC_PLATFORM_HAS_GETENTROPY=0
|
||||
clang-tidy-9 src/snmalloc/override/malloc.cc -header-filter="`pwd`/*" -warnings-as-errors='*' -export-fixes=tidy.fail -- -std=c++17 -mcx16 -DSNMALLOC_PLATFORM_HAS_GETENTROPY=0
|
||||
if [ -f tidy.fail ] ; then
|
||||
cat tidy.fail
|
||||
exit 1
|
||||
|
||||
@@ -12,10 +12,10 @@ include(CMakeDependentOption)
|
||||
|
||||
option(SNMALLOC_HEADER_ONLY_LIBRARY "Use snmalloc has a header-only library" OFF)
|
||||
# Options that apply globally
|
||||
option(USE_SNMALLOC_STATS "Track allocation stats" OFF)
|
||||
option(SNMALLOC_CI_BUILD "Disable features not sensible for CI" OFF)
|
||||
option(SNMALLOC_QEMU_WORKAROUND "Disable using madvise(DONT_NEED) to zero memory on Linux" Off)
|
||||
option(SNMALLOC_USE_CXX17 "Build as C++17 for legacy support." OFF)
|
||||
option(SNMALLOC_TRACING "Enable large quantities of debug output." OFF)
|
||||
option(SNMALLOC_NO_REALLOCARRAY "Build without reallocarray exported" ON)
|
||||
option(SNMALLOC_NO_REALLOCARR "Build without reallocarr exported" ON)
|
||||
# Options that apply only if we're not building the header-only library
|
||||
@@ -198,8 +198,8 @@ function(add_as_define FLAG)
|
||||
target_compile_definitions(snmalloc INTERFACE $<$<BOOL:${${FLAG}}>:${FLAG}>)
|
||||
endfunction()
|
||||
|
||||
add_as_define(USE_SNMALLOC_STATS)
|
||||
add_as_define(SNMALLOC_QEMU_WORKAROUND)
|
||||
add_as_define(SNMALLOC_TRACING)
|
||||
add_as_define(SNMALLOC_CI_BUILD)
|
||||
add_as_define(SNMALLOC_PLATFORM_HAS_GETENTROPY)
|
||||
if (SNMALLOC_NO_REALLOCARRAY)
|
||||
@@ -328,9 +328,9 @@ if(NOT SNMALLOC_HEADER_ONLY_LIBRARY)
|
||||
|
||||
endfunction()
|
||||
|
||||
set(SHIM_FILES src/override/new.cc)
|
||||
set(SHIM_FILES src/snmalloc/override/new.cc)
|
||||
if (SNMALLOC_MEMCPY_BOUNDS)
|
||||
list(APPEND SHIM_FILES src/override/memcpy.cc)
|
||||
list(APPEND SHIM_FILES src/snmalloc/override/memcpy.cc)
|
||||
endif ()
|
||||
|
||||
if (SNMALLOC_STATIC_LIBRARY)
|
||||
@@ -346,8 +346,8 @@ if(NOT SNMALLOC_HEADER_ONLY_LIBRARY)
|
||||
endif()
|
||||
|
||||
if(SNMALLOC_RUST_SUPPORT)
|
||||
add_shim(snmallocshim-rust STATIC src/override/rust.cc)
|
||||
add_shim(snmallocshim-checks-rust STATIC src/override/rust.cc)
|
||||
add_shim(snmallocshim-rust STATIC src/snmalloc/override/rust.cc)
|
||||
add_shim(snmallocshim-checks-rust STATIC src/snmalloc/override/rust.cc)
|
||||
target_compile_definitions(snmallocshim-checks-rust PRIVATE SNMALLOC_CHECK_CLIENT)
|
||||
endif()
|
||||
|
||||
@@ -426,9 +426,6 @@ if(NOT SNMALLOC_HEADER_ONLY_LIBRARY)
|
||||
set_tests_properties(${TESTNAME} PROPERTIES PROCESSORS 4)
|
||||
endif()
|
||||
endif()
|
||||
# if (${TEST_CATEGORY} MATCHES "func")
|
||||
# target_compile_definitions(${TESTNAME} PRIVATE -DUSE_SNMALLOC_STATS)
|
||||
# endif ()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endforeach()
|
||||
@@ -441,12 +438,12 @@ install(TARGETS snmalloc EXPORT snmallocConfig)
|
||||
install(TARGETS EXPORT snmallocConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/snmalloc)
|
||||
|
||||
install(DIRECTORY src/aal DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/ds DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/override DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/backend DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/mem DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/pal DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/snmalloc/aal DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/snmalloc/ds DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/snmalloc/override DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/snmalloc/backend DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/snmalloc/mem DESTINATION include/snmalloc)
|
||||
install(DIRECTORY src/snmalloc/pal DESTINATION include/snmalloc)
|
||||
install(FILES
|
||||
src/test/measuretime.h
|
||||
src/test/opt.h
|
||||
@@ -455,7 +452,7 @@ install(FILES
|
||||
src/test/xoroshiro.h
|
||||
DESTINATION include/snmalloc/test
|
||||
)
|
||||
install(FILES src/snmalloc.h;src/snmalloc_core.h;src/snmalloc_front.h DESTINATION include/snmalloc)
|
||||
install(FILES src/snmalloc/snmalloc.h;src/snmalloc/snmalloc_core.h;src/snmalloc/snmalloc_front.h DESTINATION include/snmalloc)
|
||||
|
||||
install(EXPORT snmallocConfig
|
||||
FILE snmalloc-config.cmake
|
||||
|
||||
55
src/ds/csv.h
55
src/ds/csv.h
@@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
class CSVStream
|
||||
{
|
||||
private:
|
||||
std::ostream* out;
|
||||
bool first = true;
|
||||
|
||||
public:
|
||||
class Endl
|
||||
{};
|
||||
|
||||
Endl endl;
|
||||
|
||||
CSVStream(std::ostream* o) : out(o) {}
|
||||
|
||||
void preprint()
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
*out << ", ";
|
||||
}
|
||||
else
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
CSVStream& operator<<(const std::string& str)
|
||||
{
|
||||
preprint();
|
||||
*out << str;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CSVStream& operator<<(uint64_t u)
|
||||
{
|
||||
preprint();
|
||||
*out << u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CSVStream& operator<<(Endl)
|
||||
{
|
||||
*out << std::endl;
|
||||
first = true;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
@@ -1,428 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../mem/sizeclasstable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
# include "../ds/csv.h"
|
||||
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
template<size_t N, size_t LARGE_N>
|
||||
struct AllocStats
|
||||
{
|
||||
constexpr AllocStats() = default;
|
||||
|
||||
struct CurrentMaxPair
|
||||
{
|
||||
size_t current{0};
|
||||
size_t max{0};
|
||||
size_t used{0};
|
||||
|
||||
void inc()
|
||||
{
|
||||
current++;
|
||||
used++;
|
||||
if (current > max)
|
||||
max++;
|
||||
}
|
||||
|
||||
void dec()
|
||||
{
|
||||
// Split stats means this is not true.
|
||||
// TODO reestablish checks, when we sanitise the stats.
|
||||
// SNMALLOC_ASSERT(current > 0);
|
||||
current--;
|
||||
}
|
||||
|
||||
bool is_empty()
|
||||
{
|
||||
return current == 0;
|
||||
}
|
||||
|
||||
bool is_unused()
|
||||
{
|
||||
return max == 0;
|
||||
}
|
||||
|
||||
void add(CurrentMaxPair& that)
|
||||
{
|
||||
current += that.current;
|
||||
max += that.max;
|
||||
used += that.used;
|
||||
}
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
void print(CSVStream& csv, size_t multiplier = 1)
|
||||
{
|
||||
csv << current * multiplier << max * multiplier << used * multiplier;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Stats
|
||||
{
|
||||
constexpr Stats() = default;
|
||||
|
||||
CurrentMaxPair count;
|
||||
CurrentMaxPair slab_count;
|
||||
uint64_t time{0};
|
||||
uint64_t ticks{0};
|
||||
double online_average{0};
|
||||
|
||||
bool is_empty()
|
||||
{
|
||||
return count.is_empty();
|
||||
}
|
||||
|
||||
void add(Stats& that)
|
||||
{
|
||||
count.add(that.count);
|
||||
slab_count.add(that.slab_count);
|
||||
}
|
||||
|
||||
void addToRunningAverage()
|
||||
{
|
||||
uint64_t now = Aal::tick();
|
||||
|
||||
if (slab_count.current != 0)
|
||||
{
|
||||
double occupancy = static_cast<double>(count.current) /
|
||||
static_cast<double>(slab_count.current);
|
||||
uint64_t duration = now - time;
|
||||
|
||||
if (ticks == 0)
|
||||
online_average = occupancy;
|
||||
else
|
||||
online_average +=
|
||||
((occupancy - online_average) * static_cast<double>(duration)) /
|
||||
static_cast<double>(ticks);
|
||||
|
||||
ticks += duration;
|
||||
}
|
||||
|
||||
time = now;
|
||||
}
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
void
|
||||
print(CSVStream& csv, size_t multiplier = 1, size_t slab_multiplier = 1)
|
||||
{
|
||||
// Keep in sync with header lower down
|
||||
count.print(csv, multiplier);
|
||||
slab_count.print(csv, slab_multiplier);
|
||||
size_t average =
|
||||
static_cast<size_t>(online_average * static_cast<double>(multiplier));
|
||||
|
||||
csv << average << (slab_multiplier - average) * slab_count.max
|
||||
<< csv.endl;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
static constexpr size_t BUCKETS_BITS = 4;
|
||||
static constexpr size_t BUCKETS = 1 << BUCKETS_BITS;
|
||||
static constexpr size_t TOTAL_BUCKETS =
|
||||
bits::to_exp_mant_const<BUCKETS_BITS>(
|
||||
bits::one_at_bit(bits::ADDRESS_BITS - 1));
|
||||
|
||||
Stats sizeclass[N];
|
||||
|
||||
size_t large_pop_count[LARGE_N] = {0};
|
||||
size_t large_push_count[LARGE_N] = {0};
|
||||
|
||||
size_t remote_freed = 0;
|
||||
size_t remote_posted = 0;
|
||||
size_t remote_received = 0;
|
||||
size_t superslab_push_count = 0;
|
||||
size_t superslab_pop_count = 0;
|
||||
size_t superslab_fresh_count = 0;
|
||||
size_t segment_count = 0;
|
||||
size_t bucketed_requests[TOTAL_BUCKETS] = {};
|
||||
#endif
|
||||
|
||||
void alloc_request(size_t size)
|
||||
{
|
||||
UNUSED(size);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
auto index = (size == 0) ? 0 : bits::to_exp_mant<BUCKETS_BITS>(size);
|
||||
SNMALLOC_ASSERT(index < TOTAL_BUCKETS);
|
||||
bucketed_requests[index]++;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_empty()
|
||||
{
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
for (size_t i = 0; i < N; i++)
|
||||
{
|
||||
if (!sizeclass[i].is_empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < LARGE_N; i++)
|
||||
{
|
||||
if (large_push_count[i] != large_pop_count[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return (remote_freed == remote_posted);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void sizeclass_alloc(smallsizeclass_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
sizeclass[sc].addToRunningAverage();
|
||||
sizeclass[sc].count.inc();
|
||||
#endif
|
||||
}
|
||||
|
||||
void sizeclass_dealloc(smallsizeclass_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
sizeclass[sc].addToRunningAverage();
|
||||
sizeclass[sc].count.dec();
|
||||
#endif
|
||||
}
|
||||
|
||||
void large_alloc(size_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
SNMALLOC_ASSUME(sc < LARGE_N);
|
||||
large_pop_count[sc]++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void sizeclass_alloc_slab(smallsizeclass_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
sizeclass[sc].addToRunningAverage();
|
||||
sizeclass[sc].slab_count.inc();
|
||||
#endif
|
||||
}
|
||||
|
||||
void sizeclass_dealloc_slab(smallsizeclass_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
sizeclass[sc].addToRunningAverage();
|
||||
sizeclass[sc].slab_count.dec();
|
||||
#endif
|
||||
}
|
||||
|
||||
void large_dealloc(size_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
large_push_count[sc]++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void segment_create()
|
||||
{
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
segment_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void superslab_pop()
|
||||
{
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
superslab_pop_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void superslab_push()
|
||||
{
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
superslab_push_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void superslab_fresh()
|
||||
{
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
superslab_fresh_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void remote_free(smallsizeclass_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
remote_freed += sizeclass_to_size(sc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void remote_post()
|
||||
{
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
remote_posted = remote_freed;
|
||||
#endif
|
||||
}
|
||||
|
||||
void remote_receive(smallsizeclass_t sc)
|
||||
{
|
||||
UNUSED(sc);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
remote_received += sizeclass_to_size(sc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void add(AllocStats<N, LARGE_N>& that)
|
||||
{
|
||||
UNUSED(that);
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
for (size_t i = 0; i < N; i++)
|
||||
sizeclass[i].add(that.sizeclass[i]);
|
||||
|
||||
for (size_t i = 0; i < LARGE_N; i++)
|
||||
{
|
||||
large_push_count[i] += that.large_push_count[i];
|
||||
large_pop_count[i] += that.large_pop_count[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TOTAL_BUCKETS; i++)
|
||||
bucketed_requests[i] += that.bucketed_requests[i];
|
||||
|
||||
remote_freed += that.remote_freed;
|
||||
remote_posted += that.remote_posted;
|
||||
remote_received += that.remote_received;
|
||||
superslab_pop_count += that.superslab_pop_count;
|
||||
superslab_push_count += that.superslab_push_count;
|
||||
superslab_fresh_count += that.superslab_fresh_count;
|
||||
segment_count += that.segment_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
template<class Alloc>
|
||||
void print(std::ostream& o, uint64_t dumpid = 0, uint64_t allocatorid = 0)
|
||||
{
|
||||
UNUSED(o, dumpid, allocatorid);
|
||||
|
||||
CSVStream csv(&o);
|
||||
|
||||
if (dumpid == 0)
|
||||
{
|
||||
// Output headers for initial dump
|
||||
// Keep in sync with data dump
|
||||
csv << "GlobalStats"
|
||||
<< "DumpID"
|
||||
<< "AllocatorID"
|
||||
<< "Remote freed"
|
||||
<< "Remote posted"
|
||||
<< "Remote received"
|
||||
<< "Superslab pop"
|
||||
<< "Superslab push"
|
||||
<< "Superslab fresh"
|
||||
<< "Segments" << csv.endl;
|
||||
|
||||
csv << "BucketedStats"
|
||||
<< "DumpID"
|
||||
<< "AllocatorID"
|
||||
<< "Size group"
|
||||
<< "Size"
|
||||
<< "Current count"
|
||||
<< "Max count"
|
||||
<< "Total Allocs"
|
||||
<< "Current Slab bytes"
|
||||
<< "Max Slab bytes"
|
||||
<< "Total slab allocs"
|
||||
<< "Average Slab Usage"
|
||||
<< "Average wasted space" << csv.endl;
|
||||
|
||||
csv << "LargeBucketedStats"
|
||||
<< "DumpID"
|
||||
<< "AllocatorID"
|
||||
<< "Size group"
|
||||
<< "Size"
|
||||
<< "Push count"
|
||||
<< "Pop count" << csv.endl;
|
||||
|
||||
csv << "AllocSizes"
|
||||
<< "DumpID"
|
||||
<< "AllocatorID"
|
||||
<< "ClassID"
|
||||
<< "Low size"
|
||||
<< "High size"
|
||||
<< "Count" << csv.endl;
|
||||
}
|
||||
|
||||
for (smallsizeclass_t i = 0; i < N; i++)
|
||||
{
|
||||
if (sizeclass[i].count.is_unused())
|
||||
continue;
|
||||
|
||||
sizeclass[i].addToRunningAverage();
|
||||
|
||||
csv << "BucketedStats" << dumpid << allocatorid << i
|
||||
<< sizeclass_to_size(i);
|
||||
|
||||
sizeclass[i].print(csv, sizeclass_to_size(i));
|
||||
}
|
||||
|
||||
// for (uint8_t i = 0; i < LARGE_N; i++)
|
||||
// {
|
||||
// if ((large_push_count[i] == 0) && (large_pop_count[i] == 0))
|
||||
// continue;
|
||||
|
||||
// csv << "LargeBucketedStats" << dumpid << allocatorid << (i + N)
|
||||
// << large_sizeclass_to_size(i) << large_push_count[i]
|
||||
// << large_pop_count[i] << csv.endl;
|
||||
// }
|
||||
|
||||
size_t low = 0;
|
||||
size_t high = 0;
|
||||
|
||||
for (size_t i = 0; i < TOTAL_BUCKETS; i++)
|
||||
{
|
||||
low = high + 1;
|
||||
high = bits::from_exp_mant<BUCKETS_BITS>(i);
|
||||
|
||||
if (bucketed_requests[i] == 0)
|
||||
continue;
|
||||
|
||||
csv << "AllocSizes" << dumpid << allocatorid << i << low << high
|
||||
<< bucketed_requests[i] << csv.endl;
|
||||
}
|
||||
|
||||
csv << "GlobalStats" << dumpid << allocatorid << remote_freed
|
||||
<< remote_posted << remote_received << superslab_pop_count
|
||||
<< superslab_push_count << superslab_fresh_count << segment_count
|
||||
<< csv.endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
void start()
|
||||
{
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
for (size_t i = 0; i < N; i++)
|
||||
sizeclass[i].time = Aal::tick();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Core implementation of snmalloc independent of the configuration mode
|
||||
#include "../snmalloc_core.h"
|
||||
|
||||
#ifndef SNMALLOC_PROVIDE_OWN_CONFIG
|
||||
# include "../backend/globalconfig.h"
|
||||
// The default configuration for snmalloc is used if alternative not defined
|
||||
namespace snmalloc
|
||||
{
|
||||
using Alloc = snmalloc::LocalAllocator<snmalloc::Globals>;
|
||||
} // namespace snmalloc
|
||||
#endif
|
||||
|
||||
// User facing API surface, needs to know what `Alloc` is.
|
||||
#include "../snmalloc_front.h"
|
||||
|
||||
#ifndef SNMALLOC_EXPORT
|
||||
# define SNMALLOC_EXPORT
|
||||
#endif
|
||||
#ifdef SNMALLOC_STATIC_LIBRARY_PREFIX
|
||||
# define __SN_CONCAT(a, b) a##b
|
||||
# define __SN_EVALUATE(a, b) __SN_CONCAT(a, b)
|
||||
# define SNMALLOC_NAME_MANGLE(a) \
|
||||
__SN_EVALUATE(SNMALLOC_STATIC_LIBRARY_PREFIX, a)
|
||||
#elif !defined(SNMALLOC_NAME_MANGLE)
|
||||
# define SNMALLOC_NAME_MANGLE(a) a
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Core implementation of snmalloc independent of the configuration mode
|
||||
#include "snmalloc_core.h"
|
||||
|
||||
// If you define SNMALLOC_PROVIDE_OWN_CONFIG then you must provide your own
|
||||
// definition of `snmalloc::Alloc` and include `snmalloc_front.h` before
|
||||
// including any files that include `snmalloc.h` and consume the global
|
||||
// allocation APIs.
|
||||
#ifndef SNMALLOC_PROVIDE_OWN_CONFIG
|
||||
// Default implementation of global state
|
||||
# include "backend/globalconfig.h"
|
||||
|
||||
// The default configuration for snmalloc
|
||||
namespace snmalloc
|
||||
{
|
||||
using Alloc = snmalloc::LocalAllocator<snmalloc::Globals>;
|
||||
}
|
||||
|
||||
// User facing API surface, needs to know what `Alloc` is.
|
||||
# include "snmalloc_front.h"
|
||||
#endif
|
||||
40
src/snmalloc/README.md
Normal file
40
src/snmalloc/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
Include hierarchy
|
||||
-----------------
|
||||
|
||||
The `snmalloc/` include path contains all of the snmalloc headers.
|
||||
These are arranged in a hierarchy such that each of the directories may include ones below, in the following order, starting at the bottom:
|
||||
|
||||
- `ds_core/` provides core data structures that depend on the C++ implementation and nothing else.
|
||||
This directory includes a number of things that abstract over different language extensions (for example, different built-in function names in different compilers).
|
||||
- `aal/` provides the architecture abstraction layer (AAL).
|
||||
This layer provides abstractions over CPU-specific intrinsics and defines things such as the virtual address-space size.
|
||||
There is a single AAL for an snmalloc instantiation.
|
||||
- `pal/` provides the platform abstraction layer (PAL).
|
||||
This exposes OS- or environment-specific abstractions into the rest of the code.
|
||||
An snmalloc instantiation may use more than one PAL, including ones provided by the user.
|
||||
- `ds/` includes data structures that may depend on platform services or on features specific to the current CPU.
|
||||
- `mem/` provides the core allocator abstractions.
|
||||
The code here is templated over a back-end, which defines a particular embedding of snmalloc.
|
||||
- `backend_helpers/` provides helper classes for use in defining a back end.
|
||||
This includes data structures such as pagemap implementations (efficient maps from a chunk address to associated metadata) and buddy allocators for managing address-space ranges.
|
||||
- `backend/` provides some example implementations for snmalloc embeddings that provide a global memory allocator for an address space.
|
||||
Users may ignore this entirely and use the types in `mem/` with a custom back end to expose an snmalloc instance with specific behaviour.
|
||||
Layers above this can be used with a custom configuration by defining `SNMALLOC_PROVIDE_OWN_CONFIG` and exporting a type as `snmalloc::Alloc` that defines the type of an `snmalloc::LocalAllocator` template specialisation.
|
||||
- `global/` provides some front-end components that assume that snmalloc is available in a global configuration.
|
||||
- `override/` builds on top of `global/` to provide specific implementations with compatibility with external specifications (for example C `malloc`, C++ `operator new`, jemalloc's `*allocx`, or Rust's `std::alloc`).
|
||||
|
||||
Each layer until `backend_helpers/` provides a single header with the same name as the directory.
|
||||
Files in higher layers should depend only on the single-file version.
|
||||
This allows specific files to be moved to a lower layer if appropriate, without too much code churn.
|
||||
|
||||
There is only one exception to this rule: `backend/globalconfig.h`.
|
||||
This file defines either the default configuration *or* nothing, depending on whether the user has defined `SNMALLOC_PROVIDE_OWN_CONFIG`.
|
||||
The layers above the back end should include only this file, so that there is a single interception point for externally defined back ends.
|
||||
|
||||
External code should include only the following files:
|
||||
|
||||
- `snmalloc/snmalloc_core.h` includes everything up to `backend_helpers`.
|
||||
This provides the building blocks required to assemble an snmalloc instance, but does not assume any global configuration.
|
||||
- `snmalloc/snmalloc_front.h` assumes a global configuration (either user-provided or the default from `snmalloc/backend/globalconfig.h` and exposes all of the functionality that depends on both.
|
||||
- `snmalloc/snmalloc.h` is a convenience wrapper that includes both of the above files.
|
||||
- `snmalloc/override/*.cc` can be compiled as-is or included after `snmalloc/snmalloc_core.h` and a custom global allocator definition to provide specific languages' global memory allocator APIs with a custom snmalloc embedding.
|
||||
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* The snmalloc architecture abstraction layer. This defines
|
||||
* CPU-architecture-specific functionality.
|
||||
*
|
||||
* Files in this directory may depend on `ds_core` and each other, but nothing
|
||||
* else in snmalloc.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../ds/concept.h"
|
||||
#include "../ds/defines.h"
|
||||
#include "../ds/ptrwrap.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
#include "aal_concept.h"
|
||||
#include "aal_consts.h"
|
||||
|
||||
@@ -242,10 +247,6 @@ namespace snmalloc
|
||||
constexpr static bool aal_supports = (AAL::aal_features & F) == F;
|
||||
} // namespace snmalloc
|
||||
|
||||
#if defined(_MSC_VER) && defined(SNMALLOC_VA_BITS_32)
|
||||
# include <intsafe.h>
|
||||
#endif
|
||||
|
||||
#ifdef __POINTER_WIDTH__
|
||||
# if ((__POINTER_WIDTH__ == 64) && !defined(SNMALLOC_VA_BITS_64)) || \
|
||||
((__POINTER_WIDTH__ == 32) && !defined(SNMALLOC_VA_BITS_32))
|
||||
@@ -262,3 +263,7 @@ static_assert(sizeof(size_t) == 4);
|
||||
#elif defined(SNMALLOC_VA_BITS_64)
|
||||
static_assert(sizeof(size_t) == 8);
|
||||
#endif
|
||||
|
||||
// Included after the AAL has been defined, depends on the AAL's notion of an
|
||||
// address
|
||||
#include "address.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/defines.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
# include "../ds/concept.h"
|
||||
# include "../ds/ptrwrap.h"
|
||||
# include "../ds_core/ds_core.h"
|
||||
# include "aal_consts.h"
|
||||
|
||||
# include <cstdint>
|
||||
@@ -27,9 +26,12 @@ namespace snmalloc
|
||||
* AALs provide a prefetch operation.
|
||||
*/
|
||||
template<typename AAL>
|
||||
concept ConceptAAL_prefetch = requires(void *ptr)
|
||||
concept ConceptAAL_prefetch = requires(void* ptr)
|
||||
{
|
||||
{ AAL::prefetch(ptr) } noexcept -> ConceptSame<void>;
|
||||
{
|
||||
AAL::prefetch(ptr)
|
||||
}
|
||||
noexcept->ConceptSame<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,29 +40,31 @@ namespace snmalloc
|
||||
template<typename AAL>
|
||||
concept ConceptAAL_tick = requires()
|
||||
{
|
||||
{ AAL::tick() } noexcept -> ConceptSame<uint64_t>;
|
||||
{
|
||||
AAL::tick()
|
||||
}
|
||||
noexcept->ConceptSame<uint64_t>;
|
||||
};
|
||||
|
||||
template<typename AAL>
|
||||
concept ConceptAAL_capptr_methods =
|
||||
requires(capptr::Chunk<void> auth, capptr::AllocFull<void> ret, size_t sz)
|
||||
requires(capptr::Chunk<void> auth, capptr::AllocFull<void> ret, size_t sz)
|
||||
{
|
||||
/**
|
||||
* Produce a pointer with reduced authority from a more privilged pointer.
|
||||
* The resulting pointer will have base at auth's address and length of
|
||||
* exactly sz. auth+sz must not exceed auth's limit.
|
||||
*/
|
||||
{ AAL::template capptr_bound<void, capptr::bounds::Chunk>(auth, sz) }
|
||||
noexcept
|
||||
-> ConceptSame<capptr::Chunk<void>>;
|
||||
{
|
||||
AAL::template capptr_bound<void, capptr::bounds::Chunk>(auth, sz)
|
||||
}
|
||||
noexcept->ConceptSame<capptr::Chunk<void>>;
|
||||
};
|
||||
|
||||
template<typename AAL>
|
||||
concept ConceptAAL =
|
||||
ConceptAAL_static_members<AAL> &&
|
||||
ConceptAAL_prefetch<AAL> &&
|
||||
ConceptAAL_tick<AAL> &&
|
||||
ConceptAAL_capptr_methods<AAL>;
|
||||
ConceptAAL_static_members<AAL>&& ConceptAAL_prefetch<AAL>&&
|
||||
ConceptAAL_tick<AAL>&& ConceptAAL_capptr_methods<AAL>;
|
||||
|
||||
} // namespace snmalloc
|
||||
#endif
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
#include "../pal/pal_consts.h"
|
||||
#include "bits.h"
|
||||
#include "ptrwrap.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
#pragma once
|
||||
#include "../mem/allocconfig.h"
|
||||
#include "../mem/metadata.h"
|
||||
#include "../pal/pal.h"
|
||||
#include "commitrange.h"
|
||||
#include "commonconfig.h"
|
||||
#include "empty_range.h"
|
||||
#include "globalrange.h"
|
||||
#include "largebuddyrange.h"
|
||||
#include "pagemap.h"
|
||||
#include "pagemapregisterrange.h"
|
||||
#include "palrange.h"
|
||||
#include "range_helpers.h"
|
||||
#include "smallbuddyrange.h"
|
||||
#include "statsrange.h"
|
||||
#include "subrange.h"
|
||||
#include "../backend_helpers/backend_helpers.h"
|
||||
|
||||
#if defined(SNMALLOC_CHECK_CLIENT) && !defined(OPEN_ENCLAVE)
|
||||
/**
|
||||
@@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../backend/backend.h"
|
||||
#include "../mem/corealloc.h"
|
||||
#include "../mem/pool.h"
|
||||
#include "commonconfig.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -1,19 +1,17 @@
|
||||
#pragma once
|
||||
// If you define SNMALLOC_PROVIDE_OWN_CONFIG then you must provide your own
|
||||
// definition of `snmalloc::Alloc` before including any files that include
|
||||
// `snmalloc.h` or consume the global allocation APIs.
|
||||
#ifndef SNMALLOC_PROVIDE_OWN_CONFIG
|
||||
|
||||
#include "../backend/backend.h"
|
||||
#include "../mem/corealloc.h"
|
||||
#include "../mem/pool.h"
|
||||
#include "commonconfig.h"
|
||||
# include "../backend/backend.h"
|
||||
|
||||
#ifdef SNMALLOC_TRACING
|
||||
# include <iostream>
|
||||
#endif
|
||||
namespace snmalloc
|
||||
{
|
||||
// Forward reference to thread local cleanup.
|
||||
void register_clean_up();
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
# ifdef USE_SNMALLOC_STATS
|
||||
inline static void print_stats()
|
||||
{
|
||||
printf("No Stats yet!");
|
||||
@@ -21,7 +19,7 @@ namespace snmalloc
|
||||
// current_alloc_pool()->aggregate_stats(s);
|
||||
// s.print<Alloc>(std::cout);
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
/**
|
||||
* The default configuration for a global snmalloc. This allocates memory
|
||||
@@ -59,9 +57,9 @@ namespace snmalloc
|
||||
static void ensure_init()
|
||||
{
|
||||
FlagLock lock{initialisation_lock};
|
||||
#ifdef SNMALLOC_TRACING
|
||||
# ifdef SNMALLOC_TRACING
|
||||
message<1024>("Run init_impl");
|
||||
#endif
|
||||
# endif
|
||||
|
||||
if (initialised)
|
||||
return;
|
||||
@@ -74,9 +72,9 @@ namespace snmalloc
|
||||
// Need to initialise pagemap.
|
||||
Backend::init();
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
# ifdef USE_SNMALLOC_STATS
|
||||
atexit(snmalloc::print_stats);
|
||||
#endif
|
||||
# endif
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
@@ -96,3 +94,10 @@ namespace snmalloc
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
|
||||
// The default configuration for snmalloc
|
||||
namespace snmalloc
|
||||
{
|
||||
using Alloc = snmalloc::LocalAllocator<snmalloc::Globals>;
|
||||
} // namespace snmalloc
|
||||
#endif
|
||||
14
src/snmalloc/backend_helpers/backend_helpers.h
Normal file
14
src/snmalloc/backend_helpers/backend_helpers.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "../mem/mem.h"
|
||||
#include "buddy.h"
|
||||
#include "commitrange.h"
|
||||
#include "commonconfig.h"
|
||||
#include "empty_range.h"
|
||||
#include "globalrange.h"
|
||||
#include "largebuddyrange.h"
|
||||
#include "pagemap.h"
|
||||
#include "pagemapregisterrange.h"
|
||||
#include "palrange.h"
|
||||
#include "range_helpers.h"
|
||||
#include "smallbuddyrange.h"
|
||||
#include "statsrange.h"
|
||||
#include "subrange.h"
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/address.h"
|
||||
#include "../ds/bits.h"
|
||||
#include "../ds/redblacktree.h"
|
||||
#include "../ds/ds.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -119,4 +117,4 @@ namespace snmalloc
|
||||
return bigger;
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
} // namespace snmalloc
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/ptrwrap.h"
|
||||
#include "../pal/pal_consts.h"
|
||||
#include "../pal/pal.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../backend/backend_concept.h"
|
||||
#include "../ds/defines.h"
|
||||
#include "../mem/remoteallocator.h"
|
||||
#include "../mem/mem.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -108,75 +106,5 @@ namespace snmalloc
|
||||
inline static RemoteAllocator unused_remote;
|
||||
};
|
||||
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` implements `is_initialised`. Calls
|
||||
* it if it exists.
|
||||
*/
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH auto call_is_initialised(T*, int)
|
||||
-> decltype(T::is_initialised())
|
||||
{
|
||||
return T::is_initialised();
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` does not implement `is_initialised`.
|
||||
* Unconditionally returns true if invoked.
|
||||
*/
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH auto call_is_initialised(T*, long)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* SFINAE helper, calls capptr_domesticate in the backend if it exists.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendDomestication) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState* ls, CapPtr<T, B> p, int)
|
||||
-> decltype(Backend::capptr_domesticate(ls, p))
|
||||
{
|
||||
return Backend::capptr_domesticate(ls, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. If the back end does not provide special handling for
|
||||
* domestication then assume all wild pointers can be domesticated.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendGlobals) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState*, CapPtr<T, B> p, long)
|
||||
{
|
||||
return CapPtr<
|
||||
T,
|
||||
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>(
|
||||
p.unsafe_ptr());
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Wrapper that calls `Backend::capptr_domesticate` if and only if it is
|
||||
* implemented. If it is not implemented then this assumes that any wild
|
||||
* pointer can be domesticated.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendGlobals) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState* ls, CapPtr<T, B> p)
|
||||
{
|
||||
return detail::capptr_domesticate<Backend>(ls, p, 0);
|
||||
}
|
||||
|
||||
} // namespace snmalloc
|
||||
#include "../mem/remotecache.h"
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "../ds/ptrwrap.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/defines.h"
|
||||
#include "../ds/helpers.h"
|
||||
#include "../ds/ptrwrap.h"
|
||||
#include "../ds/ds.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -53,4 +51,4 @@ namespace snmalloc
|
||||
parent->dealloc_range(base, size);
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
} // namespace snmalloc
|
||||
@@ -1,10 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/address.h"
|
||||
#include "../ds/bits.h"
|
||||
#include "../mem/allocconfig.h"
|
||||
#include "../pal/pal.h"
|
||||
#include "backend_concept.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "../mem/mem.h"
|
||||
#include "buddy.h"
|
||||
#include "range_helpers.h"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../ds/helpers.h"
|
||||
#include "../mem/entropy.h"
|
||||
#include "../pal/pal.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "../mem/mem.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/address.h"
|
||||
#include "../pal/pal.h"
|
||||
|
||||
namespace snmalloc
|
||||
@@ -42,4 +41,4 @@ namespace snmalloc
|
||||
return base;
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
} // namespace snmalloc
|
||||
@@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include "../ds/address.h"
|
||||
#include "../pal/pal.h"
|
||||
|
||||
namespace snmalloc
|
||||
@@ -61,4 +60,4 @@ namespace snmalloc
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
} // namespace snmalloc
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/ptrwrap.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -34,4 +34,4 @@ namespace snmalloc
|
||||
length -= align;
|
||||
}
|
||||
}
|
||||
} // namespace snmalloc
|
||||
} // namespace snmalloc
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/address.h"
|
||||
#include "../mem/allocconfig.h"
|
||||
#include "../pal/pal.h"
|
||||
#include "range_helpers.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "../mem/entropy.h"
|
||||
#include "../mem/mem.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -54,4 +54,4 @@ namespace snmalloc
|
||||
return pointer_offset(overblock, offset);
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
} // namespace snmalloc
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits.h"
|
||||
#include "ptrwrap.h"
|
||||
#include "../aal/aal.h"
|
||||
|
||||
/**
|
||||
* This file contains an abstraction of ABA protection. This API should be
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../pal/pal.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
// 0 intermediate bits results in power of 2 small allocs. 1 intermediate
|
||||
11
src/snmalloc/ds/ds.h
Normal file
11
src/snmalloc/ds/ds.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data structures used by snmalloc.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "../pal/pal.h"
|
||||
#include "aba.h"
|
||||
#include "allocconfig.h"
|
||||
#include "flaglock.h"
|
||||
#include "mpmcstack.h"
|
||||
#include "singleton.h"
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits.h"
|
||||
#include "../aal/aal.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds_core/ds_core.h"
|
||||
#include "aba.h"
|
||||
#include "ptrwrap.h"
|
||||
#include "allocconfig.h"
|
||||
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(thread_sanitizer)
|
||||
51
src/snmalloc/ds/singleton.h
Normal file
51
src/snmalloc/ds/singleton.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds_core/ds_core.h"
|
||||
#include "flaglock.h"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/*
|
||||
* In some use cases we need to run before any of the C++ runtime has been
|
||||
* initialised. This singleton class is designed to not depend on the
|
||||
* runtime.
|
||||
*/
|
||||
template<class Object, void init(Object*) noexcept>
|
||||
class Singleton
|
||||
{
|
||||
inline static FlagWord flag;
|
||||
inline static std::atomic<bool> initialised{false};
|
||||
inline static Object obj;
|
||||
|
||||
public:
|
||||
/**
|
||||
* If argument is non-null, then it is assigned the value
|
||||
* true, if this is the first call to get.
|
||||
* At most one call will be first.
|
||||
*/
|
||||
inline SNMALLOC_SLOW_PATH static Object& get(bool* first = nullptr)
|
||||
{
|
||||
// If defined should be initially false;
|
||||
SNMALLOC_ASSERT(first == nullptr || *first == false);
|
||||
|
||||
if (SNMALLOC_UNLIKELY(!initialised.load(std::memory_order_acquire)))
|
||||
{
|
||||
FlagLock lock(flag);
|
||||
if (!initialised)
|
||||
{
|
||||
init(&obj);
|
||||
initialised.store(true, std::memory_order_release);
|
||||
if (first != nullptr)
|
||||
*first = true;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace snmalloc
|
||||
@@ -5,13 +5,16 @@
|
||||
|
||||
// #define USE_LZCNT
|
||||
|
||||
#include "../aal/aal.h"
|
||||
#include "../pal/pal_consts.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#if defined(_MSC_VER)
|
||||
# include <intsafe.h>
|
||||
#endif
|
||||
|
||||
#ifdef pause
|
||||
# undef pause
|
||||
#endif
|
||||
@@ -30,7 +33,16 @@ namespace snmalloc
|
||||
|
||||
namespace bits
|
||||
{
|
||||
static constexpr size_t BITS = Aal::bits;
|
||||
/**
|
||||
* The number of bits in a `size_t`. Many of the functions in the
|
||||
* `snmalloc::bits` namespace are defined to operate over `size_t`, mapping
|
||||
* to the correct compiler builtins irrespective of the size. This size
|
||||
* does *not* imply the number of bits of virtual address space that are
|
||||
* actually allowed to be set. `Aal::bits` provides an
|
||||
* architecture-specific definition of the number of bits of address space
|
||||
* that exist.
|
||||
*/
|
||||
static constexpr size_t BITS = sizeof(size_t) * CHAR_BIT;
|
||||
|
||||
/**
|
||||
* Returns a value of type T that has a single bit set,
|
||||
@@ -52,7 +64,7 @@ namespace snmalloc
|
||||
SNMALLOC_ASSERT(x != 0); // Calling with 0 is UB on some implementations
|
||||
#if defined(_MSC_VER)
|
||||
# ifdef USE_LZCNT
|
||||
# ifdef SNMALLOC_VA_BITS_64
|
||||
# ifdef _WIN64
|
||||
return __lzcnt64(x);
|
||||
# else
|
||||
return __lzcnt((uint32_t)x);
|
||||
@@ -60,10 +72,10 @@ namespace snmalloc
|
||||
# else
|
||||
unsigned long index;
|
||||
|
||||
# ifdef SNMALLOC_VA_BITS_64
|
||||
_BitScanReverse64(&index, x);
|
||||
# ifdef _WIN64
|
||||
_BitScanReverse64(&index, static_cast<unsigned __int64>(x));
|
||||
# else
|
||||
_BitScanReverse(&index, (unsigned long)x);
|
||||
_BitScanReverse(&index, static_cast<unsigned long>(x));
|
||||
# endif
|
||||
|
||||
return BITS - index - 1;
|
||||
@@ -101,10 +113,10 @@ namespace snmalloc
|
||||
inline size_t rotr(size_t x, size_t n)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
# ifdef SNMALLOC_VA_BITS_64
|
||||
return _rotr64(x, (int)n);
|
||||
# ifdef _WIN64
|
||||
return _rotr64(static_cast<unsigned __int64>(x), static_cast<int>(n));
|
||||
# else
|
||||
return _rotr((uint32_t)x, (int)n);
|
||||
return _rotr(static_cast<unsigned int>(x), static_cast<int>(n));
|
||||
# endif
|
||||
#else
|
||||
return rotr_const(x, n);
|
||||
@@ -114,10 +126,10 @@ namespace snmalloc
|
||||
inline size_t rotl(size_t x, size_t n)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
# ifdef SNMALLOC_VA_BITS_64
|
||||
return _rotl64(x, (int)n);
|
||||
# ifdef _WIN64
|
||||
return _rotl64(static_cast<unsigned __int64>(x), static_cast<int>(n));
|
||||
# else
|
||||
return _rotl((uint32_t)x, (int)n);
|
||||
return _rotl(static_cast<unsigned int>(x), static_cast<int>(n));
|
||||
# endif
|
||||
#else
|
||||
return rotl_const(x, n);
|
||||
@@ -145,11 +157,11 @@ namespace snmalloc
|
||||
{
|
||||
SNMALLOC_ASSERT(x != 0); // Calling with 0 is UB on some implementations
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# ifdef SNMALLOC_VA_BITS_64
|
||||
return _tzcnt_u64(x);
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# ifdef _WIN64
|
||||
return _tzcnt_u64(static_cast<unsigned __int64>(x));
|
||||
# else
|
||||
return _tzcnt_u32((uint32_t)x);
|
||||
return _tzcnt_u32(static_cast<unsigned int>(x));
|
||||
# endif
|
||||
#else
|
||||
if constexpr (std::is_same_v<unsigned long, std::size_t>)
|
||||
@@ -191,14 +203,14 @@ namespace snmalloc
|
||||
overflow = __builtin_mul_overflow(x, y, &prod);
|
||||
return prod;
|
||||
#elif defined(_MSC_VER)
|
||||
# if defined(SNMALLOC_VA_BITS_64)
|
||||
# ifdef _WIN64
|
||||
size_t high_prod;
|
||||
size_t prod = _umul128(x, y, &high_prod);
|
||||
overflow = high_prod != 0;
|
||||
return prod;
|
||||
# else
|
||||
size_t prod;
|
||||
overflow = S_OK != UIntMult(x, y, &prod);
|
||||
UINT prod;
|
||||
overflow = S_OK != UIntMult(UINT(x), UINT(y), &prod);
|
||||
return prod;
|
||||
# endif
|
||||
#else
|
||||
16
src/snmalloc/ds_core/ds_core.h
Normal file
16
src/snmalloc/ds_core/ds_core.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
/**
|
||||
* The core definitions for snmalloc. These provide some basic helpers that do
|
||||
* not depend on anything except for a working C++ implementation.
|
||||
*
|
||||
* Files in this directory may not include anything from any other directory in
|
||||
* snmalloc.
|
||||
*/
|
||||
|
||||
#include "bits.h"
|
||||
#include "concept.h"
|
||||
#include "defines.h"
|
||||
#include "helpers.h"
|
||||
#include "ptrwrap.h"
|
||||
#include "redblacktree.h"
|
||||
#include "seqset.h"
|
||||
@@ -1,53 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits.h"
|
||||
#include "flaglock.h"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/*
|
||||
* In some use cases we need to run before any of the C++ runtime has been
|
||||
* initialised. This singleton class is designed to not depend on the
|
||||
* runtime.
|
||||
*/
|
||||
template<class Object, void init(Object*) noexcept>
|
||||
class Singleton
|
||||
{
|
||||
inline static FlagWord flag;
|
||||
inline static std::atomic<bool> initialised{false};
|
||||
inline static Object obj;
|
||||
|
||||
public:
|
||||
/**
|
||||
* If argument is non-null, then it is assigned the value
|
||||
* true, if this is the first call to get.
|
||||
* At most one call will be first.
|
||||
*/
|
||||
inline SNMALLOC_SLOW_PATH static Object& get(bool* first = nullptr)
|
||||
{
|
||||
// If defined should be initially false;
|
||||
SNMALLOC_ASSERT(first == nullptr || *first == false);
|
||||
|
||||
if (SNMALLOC_UNLIKELY(!initialised.load(std::memory_order_acquire)))
|
||||
{
|
||||
FlagLock lock(flag);
|
||||
if (!initialised)
|
||||
{
|
||||
init(&obj);
|
||||
initialised.store(true, std::memory_order_release);
|
||||
if (first != nullptr)
|
||||
*first = true;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper for wrapping values.
|
||||
*
|
||||
@@ -477,4 +439,5 @@ namespace snmalloc
|
||||
*/
|
||||
struct Empty
|
||||
{};
|
||||
|
||||
} // namespace snmalloc
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/concept.h"
|
||||
#include "../ds/defines.h"
|
||||
#include "concept.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#pragma once
|
||||
#include "../pal/pal.h"
|
||||
#include "concept.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "address.h"
|
||||
#include "defines.h"
|
||||
#include "ptrwrap.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "../snmalloc.h"
|
||||
#include "threadalloc.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -107,4 +107,4 @@ namespace snmalloc
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace snmalloc
|
||||
4
src/snmalloc/global/global.h
Normal file
4
src/snmalloc/global/global.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "bounds_checks.h"
|
||||
#include "memcpy.h"
|
||||
#include "scopedalloc.h"
|
||||
#include "threadalloc.h"
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "../mem/bounds_checks.h"
|
||||
#include "../backend/globalconfig.h"
|
||||
#include "bounds_checks.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -328,4 +329,4 @@ namespace snmalloc
|
||||
Arch::copy(dst, src, len);
|
||||
return orig_dst;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace snmalloc
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "../backend/globalconfig.h"
|
||||
|
||||
/**
|
||||
* This header requires that Alloc has been defined.
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/helpers.h"
|
||||
#include "localalloc.h"
|
||||
#include "../backend/globalconfig.h"
|
||||
|
||||
#if defined(SNMALLOC_EXTERNAL_THREAD_ALLOC)
|
||||
# define SNMALLOC_THREAD_TEARDOWN_DEFINED
|
||||
@@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
# include "../ds/address.h"
|
||||
# include "../ds/concept.h"
|
||||
# include "../pal/pal_concept.h"
|
||||
# include "../ds/ds.h"
|
||||
|
||||
# include <cstddef>
|
||||
namespace snmalloc
|
||||
85
src/snmalloc/mem/backend_wrappers.h
Normal file
85
src/snmalloc/mem/backend_wrappers.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
/**
|
||||
* Several of the functions provided by the back end are optional. This file
|
||||
* contains helpers that are templated on a back end and either call the
|
||||
* corresponding function or do nothing. This allows the rest of the front end
|
||||
* to assume that these functions always exist and avoid the need for `if
|
||||
* constexpr` clauses everywhere. The no-op versions are always inlined and so
|
||||
* will be optimised away.
|
||||
*/
|
||||
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` implements `is_initialised`. Calls
|
||||
* it if it exists.
|
||||
*/
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH auto call_is_initialised(T*, int)
|
||||
-> decltype(T::is_initialised())
|
||||
{
|
||||
return T::is_initialised();
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` does not implement `is_initialised`.
|
||||
* Unconditionally returns true if invoked.
|
||||
*/
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH auto call_is_initialised(T*, long)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* SFINAE helper, calls capptr_domesticate in the backend if it exists.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendDomestication) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState* ls, CapPtr<T, B> p, int)
|
||||
-> decltype(Backend::capptr_domesticate(ls, p))
|
||||
{
|
||||
return Backend::capptr_domesticate(ls, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. If the back end does not provide special handling for
|
||||
* domestication then assume all wild pointers can be domesticated.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendGlobals) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState*, CapPtr<T, B> p, long)
|
||||
{
|
||||
return CapPtr<
|
||||
T,
|
||||
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>(
|
||||
p.unsafe_ptr());
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Wrapper that calls `Backend::capptr_domesticate` if and only if it is
|
||||
* implemented. If it is not implemented then this assumes that any wild
|
||||
* pointer can be domesticated.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendGlobals) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState* ls, CapPtr<T, B> p)
|
||||
{
|
||||
return detail::capptr_domesticate<Backend>(ls, p, 0);
|
||||
}
|
||||
|
||||
} // namespace snmalloc
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/defines.h"
|
||||
#include "allocconfig.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "localcache.h"
|
||||
#include "metadata.h"
|
||||
#include "pool.h"
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/address.h"
|
||||
#include "../pal/pal.h"
|
||||
|
||||
#include <cstdint>
|
||||
@@ -33,8 +33,7 @@
|
||||
* and randomly deciding which list to add an element to.
|
||||
*/
|
||||
|
||||
#include "../ds/address.h"
|
||||
#include "allocconfig.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "entropy.h"
|
||||
|
||||
#include <cstdint>
|
||||
@@ -1,53 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/helpers.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
#include "localalloc.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
template<SNMALLOC_CONCEPT(ConceptBackendGlobals) SharedStateHandle>
|
||||
inline static void aggregate_stats(Stats& stats)
|
||||
{
|
||||
static_assert(
|
||||
SharedStateHandle::Options.CoreAllocIsPoolAllocated,
|
||||
"Global statistics are available only for pool-allocated configurations");
|
||||
auto* alloc = AllocPool<SharedStateHandle>::iterate();
|
||||
|
||||
while (alloc != nullptr)
|
||||
{
|
||||
auto a = alloc->attached_stats();
|
||||
if (a != nullptr)
|
||||
stats.add(*a);
|
||||
stats.add(alloc->stats());
|
||||
alloc = AllocPool<SharedStateHandle>::iterate(alloc);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_SNMALLOC_STATS
|
||||
template<SNMALLOC_CONCEPT(ConceptBackendGlobals) SharedStateHandle>
|
||||
inline static void print_all_stats(std::ostream& o, uint64_t dumpid = 0)
|
||||
{
|
||||
static_assert(
|
||||
SharedStateHandle::Options.CoreAllocIsPoolAllocated,
|
||||
"Global statistics are available only for pool-allocated configurations");
|
||||
auto alloc = AllocPool<SharedStateHandle>::iterate();
|
||||
|
||||
while (alloc != nullptr)
|
||||
{
|
||||
auto stats = alloc->stats();
|
||||
if (stats != nullptr)
|
||||
stats->template print<decltype(alloc)>(o, dumpid, alloc->id());
|
||||
alloc = AllocPool<SharedStateHandle>::iterate(alloc);
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<SNMALLOC_CONCEPT(ConceptBackendGlobals) SharedStateHandle>
|
||||
inline static void print_all_stats(void*& o, uint64_t dumpid = 0)
|
||||
{
|
||||
UNUSED(o, dumpid);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<SNMALLOC_CONCEPT(ConceptBackendGlobals) SharedStateHandle>
|
||||
inline static void cleanup_unused()
|
||||
{
|
||||
@@ -6,7 +6,7 @@
|
||||
# define ALLOCATOR
|
||||
#endif
|
||||
|
||||
#include "../ds/ptrwrap.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "corealloc.h"
|
||||
#include "freelist.h"
|
||||
#include "localcache.h"
|
||||
@@ -18,9 +18,6 @@
|
||||
# include "external_alloc.h"
|
||||
#endif
|
||||
|
||||
#ifdef SNMALLOC_TRACING
|
||||
# include <iostream>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
namespace snmalloc
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/ptrwrap.h"
|
||||
#include "allocstats.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "freelist.h"
|
||||
#include "remotecache.h"
|
||||
#include "sizeclasstable.h"
|
||||
@@ -10,8 +9,6 @@
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
using Stats = AllocStats<NUM_SMALL_SIZECLASSES, NUM_LARGE_CLASSES>;
|
||||
|
||||
inline static SNMALLOC_FAST_PATH capptr::Alloc<void>
|
||||
finish_alloc_no_zero(freelist::HeadPtr p, smallsizeclass_t sizeclass)
|
||||
{
|
||||
@@ -51,10 +48,6 @@ namespace snmalloc
|
||||
// This is the entropy for a particular thread.
|
||||
LocalEntropy entropy;
|
||||
|
||||
// TODO: Minimal stats object for just the stats on this datastructure.
|
||||
// This will be a zero-size structure if stats are not enabled.
|
||||
Stats stats;
|
||||
|
||||
// Pointer to the remote allocator message_queue, used to check
|
||||
// if a deallocation is local.
|
||||
RemoteAllocator* remote_allocator;
|
||||
@@ -111,8 +104,6 @@ namespace snmalloc
|
||||
{
|
||||
auto& key = entropy.get_free_list_key();
|
||||
smallsizeclass_t sizeclass = size_to_sizeclass(size);
|
||||
stats.alloc_request(size);
|
||||
stats.sizeclass_alloc(sizeclass);
|
||||
auto& fl = small_fast_free_lists[sizeclass];
|
||||
if (SNMALLOC_LIKELY(!fl.empty()))
|
||||
{
|
||||
16
src/snmalloc/mem/mem.h
Normal file
16
src/snmalloc/mem/mem.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "backend_concept.h"
|
||||
#include "backend_wrappers.h"
|
||||
#include "corealloc.h"
|
||||
#include "entropy.h"
|
||||
#include "external_alloc.h"
|
||||
#include "freelist.h"
|
||||
#include "globalalloc.h"
|
||||
#include "localalloc.h"
|
||||
#include "localcache.h"
|
||||
#include "metadata.h"
|
||||
#include "pool.h"
|
||||
#include "pooled.h"
|
||||
#include "remoteallocator.h"
|
||||
#include "remotecache.h"
|
||||
#include "sizeclasstable.h"
|
||||
#include "ticker.h"
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../backend/backend_concept.h"
|
||||
#include "../ds/helpers.h"
|
||||
#include "../ds/seqset.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "freelist.h"
|
||||
#include "sizeclasstable.h"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/flaglock.h"
|
||||
#include "../ds/mpmcstack.h"
|
||||
#include "../pal/pal_concept.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "pooled.h"
|
||||
|
||||
#include <new>
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "backend_concept.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "../mem/allocconfig.h"
|
||||
#include "../mem/freelist.h"
|
||||
#include "../mem/metadata.h"
|
||||
#include "../mem/sizeclasstable.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "freelist.h"
|
||||
#include "metadata.h"
|
||||
#include "sizeclasstable.h"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "allocconfig.h"
|
||||
#include "../ds/ds.h"
|
||||
#include "backend_wrappers.h"
|
||||
#include "freelist.h"
|
||||
#include "metadata.h"
|
||||
#include "remoteallocator.h"
|
||||
@@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../ds/defines.h"
|
||||
#include "../ds/helpers.h"
|
||||
#include "allocconfig.h"
|
||||
#include "../ds/ds.h"
|
||||
|
||||
/**
|
||||
* This file contains all the code for transforming transforming sizes to
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/defines.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "mem/memcpy.h"
|
||||
|
||||
#include "override.h"
|
||||
|
||||
extern "C"
|
||||
15
src/snmalloc/override/override.h
Normal file
15
src/snmalloc/override/override.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "../global/global.h"
|
||||
|
||||
#ifndef SNMALLOC_EXPORT
|
||||
# define SNMALLOC_EXPORT
|
||||
#endif
|
||||
#ifdef SNMALLOC_STATIC_LIBRARY_PREFIX
|
||||
# define __SN_CONCAT(a, b) a##b
|
||||
# define __SN_EVALUATE(a, b) __SN_CONCAT(a, b)
|
||||
# define SNMALLOC_NAME_MANGLE(a) \
|
||||
__SN_EVALUATE(SNMALLOC_STATIC_LIBRARY_PREFIX, a)
|
||||
#elif !defined(SNMALLOC_NAME_MANGLE)
|
||||
# define SNMALLOC_NAME_MANGLE(a) a
|
||||
#endif
|
||||
@@ -1,10 +1,22 @@
|
||||
/**
|
||||
* The platform abstraction layer. This defines an abstraction that exposes
|
||||
* services from the operating system or any equivalent environment.
|
||||
*
|
||||
* It is possible to have multiple PALs in a single snmalloc instance. For
|
||||
* example, one may provide the base operating system functionality, another
|
||||
* may hide some of this or provide its own abstractions for sandboxing or
|
||||
* isolating heaps.
|
||||
*
|
||||
* Files in this directory may depend on the architecture abstraction and core
|
||||
* layers (`aal` and `ds_core`, respectively) but nothing else in snmalloc.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../ds/concept.h"
|
||||
#include "../aal/aal.h"
|
||||
#include "pal_concept.h"
|
||||
#include "pal_consts.h"
|
||||
|
||||
// If simultating OE, then we need the underlying platform
|
||||
// If simulating OE, then we need the underlying platform
|
||||
#if defined(OPEN_ENCLAVE)
|
||||
# include "pal_open_enclave.h"
|
||||
#endif
|
||||
@@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
# include "../ds/concept.h"
|
||||
# include "pal_consts.h"
|
||||
# include "pal_ds.h"
|
||||
|
||||
# include <utility>
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
|
||||
/*
|
||||
* These concepts enforce that these are indeed constants that fit in the
|
||||
* desired types. (This is subtly different from saying that they are the
|
||||
@@ -41,7 +40,10 @@ namespace snmalloc
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_error = requires(const char* const str)
|
||||
{
|
||||
{ PAL::error(str) } -> ConceptSame<void>;
|
||||
{
|
||||
PAL::error(str)
|
||||
}
|
||||
->ConceptSame<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -50,25 +52,40 @@ namespace snmalloc
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_memops = requires(void* vp, std::size_t sz)
|
||||
{
|
||||
{ PAL::notify_not_using(vp, sz) } noexcept -> ConceptSame<void>;
|
||||
{
|
||||
PAL::notify_not_using(vp, sz)
|
||||
}
|
||||
noexcept->ConceptSame<void>;
|
||||
|
||||
{ PAL::template notify_using<NoZero>(vp, sz) } noexcept
|
||||
-> ConceptSame<void>;
|
||||
{ PAL::template notify_using<YesZero>(vp, sz) } noexcept
|
||||
-> ConceptSame<void>;
|
||||
{
|
||||
PAL::template notify_using<NoZero>(vp, sz)
|
||||
}
|
||||
noexcept->ConceptSame<void>;
|
||||
{
|
||||
PAL::template notify_using<YesZero>(vp, sz)
|
||||
}
|
||||
noexcept->ConceptSame<void>;
|
||||
|
||||
{ PAL::template zero<false>(vp, sz) } noexcept -> ConceptSame<void>;
|
||||
{ PAL::template zero<true>(vp, sz) } noexcept -> ConceptSame<void>;
|
||||
{
|
||||
PAL::template zero<false>(vp, sz)
|
||||
}
|
||||
noexcept->ConceptSame<void>;
|
||||
{
|
||||
PAL::template zero<true>(vp, sz)
|
||||
}
|
||||
noexcept->ConceptSame<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Absent any feature flags, the PAL must support a crude primitive allocator
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_reserve =
|
||||
requires(PAL p, std::size_t sz)
|
||||
concept ConceptPAL_reserve = requires(PAL p, std::size_t sz)
|
||||
{
|
||||
{ PAL::reserve(sz) } noexcept -> ConceptSame<void*>;
|
||||
{
|
||||
PAL::reserve(sz)
|
||||
}
|
||||
noexcept->ConceptSame<void*>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -77,9 +94,14 @@ namespace snmalloc
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_reserve_aligned = requires(std::size_t sz)
|
||||
{
|
||||
{ PAL::template reserve_aligned<true>(sz) } noexcept -> ConceptSame<void*>;
|
||||
{ PAL::template reserve_aligned<false>(sz) } noexcept
|
||||
-> ConceptSame<void*>;
|
||||
{
|
||||
PAL::template reserve_aligned<true>(sz)
|
||||
}
|
||||
noexcept->ConceptSame<void*>;
|
||||
{
|
||||
PAL::template reserve_aligned<false>(sz)
|
||||
}
|
||||
noexcept->ConceptSame<void*>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -88,14 +110,23 @@ namespace snmalloc
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_mem_low_notify = requires(PalNotificationObject* pno)
|
||||
{
|
||||
{ PAL::expensive_low_memory_check() } -> ConceptSame<bool>;
|
||||
{ PAL::register_for_low_memory_callback(pno) } -> ConceptSame<void>;
|
||||
{
|
||||
PAL::expensive_low_memory_check()
|
||||
}
|
||||
->ConceptSame<bool>;
|
||||
{
|
||||
PAL::register_for_low_memory_callback(pno)
|
||||
}
|
||||
->ConceptSame<void>;
|
||||
};
|
||||
|
||||
template<typename PAL>
|
||||
concept ConceptPAL_get_entropy64 = requires()
|
||||
{
|
||||
{ PAL::get_entropy64() } -> ConceptSame<uint64_t>;
|
||||
{
|
||||
PAL::get_entropy64()
|
||||
}
|
||||
->ConceptSame<uint64_t>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -105,21 +136,17 @@ namespace snmalloc
|
||||
* are, naturally, not bound by the corresponding concept.
|
||||
*/
|
||||
template<typename PAL>
|
||||
concept ConceptPAL =
|
||||
ConceptPAL_static_features<PAL> &&
|
||||
ConceptPAL_static_sizes<PAL> &&
|
||||
ConceptPAL_error<PAL> &&
|
||||
ConceptPAL_memops<PAL> &&
|
||||
concept ConceptPAL = ConceptPAL_static_features<PAL>&&
|
||||
ConceptPAL_static_sizes<PAL>&& ConceptPAL_error<PAL>&&
|
||||
ConceptPAL_memops<PAL> &&
|
||||
(!pal_supports<Entropy, PAL> ||
|
||||
ConceptPAL_get_entropy64<PAL>) &&
|
||||
(!pal_supports<LowMemoryNotification, PAL> ||
|
||||
ConceptPAL_mem_low_notify<PAL>) &&
|
||||
(pal_supports<NoAllocation, PAL> ||
|
||||
(
|
||||
(!pal_supports<AlignedAllocation, PAL> ||
|
||||
ConceptPAL_reserve_aligned<PAL>) &&
|
||||
ConceptPAL_reserve<PAL>)
|
||||
);
|
||||
ConceptPAL_get_entropy64<
|
||||
PAL>)&&(!pal_supports<LowMemoryNotification, PAL> ||
|
||||
ConceptPAL_mem_low_notify<
|
||||
PAL>)&&(pal_supports<NoAllocation, PAL> ||
|
||||
((!pal_supports<AlignedAllocation, PAL> ||
|
||||
ConceptPAL_reserve_aligned<
|
||||
PAL>)&&ConceptPAL_reserve<PAL>));
|
||||
|
||||
} // namespace snmalloc
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/defines.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/defines.h"
|
||||
#include "../ds/helpers.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
|
||||
#if defined(FreeBSD_KERNEL)
|
||||
extern "C"
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__linux__)
|
||||
# include "../ds/bits.h"
|
||||
# include "../ds_core/ds_core.h"
|
||||
# include "pal_posix.h"
|
||||
|
||||
# include <string.h>
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../ds_core/ds_core.h"
|
||||
#include "pal_timer_default.h"
|
||||
|
||||
namespace snmalloc
|
||||
@@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SNMALLOC_TRACING
|
||||
# include <iostream>
|
||||
#endif
|
||||
#include "../ds/address.h"
|
||||
#include "../aal/aal.h"
|
||||
#include "pal_timer_default.h"
|
||||
#if defined(SNMALLOC_BACKTRACE_HEADER)
|
||||
# include SNMALLOC_BACKTRACE_HEADER
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/address.h"
|
||||
#include "../ds/bits.h"
|
||||
#include "../aal/aal.h"
|
||||
#include "pal_timer_default.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user