libcopp  1.1.0
stack_pool.h
Go to the documentation of this file.
1 #ifndef COPP_STACKCONTEXT_STACK_POOL_H
2 #define COPP_STACKCONTEXT_STACK_POOL_H
3 
4 #pragma once
5 
6 #include <assert.h>
7 #include <cstring>
8 #include <list>
9 
10 #include <libcopp/utils/features.h>
14 
15 
18 
19 
20 namespace copp {
21  template <typename TAlloc>
22  class stack_pool {
23  public:
24  typedef TAlloc allocator_t;
25  typedef std::shared_ptr<stack_pool<TAlloc> > ptr_t;
26 
27  struct limit_t {
32  };
33 
34  struct configure_t {
35  size_t stack_size;
36  size_t stack_offset;
37  size_t gc_number;
42  bool auto_gc;
43  };
44 
45  private:
47 
48  stack_pool() UTIL_CONFIG_DELETED_FUNCTION;
49  stack_pool(const stack_pool &) UTIL_CONFIG_DELETED_FUNCTION;
50 
51  public:
52  static ptr_t create() { return std::make_shared<stack_pool>(constructor_delegator()); }
53 
55  memset(&limits_, 0, sizeof(limits_));
56  memset(&conf_, 0, sizeof(conf_));
58  conf_.auto_gc = true;
59  }
60  ~stack_pool() { clear(); }
61 
62  inline const limit_t &get_limit() const { return limits_; }
63 
64  // configure
65  inline allocator_t & get_origin_allocator() COPP_MACRO_NOEXCEPT { return alloc_; }
66  inline const allocator_t &get_origin_allocator() const COPP_MACRO_NOEXCEPT { return alloc_; }
67 
68  size_t set_stack_size(size_t sz) {
71  } else {
73  }
74 
75  if (sz != conf_.stack_size) {
76  clear();
77  }
78 
79  return conf_.stack_size = sz;
80  }
81  size_t get_stack_size() const { return conf_.stack_size; }
82  size_t get_stack_size_offset() const { return conf_.stack_offset; }
83 
88 
93 
94  inline void set_auto_gc(bool v) COPP_MACRO_NOEXCEPT { conf_.auto_gc = v; }
95  inline bool is_auto_gc() const COPP_MACRO_NOEXCEPT { return conf_.auto_gc; }
96 
97  inline void set_gc_once_number(size_t v) COPP_MACRO_NOEXCEPT { conf_.gc_number = v; }
99 
100  // actions
101 
108  void allocate(stack_context &ctx) UTIL_CONFIG_NOEXCEPT {
109 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
111 #endif
112  // check limit
114  ctx.sp = NULL;
115  ctx.size = 0;
116  return;
117  }
118 
120  ctx.sp = NULL;
121  ctx.size = 0;
122  return;
123  }
124 
125  // get from pool, in order to max reuse cache, we use FILO to allocate stack
126  if (!free_list_.empty()) {
127  typename std::list<stack_context>::reverse_iterator iter = free_list_.rbegin();
128  assert(iter != free_list_.rend());
129 
130  // free limit
131  if (likely(limits_.free_stack_number > 0)) {
133  } else {
134  limits_.free_stack_number = free_list_.size() - 1;
135  }
136 
137  if (likely(limits_.free_stack_size >= (*iter).size)) {
138  limits_.free_stack_size -= (*iter).size;
139  } else {
141  }
142 
143  // make sure the stack must be greater or equal than configure after reset
144  if (likely(iter->size >= conf_.stack_size)) {
145  ctx = *iter;
146  free_list_.pop_back();
147 
148  // used limit
150  limits_.used_stack_size += ctx.size;
151  return;
152  } else {
153  // just pop cache
154  free_list_.pop_back();
155  }
156  }
157 
158  // get from origin allocator
159  alloc_.allocate(ctx, conf_.stack_size);
160  if (NULL != ctx.sp && ctx.size > 0) {
161  // used limit
163  limits_.used_stack_size += ctx.size;
164 
165  conf_.stack_offset = ctx.size - conf_.stack_size;
166  }
167  }
168 
173  void deallocate(stack_context &ctx) UTIL_CONFIG_NOEXCEPT {
174  assert(ctx.sp && ctx.size > 0);
175  do {
176 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
178 #endif
179  // check ctx
180  if (ctx.sp == NULL || 0 == ctx.size) {
181  break;
182  }
183 
184  // limits
185  if (likely(limits_.used_stack_size >= ctx.size)) {
186  limits_.used_stack_size -= ctx.size;
187  } else {
189  }
190 
191  if (likely(limits_.used_stack_number > 0)) {
193  }
194 
195  // check size
196  if (ctx.size != conf_.stack_size + conf_.stack_offset) {
197  alloc_.deallocate(ctx);
198  break;
199  }
200 
201  // push to free list
202  free_list_.push_back(ctx);
203 
204  // limits
206  limits_.free_stack_size += ctx.size;
207  } while (false);
208 
209  // check GC
210  if (conf_.auto_gc) {
211  gc();
212  }
213  }
214 
215  size_t gc() {
216  size_t ret = 0;
217  // gc only if free stacks is greater than used
219  return ret;
220  }
221 
222  // gc when stack is too large
223  if (0 != conf_.min_stack_size || 0 != conf_.min_stack_number) {
224  bool min_stack_size =
226  bool min_stack_number =
228  if (min_stack_size && min_stack_number) {
229  return ret;
230  }
231  }
232 
233 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
235 #endif
236 
237  size_t keep_size = limits_.free_stack_size >> 1;
238  size_t keep_number = limits_.free_stack_number >> 1;
239  size_t left_gc = conf_.gc_number;
240  while (limits_.free_stack_size > keep_size || limits_.free_stack_number > keep_number) {
241  if (free_list_.empty()) {
244  break;
245  }
246 
247  typename std::list<stack_context>::iterator iter = free_list_.begin();
248  assert(iter != free_list_.end());
249 
250  if (likely(limits_.free_stack_number > 0)) {
252  } else {
253  limits_.free_stack_number = free_list_.size() - 1;
254  }
255 
256  if (likely(limits_.free_stack_size >= (*iter).size)) {
257  limits_.free_stack_size -= (*iter).size;
258  } else {
260  }
261 
262  alloc_.deallocate(*iter);
263  free_list_.pop_front();
264  ++ret;
265 
266  // gc max stacks once
267  if (0 != left_gc) {
268  --left_gc;
269  if (0 == left_gc) {
270  break;
271  }
272  }
273  }
274 
276 
277  return ret;
278  }
279 
280  void clear() {
281 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
283 #endif
284 
287 
288  for (typename std::list<stack_context>::iterator iter = free_list_.begin(); iter != free_list_.end(); ++iter) {
289  alloc_.deallocate(*iter);
290  }
291 
293  }
294 
295  private:
298  allocator_t alloc_;
299 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
301 #endif
302  std::list<stack_context> free_list_;
303  };
304 } // namespace copp
305 
306 #endif
static std::size_t default_size() COPP_MACRO_NOEXCEPT
allocator_t alloc_
Definition: stack_pool.h:298
#define UTIL_LOCK_ATOMIC_THREAD_FENCE(x)
stack_pool() UTIL_CONFIG_DELETED_FUNCTION
size_t get_min_stack_size() const COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:90
size_t get_max_stack_number() const COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:87
void set_auto_gc(bool v) COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:94
const allocator_t & get_origin_allocator() const COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:66
自旋锁 Licensed under the MIT licenses.
#define likely(x)
util::lock::spin_lock action_lock_
Definition: stack_pool.h:300
stack_pool(constructor_delegator)
Definition: stack_pool.h:54
void allocate(stack_context &ctx) UTIL_CONFIG_NOEXCEPT
Definition: stack_pool.h:108
static ptr_t create()
Definition: stack_pool.h:52
锁管理器 Licensed under the MIT licenses.
size_t get_stack_size_offset() const
Definition: stack_pool.h:82
void set_max_stack_number(size_t sz) COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:86
allocator_t & get_origin_allocator() COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:65
#define COPP_MACRO_NOEXCEPT
Definition: features.h:71
TAlloc allocator_t
Definition: stack_pool.h:24
configure_t conf_
Definition: stack_pool.h:297
size_t set_stack_size(size_t sz)
Definition: stack_pool.h:68
static std::size_t minimum_size() COPP_MACRO_NOEXCEPT
导入智能指针库 Licensed under the MIT licenses.
void set_min_stack_number(size_t sz) COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:91
size_t get_gc_once_number() const COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:98
void set_max_stack_size(size_t sz) COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:84
const limit_t & get_limit() const
Definition: stack_pool.h:62
static std::size_t round_to_page_size(std::size_t stacksize) COPP_MACRO_NOEXCEPT
void set_gc_once_number(size_t v) COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:97
void deallocate(stack_context &ctx) UTIL_CONFIG_NOEXCEPT
Definition: stack_pool.h:173
size_t get_min_stack_number() const COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:92
bool is_auto_gc() const COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:95
size_t get_max_stack_size() const COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:85
std::list< stack_context > free_list_
Definition: stack_pool.h:302
void set_min_stack_size(size_t sz) COPP_MACRO_NOEXCEPT
Definition: stack_pool.h:89
size_t get_stack_size() const
Definition: stack_pool.h:81
std::shared_ptr< stack_pool< TAlloc > > ptr_t
Definition: stack_pool.h:25