protected_stack_allocator.hpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright Oliver Kowalke 2009.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H
  6. #define BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H
  7. extern "C" {
  8. #include <fcntl.h>
  9. #include <sys/mman.h>
  10. #include <sys/stat.h>
  11. #include <unistd.h>
  12. }
  13. #if defined(BOOST_USE_VALGRIND)
  14. #include <valgrind/valgrind.h>
  15. #endif
  16. #include <cmath>
  17. #include <cstddef>
  18. #include <new>
  19. #include <boost/assert.hpp>
  20. #include <boost/config.hpp>
  21. #include <boost/coroutine/detail/config.hpp>
  22. #include <boost/coroutine/stack_context.hpp>
  23. #include <boost/coroutine/stack_traits.hpp>
  24. #ifdef BOOST_HAS_ABI_HEADERS
  25. # include BOOST_ABI_PREFIX
  26. #endif
  27. namespace boost {
  28. namespace coroutines {
  29. template< typename traitsT >
  30. struct basic_protected_stack_allocator
  31. {
  32. typedef traitsT traits_type;
  33. void allocate( stack_context & ctx, std::size_t size = traits_type::minimum_size() )
  34. {
  35. BOOST_ASSERT( traits_type::minimum_size() <= size);
  36. BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= size) );
  37. // page at bottom will be used as guard-page
  38. const std::size_t pages(
  39. static_cast< std::size_t >(
  40. std::floor(
  41. static_cast< float >( size) / traits_type::page_size() ) ) );
  42. BOOST_ASSERT_MSG( 2 <= pages, "at least two pages must fit into stack (one page is guard-page)");
  43. const std::size_t size_( pages * traits_type::page_size() );
  44. BOOST_ASSERT( 0 != size && 0 != size_);
  45. BOOST_ASSERT( size_ <= size);
  46. // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L)
  47. #if defined(MAP_ANON)
  48. void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
  49. #else
  50. void * limit = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  51. #endif
  52. if ( MAP_FAILED == limit) throw std::bad_alloc();
  53. // conforming to POSIX.1-2001
  54. #if defined(BOOST_DISABLE_ASSERTS)
  55. ::mprotect( limit, traits_type::page_size(), PROT_NONE);
  56. #else
  57. const int result( ::mprotect( limit, traits_type::page_size(), PROT_NONE) );
  58. BOOST_ASSERT( 0 == result);
  59. #endif
  60. ctx.size = size_;
  61. ctx.sp = static_cast< char * >( limit) + ctx.size;
  62. #if defined(BOOST_USE_VALGRIND)
  63. ctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( ctx.sp, limit);
  64. #endif
  65. }
  66. void deallocate( stack_context & ctx)
  67. {
  68. BOOST_ASSERT( ctx.sp);
  69. BOOST_ASSERT( traits_type::minimum_size() <= ctx.size);
  70. BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= ctx.size) );
  71. #if defined(BOOST_USE_VALGRIND)
  72. VALGRIND_STACK_DEREGISTER( ctx.valgrind_stack_id);
  73. #endif
  74. void * limit = static_cast< char * >( ctx.sp) - ctx.size;
  75. // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L)
  76. ::munmap( limit, ctx.size);
  77. }
  78. };
  79. typedef basic_protected_stack_allocator< stack_traits > protected_stack_allocator;
  80. }}
  81. #ifdef BOOST_HAS_ABI_HEADERS
  82. # include BOOST_ABI_SUFFIX
  83. #endif
  84. #endif // BOOST_COROUTINES_PROTECTED_STACK_ALLOCATOR_H