1 // 2 // detail/thread_info_base.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2019 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 <climits> 19 #include <cstddef> 20 #include <boost/asio/detail/noncopyable.hpp> 21 22 #include <boost/asio/detail/push_options.hpp> 23 24 namespace boost { 25 namespace asio { 26 namespace detail { 27 28 class thread_info_base 29 : private noncopyable 30 { 31 public: 32 struct default_tag 33 { 34 enum { mem_index = 0 }; 35 }; 36 37 struct awaitable_frame_tag 38 { 39 enum { mem_index = 1 }; 40 }; 41 42 struct executor_function_tag 43 { 44 enum { mem_index = 2 }; 45 }; 46 thread_info_base()47 thread_info_base() 48 { 49 for (int i = 0; i < max_mem_index; ++i) 50 reusable_memory_[i] = 0; 51 } 52 ~thread_info_base()53 ~thread_info_base() 54 { 55 for (int i = 0; i < max_mem_index; ++i) 56 if (reusable_memory_[i]) 57 ::operator delete(reusable_memory_[i]); 58 } 59 allocate(thread_info_base * this_thread,std::size_t size)60 static void* allocate(thread_info_base* this_thread, std::size_t size) 61 { 62 return allocate(default_tag(), this_thread, size); 63 } 64 deallocate(thread_info_base * this_thread,void * pointer,std::size_t size)65 static void deallocate(thread_info_base* this_thread, 66 void* pointer, std::size_t size) 67 { 68 deallocate(default_tag(), this_thread, pointer, size); 69 } 70 71 template <typename Purpose> allocate(Purpose,thread_info_base * this_thread,std::size_t size)72 static void* allocate(Purpose, thread_info_base* this_thread, 73 std::size_t size) 74 { 75 std::size_t chunks = (size + chunk_size - 1) / chunk_size; 76 77 if (this_thread && this_thread->reusable_memory_[Purpose::mem_index]) 78 { 79 void* const pointer = this_thread->reusable_memory_[Purpose::mem_index]; 80 this_thread->reusable_memory_[Purpose::mem_index] = 0; 81 82 unsigned char* const mem = static_cast<unsigned char*>(pointer); 83 if (static_cast<std::size_t>(mem[0]) >= chunks) 84 { 85 mem[size] = mem[0]; 86 return pointer; 87 } 88 89 ::operator delete(pointer); 90 } 91 92 void* const pointer = ::operator new(chunks * chunk_size + 1); 93 unsigned char* const mem = static_cast<unsigned char*>(pointer); 94 mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0; 95 return pointer; 96 } 97 98 template <typename Purpose> deallocate(Purpose,thread_info_base * this_thread,void * pointer,std::size_t size)99 static void deallocate(Purpose, thread_info_base* this_thread, 100 void* pointer, std::size_t size) 101 { 102 if (size <= chunk_size * UCHAR_MAX) 103 { 104 if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0) 105 { 106 unsigned char* const mem = static_cast<unsigned char*>(pointer); 107 mem[0] = mem[size]; 108 this_thread->reusable_memory_[Purpose::mem_index] = pointer; 109 return; 110 } 111 } 112 113 ::operator delete(pointer); 114 } 115 116 private: 117 enum { chunk_size = 4 }; 118 enum { max_mem_index = 3 }; 119 void* reusable_memory_[max_mem_index]; 120 }; 121 122 } // namespace detail 123 } // namespace asio 124 } // namespace boost 125 126 #include <boost/asio/detail/pop_options.hpp> 127 128 #endif // BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP 129