| |
| // Copyright Oliver Kowalke 2014. |
| // Distributed under the Boost Software License, Version 1.0. |
| // (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| #ifndef BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H |
| #define BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H |
| |
| extern "C" { |
| #include <fcntl.h> |
| #include <sys/mman.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| } |
| |
| #include <cmath> |
| #include <cstddef> |
| #include <new> |
| |
| #include <boost/assert.hpp> |
| #include <boost/config.hpp> |
| |
| #include <boost/context/detail/config.hpp> |
| #include <boost/context/stack_context.hpp> |
| #include <boost/context/stack_traits.hpp> |
| |
| #if defined(BOOST_USE_VALGRIND) |
| #include <valgrind/valgrind.h> |
| #endif |
| |
| #ifdef BOOST_HAS_ABI_HEADERS |
| # include BOOST_ABI_PREFIX |
| #endif |
| |
| namespace boost { |
| namespace context { |
| |
| template< typename traitsT > |
| class basic_protected_fixedsize_stack { |
| private: |
| std::size_t size_; |
| |
| public: |
| typedef traitsT traits_type; |
| |
| basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) : |
| size_( size) { |
| BOOST_ASSERT( traits_type::minimum_size() <= size_); |
| BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size_) ); |
| } |
| |
| stack_context allocate() { |
| // page at bottom will be used as guard-page |
| const std::size_t pages( |
| static_cast< std::size_t >( |
| std::floor( |
| static_cast< float >( size_) / traits_type::page_size() ) ) ); |
| BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)"); |
| const std::size_t size__( pages * traits_type::page_size() ); |
| BOOST_ASSERT( 0 < size_ && 0 < size__); |
| BOOST_ASSERT( size__ <= size_); |
| |
| // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) |
| #if defined(MAP_ANON) |
| void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); |
| #else |
| void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| #endif |
| if ( MAP_FAILED == vp) throw std::bad_alloc(); |
| |
| // conforming to POSIX.1-2001 |
| #if defined(BOOST_DISABLE_ASSERTS) |
| ::mprotect( vp, traits_type::page_size(), PROT_NONE); |
| #else |
| const int result( ::mprotect( vp, traits_type::page_size(), PROT_NONE) ); |
| BOOST_ASSERT( 0 == result); |
| #endif |
| |
| stack_context sctx; |
| sctx.size = size__; |
| sctx.sp = static_cast< char * >( vp) + sctx.size; |
| #if defined(BOOST_USE_VALGRIND) |
| sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp); |
| #endif |
| return sctx; |
| } |
| |
| void deallocate( stack_context & sctx) { |
| BOOST_ASSERT( sctx.sp); |
| BOOST_ASSERT( traits_type::minimum_size() <= sctx.size); |
| BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); |
| |
| #if defined(BOOST_USE_VALGRIND) |
| VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id); |
| #endif |
| |
| void * vp = static_cast< char * >( sctx.sp) - sctx.size; |
| // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) |
| ::munmap( vp, sctx.size); |
| } |
| }; |
| |
| typedef basic_protected_fixedsize_stack< stack_traits > protected_fixedsize_stack; |
| |
| }} |
| |
| #ifdef BOOST_HAS_ABI_HEADERS |
| # include BOOST_ABI_SUFFIX |
| #endif |
| |
| #endif // BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H |