diff --git a/memory/buffer/paged.cpp b/memory/buffer/paged.cpp index f1382acd..14f432a6 100644 --- a/memory/buffer/paged.cpp +++ b/memory/buffer/paged.cpp @@ -20,27 +20,20 @@ using cruft::memory::buffer::paged; /////////////////////////////////////////////////////////////////////////////// -paged::paged (size_t bytes, size_t _window): - m_window (round_up (_window, pagesize ())) +paged::paged (size_t bytes) + : m_data (nullptr) { + auto const allocated_bytes = round_up (bytes, pagesize ()); + // reserve the address region with no access permissions - m_begin = reinterpret_cast ( - mmap (nullptr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) + auto ptr = reinterpret_cast ( + mmap (nullptr, allocated_bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) ); - if (m_begin == MAP_FAILED) + if (ptr == MAP_FAILED) posix::error::throw_code (); - // remap the initial window with read/write permissions - m_cursor = m_begin + round_up (min (m_window, bytes), pagesize ()); - if (MAP_FAILED == mmap (m_begin, - m_cursor - m_begin, - PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) - posix::error::throw_code (); - - // record the nominal end address - m_end = m_begin + round_up (bytes, pagesize ()); + m_data = { ptr, allocated_bytes }; } @@ -48,112 +41,59 @@ paged::paged (size_t bytes, size_t _window): paged::~paged () { // ignore errors in production; we don't want to double throw. - auto res = munmap (m_begin, m_end - m_begin); + auto res = munmap (m_data.data (), capacity ()); (void)res; CHECK_ZERO (res); } /////////////////////////////////////////////////////////////////////////////// -char* +paged::value_type * paged::begin (void)& { - return m_begin; + return m_data.begin (); } //----------------------------------------------------------------------------- -char* +paged::value_type * paged::end (void)& { - return m_end; + return m_data.end (); } /////////////////////////////////////////////////////////////////////////////// void -paged::access (char *cursor) +paged::commit (cruft::view region) { - if (cursor < m_cursor) - release (cursor); - else - commit (cursor); + apply_prot (region, PROT_READ | PROT_WRITE); } //----------------------------------------------------------------------------- void -paged::commit (char *cursor) +paged::release (cruft::view region) { - // bail if it's already mapped - if (cursor <= m_cursor) - return; - - if (cursor > m_end || cursor < m_begin) - throw std::out_of_range ("invalid commit cursor"); - - // bump the request up to page aligned and tack on a little to amortize - // syscall overheads - cursor = align (cursor, pagesize ()) + m_window; - cursor = min (cursor, m_end); - - if (MAP_FAILED == mmap (m_cursor, - cursor - m_cursor, - PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0)) - posix::error::throw_code (); - - m_cursor = cursor; + apply_prot (region, PROT_NONE); } //----------------------------------------------------------------------------- void -paged::release (char *desired) +paged::apply_prot (cruft::view region, int prot) { - if (desired > m_end || desired < m_begin) - throw std::out_of_range ("invalid release cursor"); + if (!covers (m_data, region)) + throw std::out_of_range ("invalid commit region"); - align (desired, pagesize ()); + // bump the request up to page aligned + static_assert (sizeof (value_type) == 1); + auto const alignment = pagesize (); + auto const first = align_down (region.begin (), alignment); + auto const last = align_up (region.end (), alignment); - // bail if the region is alread unmapped, or if it's not sufficiently - // behind the current cursor. - if (desired >= m_cursor || cruft::cast::sign (m_cursor - desired) < m_window) - return; - - desired += m_window; - - if (MAP_FAILED == mmap (desired, - m_end - desired, - PROT_NONE, + if (MAP_FAILED == mmap (first, last - first, prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) posix::error::throw_code (); - - m_cursor = desired; -} - - -/////////////////////////////////////////////////////////////////////////////// -size_t -paged::size (void) const -{ - return m_cursor - m_begin; -} - - -//----------------------------------------------------------------------------- -size_t -paged::capacity (void) const -{ - return m_end - m_begin; -} - - -//----------------------------------------------------------------------------- -size_t -paged::window (void) const -{ - return m_window; } diff --git a/memory/buffer/paged.hpp b/memory/buffer/paged.hpp index 0baec233..d287fb77 100644 --- a/memory/buffer/paged.hpp +++ b/memory/buffer/paged.hpp @@ -6,46 +6,55 @@ * Copyright 2015 Danny Robson */ -#ifndef __UTIL_MEMORY_BUFFER_PAGED_HPP -#define __UTIL_MEMORY_BUFFER_PAGED_HPP +#pragma once + +#include "../../std.hpp" +#include "../../view.hpp" #include + namespace cruft::memory::buffer { + /// Implements a manually paged memory buffer of a fixed length. + /// + /// It can be used to ensure a contiguous memory region of bounded size + /// is available at a later point in execution. class paged { public: - using value_type = char; + using value_type = u08; - paged (size_t bytes, size_t window); + paged (size_t bytes); ~paged (); paged (const paged&) = delete; - paged (paged &&) = delete; + paged (paged &&); paged& operator= (const paged&) = delete; paged& operator= (paged &&) = delete; - char* begin (void)&; - char* end (void)&; + value_type* begin (void)&; + value_type* end (void)&; - const char* cbegin (void)&; - const char* cend (void)&; + const value_type* cbegin (void)&; + const value_type* cend (void)&; - const char* begin (void) const&; - const char* end (void) const&; + const value_type* begin (void) const&; + const value_type* end (void) const&; - void access (char*); + void commit (value_type *ptr) { return commit ({ ptr, 1 }); } + void release (value_type *ptr) { return release ({ ptr, 1 }); } - size_t size (void) const; - size_t capacity (void) const; - size_t window (void) const; + /// Populates the memory range and ensures it is read/write. + void commit (cruft::view); + /// Returns the memory range to the system. + void release (cruft::view); + + auto size (void) const { return m_data.size (); } + auto capacity (void) const { return m_data.size (); } private: - void commit (char*); - void release (char*); + /// Applies memory protection flags to the given memory region. + void apply_prot (cruft::view, int prot); - char *m_begin, *m_end, *m_cursor; - size_t m_window; + cruft::view m_data; }; } - -#endif