1 // 2 // detail/thread_info_base.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 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 { 70 // The following test for non-null pointers is technically redundant, but 71 // it is significantly faster when using a tight io_context::poll() loop 72 // in latency sensitive applications. 73 if (reusable_memory_[i]) 74 ::operator delete(reusable_memory_[i]); 75 } 76 } 77 allocate(thread_info_base * this_thread,std::size_t size)78 static void* allocate(thread_info_base* this_thread, std::size_t size) 79 { 80 return allocate(default_tag(), this_thread, size); 81 } 82 deallocate(thread_info_base * this_thread,void * pointer,std::size_t size)83 static void deallocate(thread_info_base* this_thread, 84 void* pointer, std::size_t size) 85 { 86 deallocate(default_tag(), this_thread, pointer, size); 87 } 88 89 template <typename Purpose> allocate(Purpose,thread_info_base * this_thread,std::size_t size)90 static void* allocate(Purpose, thread_info_base* this_thread, 91 std::size_t size) 92 { 93 std::size_t chunks = (size + chunk_size - 1) / chunk_size; 94 95 if (this_thread && this_thread->reusable_memory_[Purpose::mem_index]) 96 { 97 void* const pointer = this_thread->reusable_memory_[Purpose::mem_index]; 98 this_thread->reusable_memory_[Purpose::mem_index] = 0; 99 100 unsigned char* const mem = static_cast<unsigned char*>(pointer); 101 if (static_cast<std::size_t>(mem[0]) >= chunks) 102 { 103 mem[size] = mem[0]; 104 return pointer; 105 } 106 107 ::operator delete(pointer); 108 } 109 110 void* const pointer = ::operator new(chunks * chunk_size + 1); 111 unsigned char* const mem = static_cast<unsigned char*>(pointer); 112 mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0; 113 return pointer; 114 } 115 116 template <typename Purpose> deallocate(Purpose,thread_info_base * this_thread,void * pointer,std::size_t size)117 static void deallocate(Purpose, thread_info_base* this_thread, 118 void* pointer, std::size_t size) 119 { 120 if (size <= chunk_size * UCHAR_MAX) 121 { 122 if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0) 123 { 124 unsigned char* const mem = static_cast<unsigned char*>(pointer); 125 mem[0] = mem[size]; 126 this_thread->reusable_memory_[Purpose::mem_index] = pointer; 127 return; 128 } 129 } 130 131 ::operator delete(pointer); 132 } 133 capture_current_exception()134 void capture_current_exception() 135 { 136 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 137 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 138 switch (has_pending_exception_) 139 { 140 case 0: 141 has_pending_exception_ = 1; 142 pending_exception_ = std::current_exception(); 143 break; 144 case 1: 145 has_pending_exception_ = 2; 146 pending_exception_ = 147 std::make_exception_ptr<multiple_exceptions>( 148 multiple_exceptions(pending_exception_)); 149 break; 150 default: 151 break; 152 } 153 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 154 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 155 } 156 rethrow_pending_exception()157 void rethrow_pending_exception() 158 { 159 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 160 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 161 if (has_pending_exception_ > 0) 162 { 163 has_pending_exception_ = 0; 164 std::exception_ptr ex( 165 BOOST_ASIO_MOVE_CAST(std::exception_ptr)( 166 pending_exception_)); 167 std::rethrow_exception(ex); 168 } 169 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 170 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 171 } 172 173 private: 174 enum { chunk_size = 4 }; 175 enum { max_mem_index = 3 }; 176 void* reusable_memory_[max_mem_index]; 177 178 #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ 179 && !defined(BOOST_ASIO_NO_EXCEPTIONS) 180 int has_pending_exception_; 181 std::exception_ptr pending_exception_; 182 #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) 183 // && !defined(BOOST_ASIO_NO_EXCEPTIONS) 184 }; 185 186 } // namespace detail 187 } // namespace asio 188 } // namespace boost 189 190 #include <boost/asio/detail/pop_options.hpp> 191 192 #endif // BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP 193