Expose notify_using_readonly

This exposes a readonly notify using, so that the underlying platform
can map the range of pages readonly into the application.  This improves
performance of external pointer on platforms that support lazy commit
of pages as it can access anything in the range.
This commit is contained in:
Matthew Parkinson
2021-09-23 15:56:59 +01:00
committed by Matthew Parkinson
parent 0af1ee3bef
commit b4efc40aa6
3 changed files with 45 additions and 11 deletions

View File

@@ -33,6 +33,15 @@ function may not be required to do anything.
If the template parameter is set to `YesZero` then this function is also
responsible for ensuring that the newly requested memory is full of zeros.
```c++
static void notify_using_readonly(void* p, size_t size) noexcept;
```
Notify the system that the range of memory from `p` to `p` + `size` is now in use
for read-only access. This is currently only requried on platforms that support
`LazyCommit`.
On systems that lazily provide physical memory to virtual mappings, this
function may not be required to do anything.
```c++
template<bool page_aligned = false>
static void zero(void* p, size_t size) noexcept;

View File

@@ -159,7 +159,7 @@ namespace snmalloc
#ifdef SNMALLOC_CHECK_CLIENT
// Allocate a power of two extra to allow the placement of the
// pagemap be difficult to guess.
size_t additional_size = bits::next_pow2(REQUIRED_SIZE) * 2;
size_t additional_size = bits::next_pow2(REQUIRED_SIZE) * 4;
size_t request_size = REQUIRED_SIZE + additional_size;
#else
size_t request_size = REQUIRED_SIZE;
@@ -178,6 +178,18 @@ namespace snmalloc
size_t offset = get_entropy64<PAL>() & (additional_size - sizeof(T));
auto new_body =
reinterpret_cast<T*>(pointer_offset(new_body_untyped, offset));
if constexpr (pal_supports<LazyCommit, PAL>)
{
void* start_page = pointer_align_down<OS_PAGE_SIZE>(new_body);
void* end_page = pointer_align_up<OS_PAGE_SIZE>(
pointer_offset(new_body, REQUIRED_SIZE));
// Only commit readonly memory for this range, if the platform supports
// lazy commit. Otherwise, this would be a lot of memory to have
// mapped.
PAL::notify_using_readonly(
start_page, pointer_diff(start_page, end_page));
}
#else
auto new_body = reinterpret_cast<T*>(new_body_untyped);
#endif
@@ -243,15 +255,10 @@ namespace snmalloc
p = p - base;
}
// This means external pointer on Windows will be slow.
// TODO: With SNMALLOC_CHECK_CLIENT we should map that region read-only,
// not no-access, but this requires a PAL change.
if constexpr (
potentially_out_of_range
#ifndef SNMALLOC_CHECK_CLIENT
&& !pal_supports<LazyCommit, PAL>
#endif
)
// If this is potentially_out_of_range, then the pages will not have
// been mapped. With Lazy commit they will at least be mapped read-only
// Note that: this means external pointer on Windows will be slow.
if constexpr (potentially_out_of_range && !pal_supports<LazyCommit, PAL>)
{
register_range(p, 1);
}

View File

@@ -196,7 +196,7 @@ namespace snmalloc
*
* On POSIX platforms, lazy commit means that this is a no-op, unless we
* are also zeroing the pages in which case we call the platform's `zero`
* function.
* function, or we have initially mapped the pages as PROT_NONE.
*/
template<ZeroMem zero_mem>
static void notify_using(void* p, size_t size) noexcept
@@ -215,6 +215,24 @@ namespace snmalloc
zero<true>(p, size);
}
/**
* Notify platform that we will be using these pages for reading.
*
* On POSIX platforms, lazy commit means that this is a no-op, unless
* we have initially mapped the pages as PROT_NONE.
*/
static void notify_using_readonly(void* p, size_t size) noexcept
{
SNMALLOC_ASSERT(is_aligned_block<OS::page_size>(p, size));
#ifdef SNMALLOC_CHECK_CLIENT
mprotect(p, size, PROT_READ);
#else
UNUSED(p);
UNUSED(size);
#endif
}
/**
* OS specific function for zeroing memory.
*