00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef __POOL_ALLOCATOR_HH
00019 # define __POOL_ALLOCATOR_HH
00020
00021 # include <aurelia-config.hh>
00022
00023 # include <atomic>
00024 # include "../lockfree/simple_stack.hh"
00025
00026 # ifdef HAVE_VALGRIND_VALGRIND_H
00027 # pragma GCC diagnostic push
00028 # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
00029 # pragma GCC diagnostic ignored "-Wunused-value"
00030 # include <valgrind/valgrind.h>
00031 # include <valgrind/memcheck.h>
00032 # else
00033 # define VALGRIND_CREATE_MEMPOOL(X, Y, Z)
00034 # define VALGRIND_MAKE_MEM_NOACCESS(X, Y)
00035 # define VALGRIND_MEMPOOL_ALLOC(X, Y, Z)
00036 # define VALGRIND_MEMPOOL_FREE(X, Y)
00037 # define VALGRIND_MAKE_MEM_DEFINED(X, Y)
00038 # define VALGRIND_MAKE_MEM_UNDEFINED(X, Y)
00039 # endif
00040
00041 # include <cstdlib>
00042 # include <memory>
00043
00044 namespace aurelia {
00045
00046 template <int SIZE>
00047 struct block_list {
00048 private:
00049 lockfree::simple_stack<void*> blocks;
00050
00051 public:
00052 block_list() {}
00053 block_list(const block_list&) = delete;
00054
00055 void* new_block() {
00056 void *p = malloc(SIZE);
00057 if (p == NULL)
00058 throw std::bad_alloc();
00059 blocks.push(p);
00060 return p;
00061 }
00062
00063 ~block_list() {
00064 while (true) {
00065 lockfree::simple_stack<void*>::wrapped w = blocks.pop();
00066 if (w.end())
00067 return ;
00068 free(*w);
00069 }
00070 }
00071 };
00072
00073 template <typename T,
00074 int POOL_SIZE = 4096>
00075 struct chunk_alloc {
00076 private:
00077 static const void* mempool() {
00078 static bool init = false;
00079 if (!init) {
00080 init = true;
00081 VALGRIND_CREATE_MEMPOOL(&typeid(chunk_alloc), 0, false);
00082 }
00083 return &typeid(chunk_alloc);
00084 }
00085
00086 union block {
00087 typename std::aligned_storage<sizeof(T),
00088 std::alignment_of<T>::value>::type obj;
00089 block *next;
00090 };
00091
00092 static block*& free() {
00093 thread_local block* _free = NULL;
00094 return _free;
00095 }
00096
00097 static block_list<sizeof(block)*POOL_SIZE>& blocks() {
00098 static block_list<sizeof(block)*POOL_SIZE> _blocks;
00099 return _blocks;
00100 }
00101
00102 static block* ensure_blocks() {
00103 block* f = free();
00104 if (f == NULL) {
00105 f = (block*)blocks().new_block();
00106 free() = f;
00107 for (int i = 0; i < (POOL_SIZE - 1); ++i) {
00108 f[i].next = f + i + 1;
00109 }
00110 f[POOL_SIZE-1].next = NULL;
00111 VALGRIND_MAKE_MEM_NOACCESS(f, sizeof(block)*POOL_SIZE);
00112 }
00113 return f;
00114 }
00115
00116 public:
00117 static void *alloc() {
00118 block* n = ensure_blocks();
00119 VALGRIND_MEMPOOL_ALLOC(mempool(), n, sizeof(block));
00120 VALGRIND_MAKE_MEM_DEFINED(&(n->next), sizeof(block*));
00121 free() = n->next;
00122 VALGRIND_MAKE_MEM_UNDEFINED(&(n->next), sizeof(block*));
00123 return (void*)&(n->obj);
00124 }
00125
00126 static size_t offset() {
00127 block n;
00128 return ((char*)&n.obj - (char*)&n);
00129 }
00130
00131 static void del(void *p) {
00132 block *n = (block*)(((char*)p) - offset());
00133 n->next = free();
00134 VALGRIND_MEMPOOL_FREE(mempool(), n);
00135 free() = n;
00136 }
00137 };
00138
00139 template <typename T,
00140 int POOL_SIZE = 4096,
00141 typename RealAlloc = chunk_alloc<T, POOL_SIZE> >
00142 struct pool_allocator {
00143 typedef size_t size_type;
00144 typedef T* pointer;
00145 typedef T& reference;
00146 typedef const T* const_pointer;
00147 typedef const T& const_reference;
00148 typedef T value_type;
00149
00150 template <typename U>
00151 struct rebind {
00152 typedef pool_allocator<U, POOL_SIZE> other;
00153 };
00154
00155 template <typename U, int OTHERSIZE>
00156 pool_allocator(const pool_allocator<U, OTHERSIZE>&) {}
00157 pool_allocator() {}
00158
00159 pointer allocate(size_type n) {
00160 if (n == 1)
00161 return (pointer)RealAlloc::alloc();
00162 std::allocator<T> a;
00163 return a.allocate(n);
00164 }
00165
00166 void deallocate(pointer p, size_type n) {
00167 if (n == 1)
00168 return RealAlloc::del(p);
00169 std::allocator<T> a;
00170 a.deallocate(p, n);
00171 }
00172
00173 void destroy(pointer p) {
00174 p->~T();
00175 }
00176
00177 template <typename... Args>
00178 void construct(pointer p, Args... args...) {
00179 new (p) T(std::forward<Args>(args)...);
00180 }
00181 };
00182
00183 }
00184
00185 # ifdef HAVE_VALGRIND_VALGRIND_H
00186 # pragma GCC diagnostic pop
00187 # endif
00188
00189 #endif