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