This is the set of changes required for snmalloc2 to be usable by the process sandboxing code and incorporates some API changes that reduce the amount of code required to embed snmalloc. Highlights: - Merge the config and back-end classes. - Everything in config is now global (all methods are static) - The GlobalState class is gone (all global state is managed by global methods on the config class) - LocalState is now a member of the config class, all methods are instance methods. - Not every configuration needs to use the lazy initialisation hooks. They now need to be provided only if they are used. If the configuration does not provide an `ensure_init` method, it is not called. If it does not provide an `is_initialised` method then the global initialisation state is not checked. - There is now an `snmalloc::Options` class that default initialises itself to the default behaviour. Every configuration must provide a `constexpr` instance of this class. Each flag can be separately overridden and new flags can be added without breaking any existing API consumers. The config classes are moved into the backend directory.
119 lines
4.4 KiB
C++
119 lines
4.4 KiB
C++
#pragma once
|
|
|
|
#include "../ds/defines.h"
|
|
#include "../mem/remotecache.h"
|
|
|
|
namespace snmalloc
|
|
{
|
|
// Forward reference to thread local cleanup.
|
|
void register_clean_up();
|
|
|
|
/**
|
|
* Options for a specific snmalloc configuration. Every globals object must
|
|
* have one `constexpr` instance of this class called `Options`. This should
|
|
* be constructed to explicitly override any of the defaults. A
|
|
* configuration that does not need to override anything would simply declare
|
|
* this as a field of the global object:
|
|
*
|
|
* ```c++
|
|
* constexpr static snmalloc::Flags Options{};
|
|
* ```
|
|
*
|
|
* A global configuration that wished to use out-of-line message queues but
|
|
* accept the defaults for everything else would instead do this:
|
|
*
|
|
* ```c++
|
|
* constexpr static snmalloc::Flags Options{.IsQueueInline = false};
|
|
* ```
|
|
*
|
|
* To maintain backwards source compatibility in future versions, any new
|
|
* option added here should have its default set to be whatever snmalloc was
|
|
* doing before the new option was added.
|
|
*/
|
|
struct Flags
|
|
{
|
|
/**
|
|
* Should allocators have inline message queues? If this is true then
|
|
* the `CoreAllocator` is responsible for allocating the
|
|
* `RemoteAllocator` that contains its message queue. If this is false
|
|
* then the `RemoteAllocator` must be separately allocated and provided
|
|
* to the `CoreAllocator` before it is used.
|
|
*
|
|
* Setting this to `false` currently requires also setting
|
|
* `LocalAllocSupportsLazyInit` to false so that the `CoreAllocator` can
|
|
* be provided to the `LocalAllocator` fully initialised but in the
|
|
* future it may be possible to allocate the `RemoteAllocator` via
|
|
* `alloc_meta_data` or a similar API in the back end.
|
|
*/
|
|
bool IsQueueInline = true;
|
|
|
|
/**
|
|
* Does the `CoreAllocator` own a `Backend::LocalState` object? If this is
|
|
* true then the `CoreAllocator` is responsible for allocating and
|
|
* deallocating a local state object, otherwise the surrounding code is
|
|
* responsible for creating it.
|
|
*
|
|
* Use cases that set this to false will probably also need to set
|
|
* `LocalAllocSupportsLazyInit` to false so that they can provide the local
|
|
* state explicitly during allocator creation.
|
|
*/
|
|
bool CoreAllocOwnsLocalState = true;
|
|
|
|
/**
|
|
* Are `CoreAllocator` allocated by the pool allocator? If not then the
|
|
* code embedding this snmalloc configuration is responsible for allocating
|
|
* `CoreAllocator` instances.
|
|
*
|
|
* Users setting this flag must also set `LocalAllocSupportsLazyInit` to
|
|
* false currently because there is no alternative mechanism for allocating
|
|
* core allocators. This may change in future versions.
|
|
*/
|
|
bool CoreAllocIsPoolAllocated = true;
|
|
|
|
/**
|
|
* Do `LocalAllocator` instances in this configuration support lazy
|
|
* initialisation? If so, then the first exit from a fast path will
|
|
* trigger allocation of a `CoreAllocator` and associated state. If not
|
|
* then the code embedding this configuration of snmalloc is responsible
|
|
* for allocating core allocators.
|
|
*/
|
|
bool LocalAllocSupportsLazyInit = true;
|
|
};
|
|
|
|
/**
|
|
* Class containing definitions that are likely to be used by all except for
|
|
* the most unusual back-end implementations. This can be subclassed as a
|
|
* convenience for back-end implementers, but is not required.
|
|
*/
|
|
class CommonConfig
|
|
{
|
|
public:
|
|
/**
|
|
* Special remote that should never be used as a real remote.
|
|
* This is used to initialise allocators that should always hit the
|
|
* remote path for deallocation. Hence moving a branch off the critical
|
|
* path.
|
|
*/
|
|
SNMALLOC_REQUIRE_CONSTINIT
|
|
inline static RemoteAllocator unused_remote;
|
|
|
|
/**
|
|
* Special remote that is used in meta-data for large allocations.
|
|
*
|
|
* nullptr is considered a large allocations for this purpose to move
|
|
* of the critical path.
|
|
*
|
|
* Bottom bits of the remote pointer are used for a sizeclass, we need
|
|
* size bits to represent the non-large sizeclasses, we can then get
|
|
* the large sizeclass by having the fake large_remote considerably
|
|
* more aligned.
|
|
*/
|
|
SNMALLOC_REQUIRE_CONSTINIT
|
|
inline static constexpr RemoteAllocator* fake_large_remote{nullptr};
|
|
|
|
static_assert(
|
|
&unused_remote != fake_large_remote,
|
|
"Compilation should ensure these are different");
|
|
};
|
|
} // namespace snmalloc
|