2#ifndef CLICK_ALLOCATOR_HH
3#define CLICK_ALLOCATOR_HH
5#include <click/config.h>
6#include <click/glue.hh>
7#include <click/multithread.hh>
10#define CLICK_DEBUG_ALLOCATOR 0
14#define ALLOCATOR_POISON 0xA2C188F1
16class pool_allocator_mt_base {
21 static void set_dying(
bool v) {
58template <
typename T,
bool zero = false,
int POOL_SIZE = 64,
int POOL_COUNT = 32>
61 typedef struct item_t{
63#if CLICK_DEBUG_ALLOCATOR
68 typedef struct Pool_t {
87 typedef struct GlobalPool_t {
88 uint8_t _pad[
sizeof(item)];
89 struct GlobalPool_t* next;
95 void static_initialize() {
96 _pool.
resize(click_max_cpu_ids(),Pool());
99 T* allocate_uninitialized() {
100#if CLICK_DEBUG_ALLOCATOR
102 assert(_allocated >= _released);
105 Pool& p = _pool.get();
106#if CLICK_DEBUG_ALLOCATOR
107 assert(p.count == p.find_count());
111 if (_global_count > 0) {
112#if CLICK_DEBUG_ALLOCATOR
113 click_chatter(
"Global pool retrieved by thread %d",click_current_cpu_id());
115 p.first = (item*)_global_pool;
117 _global_pool = _global_pool->next;
122 p.first = (item*)(CLICK_LALLOC(
sizeof(T)));
124 bzero(p.first,
sizeof(T));
126#if CLICK_DEBUG_ALLOCATOR
132#if CLICK_DEBUG_ALLOCATOR
133 assert( ((item*)(p.first))->poison == ALLOCATOR_POISON);
134 ((item*)(p.first))->poison = 0;
138#if CLICK_DEBUG_ALLOCATOR
139 assert( ((item*)(p.first))->poison == ALLOCATOR_POISON);
140 ((item*)(p.first))->poison = 0;
144 p.first = p.first->next;
146#if CLICK_DEBUG_ALLOCATOR
147 assert(p.count == p.find_count());
150#if CLICK_DEBUG_ALLOCATOR > 1
151 click_chatter(
"%s Allocate %p %d %d",
typeid(T).name(), e,_released, _allocated);
156 T* allocate(
const T &t) {
157 T* e = allocate_uninitialized();
163 T* e = allocate_uninitialized();
168 void release_unitialized(T* e) {
170#if CLICK_DEBUG_ALLOCATOR
172#if CLICK_DEBUG_ALLOCATOR > 1
173 click_chatter(
"%s Release %p %d %d",
typeid(T).name(), e, _released, _allocated);
176 assert(_released <= _allocated);
178 Pool& p = _pool.get();
180#if CLICK_DEBUG_ALLOCATOR
181 assert(((item*)e)->poison != ALLOCATOR_POISON);
182 ((item*)e)->poison = ALLOCATOR_POISON;
184 if (unlikely(p.count == POOL_SIZE + 1)) {
186 if (_global_count == POOL_COUNT-1 || dying()) {
188 CLICK_LFREE(e,
sizeof(T));
190#if CLICK_DEBUG_ALLOCATOR
191 click_chatter(
"Global pool is full, freeing item");
194 click_chatter(
"Extremly inefficient pool_allocator_mt for %s ! Change parameters !",
typeid(T).name());
199#if CLICK_DEBUG_ALLOCATOR
200 click_chatter(
"Pool for thread %d is full, putting the pool in the global list",click_current_cpu_id());
203 GlobalPool* new_pool = (GlobalPool*)(p.first);
204 new_pool->next = _global_pool;
205 _global_pool = new_pool;
208 ((item*)e)->next = 0;
212 ((item*)e)->next = p.first;
215#if CLICK_DEBUG_ALLOCATOR
216 assert(p.count == p.find_count());
222 release_unitialized(e);
230 GlobalPool* _global_pool;
233#if CLICK_DEBUG_ALLOCATOR
240template <
typename T,
int POOL_SIZE = 64,
int POOL_COUNT = 32>
241class pool_allocator_aware_mt : pool_allocator_mt_base {
public:
243 typedef struct Pool_t {
255 p = (T*)p->pool_next_item;
263 pool_allocator_aware_mt();
264 ~pool_allocator_aware_mt();
267 return _pool.weight() == click_max_cpu_ids();
270 T* allocate_uninitialized() {
271#if CLICK_DEBUG_ALLOCATOR
273 assert(_allocated >= _released);
276 Pool& p = _pool.get();
277#if CLICK_DEBUG_ALLOCATOR
278 assert(p.count == p.find_count());
281 _global_lock.acquire();
282 if (_global_count > 0) {
283#if CLICK_DEBUG_ALLOCATOR
284 click_chatter(
"Global pool retrieved by thread %d",click_current_cpu_id());
286 p.first = _global_pool;
288 _global_pool = (T*)_global_pool->pool_next_pool;
291 _global_lock.release();
294#if CLICK_DEBUG_ALLOCATOR
297 p.first->pool_next_item = 0;
300#if CLICK_DEBUG_ALLOCATOR
301 assert(p.first->poison == ALLOCATOR_POISON);
306#if CLICK_DEBUG_ALLOCATOR
307 assert(p.first->poison == ALLOCATOR_POISON);
312 p.first = (T*)p.first->pool_next_item;
314#if CLICK_DEBUG_ALLOCATOR
315 assert(p.count == p.find_count());
320 void release_unitialized(T* e) {
321#if CLICK_DEBUG_ALLOCATOR
323 assert(_released <= _allocated);
325 Pool& p = _pool.get();
327#if CLICK_DEBUG_ALLOCATOR
328 assert(e->poison != ALLOCATOR_POISON);
329 e->poison = ALLOCATOR_POISON;
331 if (unlikely(p.count == POOL_SIZE + 1)) {
332 _global_lock.acquire();
333 if (_global_count == POOL_COUNT-1 || dying()) {
334 _global_lock.release();
337#if CLICK_DEBUG_ALLOCATOR
338 click_chatter(
"Global pool is full, freeing item");
340 click_chatter(
"Extremly inefficient pool_allocator_mt for %s ! Change parameters !",
typeid(T).name());
345#if CLICK_DEBUG_ALLOCATOR
346 click_chatter(
"Pool for thread %d is full, putting the pool in the global list",click_current_cpu_id());
349 T* new_pool = (T*)(p.first);
350 new_pool->pool_next_pool = _global_pool;
351 _global_pool = new_pool;
352 _global_lock.release();
354 e->pool_next_item = 0;
358 e->pool_next_item = p.first;
361#if CLICK_DEBUG_ALLOCATOR
362 assert(p.count == p.find_count());
374#if CLICK_DEBUG_ALLOCATOR
382template <
typename T,
bool ZERO,
int POOL_SIZE,
int POOL_COUNT>
384#if CLICK_DEBUG_ALLOCATOR
391template <
typename T,
bool ZERO,
int POOL_SIZE,
int POOL_COUNT>
393 static_assert(
sizeof(T) >=
sizeof(Pool),
"Allocator object is too small");
394#if CLICK_DEBUG_ALLOCATOR
397 while (_global_pool) {
398 item* p = (item*)_global_pool;
399 _global_pool = _global_pool->next;
403 CLICK_LFREE(p,
sizeof(T));
405#if CLICK_DEBUG_ALLOCATOR
410 for (
unsigned i = 0 ; i < _pool.weight(); i++) {
411 Pool &pool = _pool.get_value(i);
412 item* p = pool.first;
416 CLICK_LFREE(p,
sizeof(T));
418#if CLICK_DEBUG_ALLOCATOR
423#if CLICK_DEBUG_ALLOCATOR
424 click_chatter(
"Allocator : Newed %u, Freed %d, allocate() %u, released() %u",_newed,n_release,_allocated,_released);
429template <
typename T,
int POOL_SIZE,
int POOL_COUNT>
430pool_allocator_aware_mt<T,POOL_SIZE,POOL_COUNT>::pool_allocator_aware_mt() : _pool(Pool()),_global_count(0),_global_pool(0) {
431#if CLICK_DEBUG_ALLOCATOR
438template <
typename T,
int POOL_SIZE,
int POOL_COUNT>
439pool_allocator_aware_mt<T,POOL_SIZE,POOL_COUNT>::~pool_allocator_aware_mt() {
440 static_assert(
sizeof(T) >=
sizeof(Pool),
"Allocator object is too small");
441#if CLICK_DEBUG_ALLOCATOR
444 while (_global_pool) {
446 _global_pool = (T*)_global_pool->pool_next_pool;
449 next = (T*)p->pool_next_item;
452#if CLICK_DEBUG_ALLOCATOR
457 for (
unsigned i = 0 ; i < _pool.weight(); i++) {
458 Pool &pool = _pool.get_value(i);
462 next = (T*)p->pool_next_item;
465#if CLICK_DEBUG_ALLOCATOR
470#if CLICK_DEBUG_ALLOCATOR
471 click_chatter(
"Allocator : Newed %u, Freed %d, allocate() %u, released() %u",_newed,n_release,_allocated,_released);
A recursive spinlock for SMP Click threads.
Definition sync.hh:439
void release()
Releases the Spinlock.
Definition sync.hh:534
void acquire()
Acquires the Spinlock.
Definition sync.hh:488
A 32-bit integer with support for atomic operations.
Definition atomic.hh:71
void resize(unsigned int max_cpu_id, T v)
Definition sync.hh:97
Definition allocator.hh:59
Classes for synchronizing among multiple CPUs, particularly in the Linux kernel.