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