Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pool.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2011 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * pool allocator
25  */
26 
27 #include "precompiled.h"
28 #include "lib/allocators/pool.h"
29 
30 #include "lib/alignment.h"
33 
34 #include "lib/timer.h"
35 
36 namespace Allocators {
37 
38 template<class Storage>
40 {
41  void operator()() const
42  {
43  Pool<double, Storage> p(100);
44  const size_t initialSpace = p.RemainingObjects();
45  double* p1 = p.Allocate();
46  ENSURE(p1 != 0);
47  ENSURE(p.Contains(uintptr_t(p1)));
48  ENSURE(p.RemainingObjects() == initialSpace-1);
49  ENSURE(p.Contains(uintptr_t(p1)+1));
50  ENSURE(p.Contains(uintptr_t(p1)+sizeof(double)-1));
51  ENSURE(!p.Contains(uintptr_t(p1)-1));
52  ENSURE(!p.Contains(uintptr_t(p1)+sizeof(double)));
53  if(p.RemainingObjects() == 0)
54  ENSURE(p.Allocate() == 0); // full
55  else
56  ENSURE(p.Allocate() != 0); // can still expand
57  p.DeallocateAll();
58  ENSURE(!p.Contains(uintptr_t(p1)));
59 
60  p1 = p.Allocate();
61  ENSURE(p1 != 0);
62  ENSURE(p.Contains(uintptr_t(p1)));
63  ENSURE(p.RemainingObjects() == initialSpace-1);
64  double* p2 = p.Allocate();
65  ENSURE(p2 != 0);
66  ENSURE(p.Contains(uintptr_t(p2)));
67  ENSURE(p.RemainingObjects() == initialSpace-2);
68  ENSURE(p2 == (double*)(uintptr_t(p1)+sizeof(double)));
69  if(p.RemainingObjects() == 0)
70  ENSURE(p.Allocate() == 0); // full
71  else
72  ENSURE(p.Allocate() != 0); // can still expand
73  }
74 };
75 
76 void TestPool()
77 {
78  ForEachStorage<BasicPoolTest>();
79 }
80 
81 } // namespace Allocators
82 
83 
84 TIMER_ADD_CLIENT(tc_pool_alloc);
85 
86 Status pool_create(Pool* p, size_t max_size, size_t el_size)
87 {
88  if(el_size == POOL_VARIABLE_ALLOCS)
89  p->el_size = 0;
90  else
91  p->el_size = Align<allocationAlignment>(el_size);
93  RETURN_STATUS_IF_ERR(da_alloc(&p->da, max_size));
94  return INFO::OK;
95 }
96 
97 
99 {
100  // don't be picky and complain if the freelist isn't empty;
101  // we don't care since it's all part of the da anyway.
102  // however, zero it to prevent further allocs from succeeding.
104  return da_free(&p->da);
105 }
106 
107 
108 bool pool_contains(const Pool* p, void* el)
109 {
110  // outside of our range
111  if(!(p->da.base <= el && el < p->da.base+p->da.pos))
112  return false;
113  // sanity check: it should be aligned (if pool has fixed-size elements)
114  if(p->el_size)
115  ENSURE((uintptr_t)((u8*)el - p->da.base) % p->el_size == 0);
116  return true;
117 }
118 
119 
120 void* pool_alloc(Pool* p, size_t size)
121 {
122  TIMER_ACCRUE(tc_pool_alloc);
123  // if pool allows variable sizes, go with the size parameter,
124  // otherwise the pool el_size setting.
125  const size_t el_size = p->el_size? p->el_size : Align<allocationAlignment>(size);
126  ASSERT(el_size != 0);
127 
128  // note: freelist is always empty in pools with variable-sized elements
129  // because they disallow pool_free.
130  void* el = mem_freelist_Detach(p->freelist);
131  if(!el) // freelist empty, need to allocate a new entry
132  {
133  // expand, if necessary
134  if(da_reserve(&p->da, el_size) < 0)
135  return 0;
136 
137  el = p->da.base + p->da.pos;
138  p->da.pos += el_size;
139  }
140 
141  ASSERT(pool_contains(p, el)); // paranoia
142  return el;
143 }
144 
145 
146 void pool_free(Pool* p, void* el)
147 {
148  // only allowed to free items if we were initialized with
149  // fixed el_size. (this avoids having to pass el_size here and
150  // check if requested_size matches that when allocating)
151  if(p->el_size == 0)
152  {
153  DEBUG_WARN_ERR(ERR::LOGIC); // cannot free variable-size items
154  return;
155  }
156 
157  if(pool_contains(p, el))
159  else
160  DEBUG_WARN_ERR(ERR::LOGIC); // invalid pointer (not in pool)
161 }
162 
163 
165 {
167 
168  // must be reset before da_set_size or CHECK_DA will complain.
169  p->da.pos = 0;
170 
171  da_set_size(&p->da, 0);
172 }
173 
175 {
176  return p->da.cur_size;
177 }
#define u8
Definition: types.h:39
const Status LOGIC
Definition: status.h:409
const Status OK
Definition: status.h:386
void pool_free(Pool *p, void *el)
Make a fixed-size element available for reuse in the given Pool.
Definition: pool.cpp:146
void * pool_alloc(Pool *p, size_t size)
Dole out memory from the pool.
Definition: pool.cpp:120
#define ASSERT(expr)
same as ENSURE in debug mode, does nothing in release mode.
Definition: debug.h:310
void * freelist
pointer to freelist (opaque); see freelist_*.
Definition: pool.h:128
size_t pool_committed(Pool *p)
Return the number of bytes committed in the pool&#39;s backing array.
Definition: pool.cpp:174
void DeallocateAll()
Definition: pool.h:80
Status pool_create(Pool *p, size_t max_size, size_t el_size)
Ready Pool for use.
Definition: pool.cpp:86
static void * mem_freelist_Detach(void *&freelist)
Definition: freelist.h:53
#define TIMER_ACCRUE(client)
Measure the time taken to execute code up until end of the current scope; bill it to the given TimerC...
Definition: timer.h:389
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
size_t RemainingObjects()
Definition: pool.h:57
u8 * base
Definition: dynarray.h:41
allocator design parameters:
Definition: pool.h:44
Status da_set_size(DynArray *da, size_t new_size)
expand or shrink the array: changes the amount of currently committed (i.e.
Definition: dynarray.cpp:93
const size_t POOL_VARIABLE_ALLOCS
pass as pool_create&#39;s &lt;el_size&gt; param to indicate variable-sized allocs are required (see below)...
Definition: pool.h:135
void operator()() const
Definition: pool.cpp:41
bool Contains(uintptr_t address) const
Definition: pool.h:87
i64 Status
Error handling system.
Definition: status.h:171
allocator design parameters:
Definition: pool.h:114
size_t pos
Definition: dynarray.h:46
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:331
DynArray da
Definition: pool.h:116
#define TIMER_ADD_CLIENT(id)
&quot;allocate&quot; a new TimerClient that will keep track of the total time billed to it, along with a descri...
Definition: timer.h:308
size_t el_size
size of elements.
Definition: pool.h:122
void pool_free_all(Pool *p)
&quot;free&quot; all user allocations that ensued from the given Pool.
Definition: pool.cpp:164
void TestPool()
Definition: pool.cpp:76
Status da_free(DynArray *da)
free all memory (address space + physical) that constitutes the given array.
Definition: dynarray.cpp:80
Status pool_destroy(Pool *p)
free all memory (address space + physical) that constitutes the given Pool.
Definition: pool.cpp:98
Status da_reserve(DynArray *da, size_t size)
Make sure at least &lt;size&gt; bytes starting at da-&gt;pos are committed and ready for use.
Definition: dynarray.cpp:130
Status da_alloc(DynArray *da, size_t max_size)
ready the DynArray object for use.
Definition: dynarray.cpp:61
size_t cur_size
reserved
Definition: dynarray.h:43
void * mem_freelist_Sentinel()
Definition: freelist.cpp:26
T * Allocate()
Definition: pool.h:62
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276
bool pool_contains(const Pool *p, void *el)
indicate whether a pointer was allocated from the given pool.
Definition: pool.cpp:108
static void mem_freelist_AddToFront(void *&freelist, void *el)
Definition: freelist.h:42