diff --git a/src/mem/alloc.h b/src/mem/alloc.h index c65c0cf..fedab96 100644 --- a/src/mem/alloc.h +++ b/src/mem/alloc.h @@ -62,30 +62,112 @@ namespace snmalloc Pagemap>; HEADER_GLOBAL SuperslabPagemap global_pagemap; + + /** + * Mixin used by `SuperslabMap` to directly access the pagemap via a global + * variable. This should be used from within the library or program that + * owns the pagemap. + */ + struct GlobalPagemap + { + /** + * Returns the pagemap. + */ + SuperslabPagemap& pagemap() + { + return global_pagemap; + } + }; + + /** + * Mixin used by `SuperslabMap` to access a pagemap provided by the user. + * This should be used by code that needs to access the canonical pagemap via + * some custom mechanism. + */ + class CustomPagemap + { + /** + * Reference to the pagemap that we're using, allowing it to not be the + * default pagemap. + */ + SuperslabPagemap& custom_pagemap; + + public: + /** + * Constructor. Takes the pagemap to use as an argument. This constructor + * will be inherited by `SuperslabMap` if this mixin is used and so should + * be called as a constructor there, rather than directly. + */ + CustomPagemap(SuperslabPagemap& pm) : custom_pagemap(pm) {} + + /** + * Returns the provided pagemap. + */ + SuperslabPagemap& pagemap() + { + return custom_pagemap; + } + }; + + /** + * Optionally exported function that accesses the global pagemap provided by + * a shared library. + */ + extern "C" void* snmalloc_pagemap_global_get(snmalloc::PagemapConfig const**); + + /** + * Mixin used by `SuperslabMap` to access the global pagemap via a + * type-checked C interface. This should be used when another library (e.g. + * your C standard library) uses snmalloc and you wish to use a different + * configuration in your program or library, but wish to share a pagemap so + * that either version can deallocate memory. + */ + class ExternalGlobalPagemap + { + /** + * A pointer to the pagemap. + */ + SuperslabPagemap* external_pagemap; + + public: + /** + * Construtor. Accesses the pagemap via the C ABI accessor and casts it to + * the expected type, failing in cases of ABI mismatch. + */ + ExternalGlobalPagemap() + { + const snmalloc::PagemapConfig* c; + external_pagemap = + SuperslabPagemap::cast_to_pagemap(snmalloc_get_global_pagemap(&c), c); + // FIXME: Report an error somehow in non-debug builds. + assert(external_pagemap); + } + + /** + * Returns the exported pagemap. + */ + SuperslabPagemap& pagemap() + { + return *external_pagemap; + } + }; + /** * Class that defines an interface to the pagemap. This is provided to * `Allocator` as a template argument and so can be replaced by a compatible * implementation (for example, to move pagemap updates to a different * protection domain). */ - struct SuperslabMap + template + struct SuperslabMap : public PagemapProvider { - /** - * Reference to the pagemap that we're using, allowing it to not be the - * default pagemap. - */ - SuperslabPagemap& pagemap; - /** - * Constructor. Uses the global pagemap by default, but can use a - * different one if required. - */ - SuperslabMap(SuperslabPagemap& pm = global_pagemap) : pagemap(pm) {} + using PagemapProvider::PagemapProvider; /** * Get the pagemap entry corresponding to a specific address. */ uint8_t get(void* p) { - return pagemap.get(p); + return PagemapProvider::pagemap().get(p); } /** * Set a pagemap entry indicating that there is a superslab at the @@ -131,10 +213,11 @@ namespace snmalloc for (size_t i = 0; i < size_bits - SUPERSLAB_BITS; i++) { size_t run = 1ULL << i; - pagemap.set_range((void*)ss, (uint8_t)(64 + i + SUPERSLAB_BITS), run); + PagemapProvider::pagemap().set_range( + (void*)ss, (uint8_t)(64 + i + SUPERSLAB_BITS), run); ss = (uintptr_t)ss + SUPERSLAB_SIZE * run; } - pagemap.set(p, (uint8_t)size_bits); + PagemapProvider::pagemap().set(p, (uint8_t)size_bits); } /** * Update the pagemap to remove a large allocation, of `size` bytes from @@ -145,7 +228,7 @@ namespace snmalloc size_t rounded_size = bits::next_pow2(size); assert(get(p) == bits::next_pow2_bits(size)); auto count = rounded_size >> SUPERSLAB_BITS; - pagemap.set_range((void*)p, PMNotOurs, count); + PagemapProvider::pagemap().set_range((void*)p, PMNotOurs, count); } private: @@ -156,12 +239,12 @@ namespace snmalloc */ void set(void* p, uint8_t x) { - pagemap.set(p, x); + PagemapProvider::pagemap().set(p, x); } }; #ifndef SNMALLOC_DEFAULT_PAGEMAP -# define SNMALLOC_DEFAULT_PAGEMAP snmalloc::SuperslabMap +# define SNMALLOC_DEFAULT_PAGEMAP snmalloc::SuperslabMap<> #endif /**