1
/*
2
* \brief Generic allocator interface
3
* \author Norman Feske
4
* \date 2006-04-16
5
*/
6
7
/*
8
* Copyright (C) 2006-2013 Genode Labs GmbH
9
*
10
* This file is part of the Genode OS framework, which is distributed
11
* under the terms of the GNU General Public License version 2.
12
*/
13
14
#
ifndef _INCLUDE__BASE__ALLOCATOR_H_
15
#
define _INCLUDE__BASE__ALLOCATOR_H_
16
17
#
include <base/stdint.h>
18
#
include <base/exception.h>
19
20
namespace
Genode {
21
22
struct
Deallocator;
23
struct
Allocator;
24
struct
Range_allocator;
25
26
template
<
typename
T
,
typename
DEALLOC
>
void
destroy(
DEALLOC &&
dealloc
,
T *
obj
)
;
27
}
28
29
30
/**
31
* Deallocator interface
32
*/
33
struct
Genode::
Deallocator
34
{
35
/**
36
* Free block a previously allocated block
37
*/
38
virtual
void
free(
void *
addr
,
size_t
size
)
=
0
;
39
40
/**
41
* Return true if the size argument of `free` is required
42
*
43
* The generic `Allocator` interface requires the caller of `free`
44
* to supply a valid size argument but not all implementations make
45
* use of this argument. If this method returns false, it is safe
46
* to call `free` with an invalid size.
47
*
48
* Allocators that rely on the size argument must not be used for
49
* constructing objects whose constructors may throw exceptions.
50
* See the documentation of `operator delete(void *, Allocator *)`
51
* below for more details.
52
*/
53
virtual
bool
need_size_for_free(
)
const
=
0
;
54
}
;
55
56
57
struct
Genode::
Allocator :
Deallocator
58
{
59
/**
60
* Exception type
61
*/
62
class
Out_of_memory :
public
Exception
{
}
;
63
64
/**
65
* Destructor
66
*/
67
virtual
~
Allocator(
)
{
}
68
69
/**
70
* Allocate block
71
*
72
* \param size block size to allocate
73
* \param out_addr resulting pointer to the new block,
74
* undefined in the error case
75
* \return true on success
76
*/
77
virtual
bool
alloc(
size_t
size
,
void *
*
out_addr
)
=
0
;
78
79
/**
80
* Allocate typed block
81
*
82
* This template allocates a typed block returned as a pointer to
83
* a non-void type. By providing this method, we prevent the
84
* compiler from warning us about "dereferencing type-punned
85
* pointer will break strict-aliasing rules".
86
*/
87
template
<
typename
T
>
bool
alloc(
size_t
size
,
T *
*
out_addr
)
88
{
89
void *
addr =
0;
90
bool ret =
alloc(
size,
&
addr)
;
91
*
out_addr =
(
T *
)
addr;
92
return
ret
;
93
}
94
95
/**
96
* Return total amount of backing store consumed by the allocator
97
*/
98
virtual
size_t
consumed(
)
const
{
return
0
;
}
99
100
/**
101
* Return meta-data overhead per block
102
*/
103
virtual
size_t
overhead(
size_t
size
)
const
=
0
;
104
105
/**
106
* Allocate block and signal error as an exception
107
*
108
* \param size block size to allocate
109
* \return pointer to the new block
110
* \throw Out_of_memory
111
*/
112
void *
alloc(
size_t
size
)
113
{
114
void *
result =
0;
115
if
(
!
alloc(
size,
&
result)
)
116
throw
Out_of_memory(
)
;
117
118
return
result
;
119
}
120
}
;
121
122
123
struct
Genode::
Range_allocator :
Allocator
124
{
125
/**
126
* Destructor
127
*/
128
virtual
~
Range_allocator(
)
{
}
129
130
/**
131
* Add free address range to allocator
132
*/
133
virtual
int
add_range(
addr_t
base
,
size_t
size
)
=
0
;
134
135
/**
136
* Remove address range from allocator
137
*/
138
virtual
int
remove_range(
addr_t
base
,
size_t
size
)
=
0
;
139
140
/**
141
* Return value of allocation functons
142
*
143
* `OK` on success, or
144
* `OUT_OF_METADATA` if meta-data allocation failed, or
145
* `RANGE_CONFLICT` if no fitting address range is found
146
*/
147
struct
Alloc_return
148
{
149
enum
Value {
OK =
0
,
OUT_OF_METADATA =
-
1
,
RANGE_CONFLICT =
-
2
}
;
150
Value const
value;
151
Alloc_return(
Value
value
)
:
value(
value)
{
}
152
153
bool
is_ok(
)
const
{
return
value ==
OK
;
}
154
bool
is_error(
)
const
{
return
!
is_ok(
)
;
}
155
}
;
156
157
/**
158
* Allocate block
159
*
160
* \param size size of new block
161
* \param out_addr start address of new block,
162
* undefined in the error case
163
* \param align alignment of new block specified
164
* as the power of two
165
*/
166
virtual
Alloc_return
alloc_aligned(
size_t
size
,
void *
*
out_addr
,
int
align
=
0
,
addr_t
from
=
0
,
addr_t
to
=
~
0UL
)
=
0
;
167
168
/**
169
* Allocate block at address
170
*
171
* \param size size of new block
172
* \param addr desired address of block
173
*
174
* \return `ALLOC_OK` on success, or
175
* `OUT_OF_METADATA` if meta-data allocation failed, or
176
* `RANGE_CONFLICT` if specified range is occupied
177
*/
178
virtual
Alloc_return
alloc_addr(
size_t
size
,
addr_t
addr
)
=
0
;
179
180
/**
181
* Free a previously allocated block
182
*
183
* NOTE: We have to declare the `Allocator::free(void *)` method
184
* here as well to make the compiler happy. Otherwise the C++
185
* overload resolution would not find `Allocator::free(void *)`.
186
*/
187
virtual
void
free(
void *
addr
)
=
0
;
188
virtual
void
free(
void *
addr
,
size_t
size
)
=
0
;
189
190
/**
191
* Return the sum of available memory
192
*
193
* Note that the returned value is not neccessarily allocatable
194
* because the memory may be fragmented.
195
*/
196
virtual
size_t
avail(
)
const
=
0
;
197
198
/**
199
* Check if address is inside an allocated block
200
*
201
* \param addr address to check
202
*
203
* \return true if address is inside an allocated block, false
204
* otherwise
205
*/
206
virtual
bool
valid_addr(
addr_t
addr
)
const
=
0
;
207
}
;
208
209
210
void *
operator
new
(
Genode::
size_t
,
Genode::
Allocator *
)
;
211
void *
operator
new
[]
(
Genode::
size_t,
Genode::
Allocator *
)
;
212
213
void *
operator
new
(
Genode::
size_t
,
Genode::
Allocator &
)
;
214
void *
operator
new
[]
(
Genode::
size_t,
Genode::
Allocator &
)
;
215
216
217
/**
218
* Delete operator invoked when an exception occurs during the construction of
219
* a dynamically allocated object
220
*
221
* When an exception occurs during the construction of a dynamically allocated
222
* object, the C++ standard devises the automatic invocation of the global
223
* operator delete. When passing an allocator as argument to the new operator
224
* (the typical case for Genode), the compiler magically calls the operator
225
* delete taking the allocator type as second argument. This is how we end up
226
* here.
227
*
228
* There is one problem though: We get the pointer of the to-be-deleted object
229
* but not its size. But Genode`s `Allocator` interface requires the object
230
* size to be passed as argument to `Allocator::free()`.
231
*
232
* Even though in the general case, we cannot assume all `Allocator`
233
* implementations to remember the size of each allocated object, the commonly
234
* used `Heap`, `Sliced_heap`, `Allocator_avl`, and `Slab` do so and ignore the
235
* size argument. When using either of those allocators, we are fine. Otherwise
236
* we print a warning and pass the zero size argument anyway.
237
*
238
* :Warning: Never use an allocator that depends on the size argument of the
239
* `free()` method for the allocation of objects that may throw exceptions
240
* at their construction time!
241
*/
242
void
operator
delete
(
void *
,
Genode::
Deallocator *
)
;
243
void
operator
delete
(
void *
,
Genode::
Deallocator &
)
;
244
245
246
/**
247
* Destroy object
248
*
249
* For destroying an object, we need to specify the allocator that was used
250
* by the object. Because we cannot pass the allocator directly to the
251
* delete expression, we mimic the expression by using this template
252
* function. The function explicitly calls the object destructor and
253
* operator delete afterwards.
254
*
255
* For details see https://github.com/genodelabs/genode/issues/1030.
256
*
257
* \param T implicit object type
258
*
259
* \param dealloc reference or pointer to allocator from which the object
260
* was allocated
261
* \param obj object to destroy
262
*/
263
template
<
typename
T
,
typename
DEALLOC
>
264
void
Genode::
destroy(
DEALLOC &&
dealloc
,
T *
obj
)
265
{
266
if
(
!
obj)
267
return
;
268
269
/* call destructors */
270
obj->
~
T(
)
;
271
272
/*
273
* Free memory at the allocator
274
*
275
* We have to use the delete operator instead of just calling
276
* `dealloc.free` because the `obj` pointer might not always point to the
277
* begin of the allocated block:
278
*
279
* If `T` is the base class of another class `A`, `obj` may refer
280
* to an instance of `A`. In particular when `A` used multiple inheritance
281
* with `T` not being the first inhertited class, the pointer to the actual
282
* object differs from `obj`.
283
*
284
* Given the pointer to the base class `T`, however, the delete operator is
285
* magically (by the means of the information found in the vtable of `T`)
286
* able to determine the actual pointer to the instance of `A` and passes
287
* this pointer to `free`.
288
*/
289
operator
delete (
obj,
dealloc)
;
290
}
291
292
#
endif /* _INCLUDE__BASE__ALLOCATOR_H_ */