summaryrefslogtreecommitdiff
path: root/firmware/include
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-08-30 14:01:33 +0000
committerThomas Martitz <kugel@rockbox.org>2011-08-30 14:01:33 +0000
commitd0b72e25903574acb1cf9184a6052cdd646dbc37 (patch)
tree5be8db5ee00b2a727e4821cf51a5f7bcf3991073 /firmware/include
parentc940811ade7d99a0e0d414df7c6509672413684a (diff)
downloadrockbox-d0b72e25903574acb1cf9184a6052cdd646dbc37.tar.gz
rockbox-d0b72e25903574acb1cf9184a6052cdd646dbc37.zip
GSoC/Buflib: Add buflib memory alocator to the core.
The buflib memory allocator is handle based and can free and compact, move or resize memory on demand. This allows to effeciently allocate memory dynamically without an MMU, by avoiding fragmentation through memory compaction. This patch adds the buflib library to the core, along with convinience wrappers to omit the context parameter. Compaction is not yet enabled, but will be in a later patch. Therefore, this acts as a replacement for buffer_alloc/buffer_get_buffer() with the benifit of a debug menu. See buflib.h for some API documentation. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30380 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/include')
-rw-r--r--firmware/include/buflib.h319
-rw-r--r--firmware/include/core_alloc.h36
2 files changed, 355 insertions, 0 deletions
diff --git a/firmware/include/buflib.h b/firmware/include/buflib.h
new file mode 100644
index 0000000000..db7b5ec50a
--- /dev/null
+++ b/firmware/include/buflib.h
@@ -0,0 +1,319 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* This is a memory allocator designed to provide reasonable management of free
11* space and fast access to allocated data. More than one allocator can be used
12* at a time by initializing multiple contexts.
13*
14* Copyright (C) 2009 Andrew Mahone
15* Copyright (C) 2011 Thomas Martitz
16*
17* This program is free software; you can redistribute it and/or
18* modify it under the terms of the GNU General Public License
19* as published by the Free Software Foundation; either version 2
20* of the License, or (at your option) any later version.
21*
22* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23* KIND, either express or implied.
24*
25****************************************************************************/
26
27#ifndef _BUFLIB_H_
28#define _BUFLIB_H_
29#include <stdint.h>
30#include <stdbool.h>
31#include <string.h>
32
33/* enable single block debugging */
34#define BUFLIB_DEBUG_BLOCK_SINGLE
35
36union buflib_data
37{
38 intptr_t val;
39 char name[1]; /* actually a variable sized string */
40 struct buflib_callbacks* ops;
41 char* alloc;
42 union buflib_data *handle;
43};
44
45struct buflib_context
46{
47 union buflib_data *handle_table;
48 union buflib_data *first_free_handle;
49 union buflib_data *last_handle;
50 union buflib_data *first_free_block;
51 union buflib_data *buf_start;
52 union buflib_data *alloc_end;
53 bool compact;
54};
55
56/**
57 * Callbacks used by the buflib to inform allocation that compaction
58 * is happening (before data is moved)
59 *
60 * Note that buflib tries to move to satisfy new allocations before shrinking.
61 * So if you have something to resize try to do it outside of the callback.
62 *
63 * Regardless of the above, if the allocation is SHRINKABLE, but not
64 * MUST_NOT_MOVE buflib will move the allocation before even attempting to
65 * shrink.
66 */
67struct buflib_callbacks {
68 /**
69 * This is called before data is moved. Use this to fix up any cached
70 * pointers pointing to inside the allocation. The size is unchanged.
71 *
72 * This is not needed if you don't cache the data pointer (but always
73 * call buflib_get_data()) and don't pass pointer to the data to yielding
74 * functions.
75 *
76 * handle: The corresponding handle
77 * current: The current start of the allocation
78 * new: The new start of the allocation, after data movement
79 *
80 * Return: Return BUFLIB_CB_OK, or BUFLIB_CB_CANNOT_MOVE if movement
81 * is impossible at this moment.
82 *
83 * If NULL: this allocation must not be moved around by the buflib when
84 * compation occurs
85 */
86 int (*move_callback)(int handle, void* current, void* new);
87 /**
88 * This is called when the buflib desires to shrink a buffer
89 * in order to satisfy new allocation. This happens when buflib runs
90 * out of memory, e.g. because buflib_alloc_maximum() was called.
91 * Move data around as you need to make space and call core_shrink() as
92 * appropriate from within the callback to complete the shrink operation.
93 * buflib will not move data as part of shrinking.
94 *
95 * hint: bit mask containing hints on how shrinking is desired (see below)
96 * handle: The corresponding handle
97 * start: The old start of the allocation
98 *
99 * Return: Return BUFLIB_CB_OK, or BUFLIB_CB_CANNOT_SHRINK if shirinking
100 * is impossible at this moment.
101 *
102 * if NULL: this allocation cannot be resized.
103 * It is recommended that allocation that must not move are
104 * at least shrinkable
105 */
106 int (*shrink_callback)(int handle, unsigned hints, void* start, size_t old_size);
107};
108
109#define BUFLIB_SHRINK_POS_MASK ((1<<0|1<<1)<<30)
110#define BUFLIB_SHRINK_SIZE_MASK (~BUFLIB_SHRINK_POS_MASK)
111#define BUFLIB_SHRINK_POS_FRONT (1u<<31)
112#define BUFLIB_SHRINK_POS_BACK (1u<<30)
113
114/**
115 * Possible return values for the callbacks, some of them can cause
116 * compaction to fail and therefore new allocations to fail
117 */
118/* Everything alright */
119#define BUFLIB_CB_OK 0
120/* Tell buflib that moving failed. Buflib may retry to move at any point */
121#define BUFLIB_CB_CANNOT_MOVE 1
122/* Tell buflib that resizing failed, possibly future making allocations fail */
123#define BUFLIB_CB_CANNOT_SHRINK 1
124
125/**
126 * Initializes buflib with a caller allocated context instance and memory pool.
127 *
128 * The buflib_context instance needs to be passed to every other buflib
129 * function. It's should be considered opaque, even though it is not yet
130 * (that's to make inlining core_get_data() possible). The documentation
131 * of the other functions will not describe the context
132 * instance paramter further as it's obligatory.
133 *
134 * context: The new buflib instance to be initialized, allocated by the caller
135 * size: The size of the memory pool
136 */
137void buflib_init(struct buflib_context *context, void *buf, size_t size);
138
139
140/**
141 * Returns how many bytes left the buflib has to satisfy allocations.
142 *
143 * This function does not yet consider possible compaction so there might
144 * be more space left. This may change in the future.
145 *
146 * Returns: The number of bytes left in the memory pool.
147 */
148size_t buflib_available(struct buflib_context *ctx);
149
150
151/**
152 * Allocates memory from buflib's memory pool
153 *
154 * size: How many bytes to allocate
155 *
156 * Returns: An integer handle identifying this allocation
157 */
158int buflib_alloc(struct buflib_context *context, size_t size);
159
160
161/**
162 * Allocates memory from the buflib's memory pool with additional callbacks
163 * and flags
164 *
165 * name: A string identifier giving this allocation a name
166 * size: How many bytes to allocate
167 * ops: a struct with pointers to callback functions (see above)
168 *
169 * Returns: An integer handle identifying this allocation
170 */
171int buflib_alloc_ex(struct buflib_context *ctx, size_t size, const char *name,
172 struct buflib_callbacks *ops);
173
174
175/**
176 * Gets all available memory from buflib, for temporary use.
177 *
178 * Since this effectively makes all future allocations fail (unless
179 * another allocation is freed in the meantime), you should definitely provide
180 * a shrink callback if you plan to hold the buffer for a longer period. This
181 * will allow buflib to permit allocations by shrinking the buffer returned by
182 * this function.
183 *
184 * Note that this currently gives whatever buflib_available() returns. However,
185 * do not depend on this behavior, it may change.
186 *
187 * name: A string identifier giving this allocation a name
188 * size: The actual size will be returned into size
189 * ops: a struct with pointers to callback functions
190 *
191 * Returns: An integer handle identifying this allocation
192 */
193int buflib_alloc_maximum(struct buflib_context* ctx, const char* name,
194 size_t *size, struct buflib_callbacks *ops);
195
196/**
197 * Queries the data pointer for the given handle. It's actually a cheap
198 * operation, don't hesitate using it extensivly.
199 *
200 * Notice that you need to re-query after every direct or indirect yield(),
201 * because compaction can happen by other threads which may get your data
202 * moved around (or you can get notified about changes by callbacks,
203 * see further above).
204 *
205 * handle: The handle corresponding to the allocation
206 *
207 * Returns: The start pointer of the allocation
208 */
209static inline void* buflib_get_data(struct buflib_context *context, int handle)
210{
211 return (void*)(context->handle_table[-handle].alloc);
212}
213
214/**
215 * Shrink the memory allocation associated with the given handle
216 * Mainly intended to be used with the shrink callback, but it can also
217 * be called outside as well, e.g. to give back buffer space allocated
218 * with buflib_alloc_maximum().
219 *
220 * Note that you must move/copy data around yourself before calling this,
221 * buflib will not do this as part of shrinking.
222 *
223 * handle: The handle identifying this allocation
224 * new_start: the new start of the allocation
225 * new_size: the new size of the allocation
226 *
227 * Returns: true if shrinking was successful. Otherwise it returns false,
228 * without having modified memory.
229 *
230 */
231bool buflib_shrink(struct buflib_context *ctx, int handle, void* newstart, size_t new_size);
232
233/**
234 * Frees memory associated with the given handle
235 *
236 * Returns: 0 (to invalidate handles in one line)
237 */
238int buflib_free(struct buflib_context *context, int handle);
239
240/**
241 * Moves the underlying buflib buffer up by size bytes (as much as
242 * possible for size == 0) without moving the end. This effectively
243 * reduces the available space by taking away managable space from the
244 * front. This space is not available for new allocations anymore.
245 *
246 * To make space available in the front, everything is moved up.
247 * It does _NOT_ call the move callbacks
248 *
249 *
250 * size: size in bytes to move the buffer up (take away). The actual
251 * bytes moved is returned in this
252 * Returns: The new start of the underlying buflib buffer
253 */
254void* buflib_buffer_out(struct buflib_context *ctx, size_t *size);
255
256/**
257 * Moves the underlying buflib buffer down by size bytes without
258 * moving the end. This grows the buflib buffer by adding space to the front.
259 * The new bytes are available for new allocations.
260 *
261 * Everything is moved down, and the new free space will be in the middle.
262 * It does _NOT_ call the move callbacks.
263 *
264 * size: size in bytes to move the buffer down (new free space)
265 */
266void buflib_buffer_in(struct buflib_context *ctx, int size);
267
268/* debugging */
269
270/**
271 * Returns the name, as given to core_alloc() and core_allloc_ex(), of the
272 * allocation associated with the given handle
273 *
274 * handle: The handle indicating the allocation
275 *
276 * Returns: A pointer to the string identifier of the allocation
277 */
278const char* buflib_get_name(struct buflib_context *ctx, int handle);
279
280/**
281 * Prints an overview of all current allocations with the help
282 * of the passed printer helper
283 *
284 * This walks only the handle table and prints only valid allocations
285 *
286 * Only available if BUFLIB_DEBUG_BLOCKS is defined
287 */
288void buflib_print_allocs(struct buflib_context *ctx, void (*print)(int, const char*));
289
290/**
291 * Prints an overview of all blocks in the buflib buffer, allocated
292 * or unallocated, with the help pf the passted printer helper
293 *
294 * This walks the entire buffer and prints unallocated space also.
295 * The output is also different from buflib_print_allocs().
296 *
297 * Only available if BUFLIB_DEBUG_BLOCKS is defined
298 */
299void buflib_print_blocks(struct buflib_context *ctx, void (*print)(int, const char*));
300
301/**
302 * Gets the number of blocks in the entire buffer, allocated or unallocated
303 *
304 * Only available if BUFLIB_DEBUG_BLOCK_SIGNLE is defined
305 */
306int buflib_get_num_blocks(struct buflib_context *ctx);
307
308/**
309 * Print information about a single block as indicated by block_num
310 * into buf
311 *
312 * buflib_get_num_blocks() beforehand to get the total number of blocks,
313 * as passing an block_num higher than that is undefined
314 *
315 * Only available if BUFLIB_DEBUG_BLOCK_SIGNLE is defined
316 */
317void buflib_print_block_at(struct buflib_context *ctx, int block_num,
318 char* buf, size_t bufsize);
319#endif
diff --git a/firmware/include/core_alloc.h b/firmware/include/core_alloc.h
new file mode 100644
index 0000000000..f5206c9db9
--- /dev/null
+++ b/firmware/include/core_alloc.h
@@ -0,0 +1,36 @@
1
2#ifndef __CORE_ALLOC_H__
3#define __CORE_ALLOC_H__
4#include <string.h>
5#include <stdbool.h>
6#include "buflib.h"
7
8/* All functions below are wrappers for functions in buflib.h, except
9 * they have a predefined context
10 */
11void core_allocator_init(void);
12int core_alloc(const char* name, size_t size);
13int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks *ops);
14int core_alloc_maximum(const char* name, size_t *size, struct buflib_callbacks *ops);
15bool core_shrink(int handle, void* new_start, size_t new_size);
16int core_free(int handle);
17size_t core_available(void);
18
19/* DO NOT ADD wrappers for buflib_buffer_out/in. They do not call
20 * the move callbacks and are therefore unsafe in the core */
21
22#ifdef BUFLIB_DEBUG_BLOCKS
23void core_print_allocs(void (*print)(const char*));
24void core_print_blocks(void (*print)(const char*));
25#endif
26#ifdef BUFLIB_DEBUG_BLOCK_SINGLE
27int core_get_num_blocks(void);
28void core_print_block_at(int block_num, char* buf, size_t bufsize);
29#endif
30
31static inline void* core_get_data(int handle)
32{
33 extern struct buflib_context core_ctx;
34 return buflib_get_data(&core_ctx, handle);
35}
36#endif /* __CORE_ALLOC_H__ */