/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2015 Danny Robson */ #include "paged.hpp" #include "../cast.hpp" #include "../maths.hpp" #include "../pointer.hpp" #include "../posix/except.hpp" #include "../memory/system.hpp" #include using cruft::buffer::paged; /////////////////////////////////////////////////////////////////////////////// paged::paged (size_t bytes) : m_data (nullptr) { auto const allocated_bytes = round_up (bytes, memory::pagesize ()); // reserve the address region with no access permissions auto ptr = reinterpret_cast ( mmap (nullptr, allocated_bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) ); if (ptr == MAP_FAILED) posix::error::throw_code (); m_data = { ptr, allocated_bytes }; } //----------------------------------------------------------------------------- paged::~paged () { // ignore errors in production; we don't want to double throw. auto res = munmap (m_data.data (), capacity ()); (void)res; CHECK_ZERO (res); } /////////////////////////////////////////////////////////////////////////////// paged::value_type * paged::begin (void)& { return m_data.begin (); } //----------------------------------------------------------------------------- paged::value_type * paged::end (void)& { return m_data.end (); } /////////////////////////////////////////////////////////////////////////////// void paged::commit (cruft::view region) { apply_prot (region, PROT_READ | PROT_WRITE); } //----------------------------------------------------------------------------- void paged::release (cruft::view region) { apply_prot (region, PROT_NONE); } //----------------------------------------------------------------------------- void paged::apply_prot (cruft::view region, int prot) { if (!covers (m_data, region)) throw std::out_of_range ("invalid commit region"); // bump the request up to page aligned static_assert (sizeof (value_type) == 1); auto const alignment = memory::pagesize (); auto const first = align::down (region.begin (), alignment); auto const last = align::up (region.end (), alignment); if (MAP_FAILED == mmap (first, last - first, prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) posix::error::throw_code (); }