@@ -62,20 +62,82 @@ namespace snmalloc
6262 Pagemap<SUPERSLAB_BITS , uint8_t , 0 >>;
6363
6464 HEADER_GLOBAL SuperslabPagemap global_pagemap;
65+
66+ /* *
67+ * Mixin used by `SuperslabMap` to directly access the pagemap via a global
68+ * variable. This should be used from within the library or program that
69+ * owns the pagemap.
70+ */
71+ struct GlobalPagemap
72+ {
73+ /* *
74+ * Returns the pagemap.
75+ */
76+ SuperslabPagemap& pagemap ()
77+ {
78+ return global_pagemap;
79+ }
80+ };
81+
82+ /* *
83+ * Optionally exported function that accesses the global pagemap provided by
84+ * a shared library.
85+ */
86+ extern " C" void * snmalloc_pagemap_global_get (snmalloc::PagemapConfig const **);
87+
88+ /* *
89+ * Mixin used by `SuperslabMap` to access the global pagemap via a
90+ * type-checked C interface. This should be used when another library (e.g.
91+ * your C standard library) uses snmalloc and you wish to use a different
92+ * configuration in your program or library, but wish to share a pagemap so
93+ * that either version can deallocate memory.
94+ */
95+ class ExternalGlobalPagemap
96+ {
97+ /* *
98+ * A pointer to the pagemap.
99+ */
100+ SuperslabPagemap* external_pagemap;
101+
102+ public:
103+ /* *
104+ * Constructor. Accesses the pagemap via the C ABI accessor and casts it to
105+ * the expected type, failing in cases of ABI mismatch.
106+ */
107+ ExternalGlobalPagemap ()
108+ {
109+ const snmalloc::PagemapConfig* c;
110+ external_pagemap =
111+ SuperslabPagemap::cast_to_pagemap (snmalloc_pagemap_global_get (&c), c);
112+ // FIXME: Report an error somehow in non-debug builds.
113+ assert (external_pagemap);
114+ }
115+
116+ /* *
117+ * Returns the exported pagemap.
118+ */
119+ SuperslabPagemap& pagemap ()
120+ {
121+ return *external_pagemap;
122+ }
123+ };
124+
65125 /* *
66126 * Class that defines an interface to the pagemap. This is provided to
67127 * `Allocator` as a template argument and so can be replaced by a compatible
68128 * implementation (for example, to move pagemap updates to a different
69129 * protection domain).
70130 */
71- struct SuperslabMap
131+ template <typename PagemapProvider = GlobalPagemap>
132+ struct SuperslabMap : public PagemapProvider
72133 {
134+ using PagemapProvider::PagemapProvider;
73135 /* *
74136 * Get the pagemap entry corresponding to a specific address.
75137 */
76138 uint8_t get (void * p)
77139 {
78- return global_pagemap .get (p);
140+ return PagemapProvider::pagemap () .get (p);
79141 }
80142 /* *
81143 * Set a pagemap entry indicating that there is a superslab at the
@@ -121,11 +183,11 @@ namespace snmalloc
121183 for (size_t i = 0 ; i < size_bits - SUPERSLAB_BITS ; i++)
122184 {
123185 size_t run = 1ULL << i;
124- global_pagemap .set_range (
186+ PagemapProvider::pagemap () .set_range (
125187 (void *)ss, (uint8_t )(64 + i + SUPERSLAB_BITS ), run);
126188 ss = (uintptr_t )ss + SUPERSLAB_SIZE * run;
127189 }
128- global_pagemap .set (p, (uint8_t )size_bits);
190+ PagemapProvider::pagemap () .set (p, (uint8_t )size_bits);
129191 }
130192 /* *
131193 * Update the pagemap to remove a large allocation, of `size` bytes from
@@ -136,7 +198,7 @@ namespace snmalloc
136198 size_t rounded_size = bits::next_pow2 (size);
137199 assert (get (p) == bits::next_pow2_bits (size));
138200 auto count = rounded_size >> SUPERSLAB_BITS ;
139- global_pagemap .set_range ((void *)p, PMNotOurs, count);
201+ PagemapProvider::pagemap () .set_range ((void *)p, PMNotOurs, count);
140202 }
141203
142204 private:
@@ -147,12 +209,12 @@ namespace snmalloc
147209 */
148210 void set (void * p, uint8_t x)
149211 {
150- global_pagemap .set (p, x);
212+ PagemapProvider::pagemap () .set (p, x);
151213 }
152214 };
153215
154216#ifndef SNMALLOC_DEFAULT_PAGEMAP
155- # define SNMALLOC_DEFAULT_PAGEMAP snmalloc::SuperslabMap
217+ # define SNMALLOC_DEFAULT_PAGEMAP snmalloc::SuperslabMap<>
156218#endif
157219
158220 /* *
0 commit comments