1 // 2 // detail/thread_info_base.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #ifndef BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP 12 #define BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include <boost/asio/detail/config.hpp> 19 #include <climits> 20 #include <cstddef> 21 #include <boost/asio/detail/noncopyable.hpp> 22 23 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 24 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 25 # include <exception> 26 # include <boost/asio/multiple_exceptions.hpp> 27 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 28 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 29 30 #include <boost/asio/detail/push_options.hpp> 31 32 namespace boost { 33 namespace asio { 34 namespace detail { 35 36 class thread_info_base 37 : private noncopyable 38 { 39 public: 40 struct default_tag 41 { 42 enum { mem_index = 0 }; 43 }; 44 45 struct awaitable_frame_tag 46 { 47 enum { mem_index = 1 }; 48 }; 49 50 struct executor_function_tag 51 { 52 enum { mem_index = 2 }; 53 }; 54 thread_info_base()55 thread_info_base() 56 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 57 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 58 : has_pending_exception_(0) 59 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 60 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 61 { 62 for (int i = 0; i < max_mem_index; ++i) 63 reusable_memory_[i] = 0; 64 } 65 ~thread_info_base()66 ~thread_info_base() 67 { 68 for (int i = 0; i < max_mem_index; ++i) 69 ::operator delete(reusable_memory_[i]); 70 } 71 allocate(thread_info_base * this_thread,std::size_t size)72 static void* allocate(thread_info_base* this_thread, std::size_t size) 73 { 74 return allocate(default_tag(), this_thread, size); 75 } 76 deallocate(thread_info_base * this_thread,void * pointer,std::size_t size)77 static void deallocate(thread_info_base* this_thread, 78 void* pointer, std::size_t size) 79 { 80 deallocate(default_tag(), this_thread, pointer, size); 81 } 82 83 template <typename Purpose> allocate(Purpose,thread_info_base * this_thread,std::size_t size)84 static void* allocate(Purpose, thread_info_base* this_thread, 85 std::size_t size) 86 { 87 std::size_t chunks = (size + chunk_size - 1) / chunk_size; 88 89 if (this_thread && this_thread->reusable_memory_[Purpose::mem_index]) 90 { 91 void* const pointer = this_thread->reusable_memory_[Purpose::mem_index]; 92 this_thread->reusable_memory_[Purpose::mem_index] = 0; 93 94 unsigned char* const mem = static_cast<unsigned char*>(pointer); 95 if (static_cast<std::size_t>(mem[0]) >= chunks) 96 { 97 mem[size] = mem[0]; 98 return pointer; 99 } 100 101 ::operator delete(pointer); 102 } 103 104 void* const pointer = ::operator new(chunks * chunk_size + 1); 105 unsigned char* const mem = static_cast<unsigned char*>(pointer); 106 mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0; 107 return pointer; 108 } 109 110 template <typename Purpose> deallocate(Purpose,thread_info_base * this_thread,void * pointer,std::size_t size)111 static void deallocate(Purpose, thread_info_base* this_thread, 112 void* pointer, std::size_t size) 113 { 114 if (size <= chunk_size * UCHAR_MAX) 115 { 116 if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0) 117 { 118 unsigned char* const mem = static_cast<unsigned char*>(pointer); 119 mem[0] = mem[size]; 120 this_thread->reusable_memory_[Purpose::mem_index] = pointer; 121 return; 122 } 123 } 124 125 ::operator delete(pointer); 126 } 127 capture_current_exception()128 void capture_current_exception() 129 { 130 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 131 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 132 switch (has_pending_exception_) 133 { 134 case 0: 135 has_pending_exception_ = 1; 136 pending_exception_ = std::current_exception(); 137 break; 138 case 1: 139 has_pending_exception_ = 2; 140 pending_exception_ = 141 std::make_exception_ptr<multiple_exceptions>( 142 multiple_exceptions(pending_exception_)); 143 default: 144 break; 145 } 146 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 147 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 148 } 149 rethrow_pending_exception()150 void rethrow_pending_exception() 151 { 152 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 153 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 154 if (has_pending_exception_ > 0) 155 { 156 has_pending_exception_ = 0; 157 std::exception_ptr ex( 158 BOOST_ASIO_MOVE_CAST(std::exception_ptr)( 159 pending_exception_)); 160 std::rethrow_exception(ex); 161 } 162 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 163 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 164 } 165 166 private: 167 enum { chunk_size = 4 }; 168 enum { max_mem_index = 3 }; 169 void* reusable_memory_[max_mem_index]; 170 171 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 172 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 173 int has_pending_exception_; 174 std::exception_ptr pending_exception_; 175 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 176 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 177 }; 178 179 } // namespace detail 180 } // namespace asio 181 } // namespace boost 182 183 #include <boost/asio/detail/pop_options.hpp> 184 185 #endif // BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP 186