summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-08-30 16:48:36 +0000
committerThomas Martitz <kugel@rockbox.org>2011-08-30 16:48:36 +0000
commit42f10e04df42ab19aac74f82a6f113ee29e2012b (patch)
treecf0561936fd8e22bc95b38a0575a078f7039acfa
parent456170afdf8eb9c43abe7580a3b522c934273a1e (diff)
downloadrockbox-42f10e04df42ab19aac74f82a6f113ee29e2012b.tar.gz
rockbox-42f10e04df42ab19aac74f82a6f113ee29e2012b.zip
Remove buflib from the pluginlib and use the core one.
buflib_get_data() isn't inlined for plugins anymore, but can be if really needed. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30387 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.c13
-rw-r--r--apps/plugin.h18
-rw-r--r--apps/plugins/lib/SOURCES1
-rw-r--r--apps/plugins/lib/buflib.c349
-rw-r--r--apps/plugins/lib/buflib.h58
-rw-r--r--apps/plugins/pictureflow/pictureflow.c17
6 files changed, 39 insertions, 417 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index 43d9e03acf..422749b533 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -791,6 +791,19 @@ static const struct plugin_api rockbox_api = {
791 the API gets incompatible */ 791 the API gets incompatible */
792 tree_get_entries, 792 tree_get_entries,
793 tree_get_entry_at, 793 tree_get_entry_at,
794
795 /* the buflib memory management library */
796 buflib_init,
797 buflib_available,
798 buflib_alloc,
799 buflib_alloc_ex,
800 buflib_alloc_maximum,
801 buflib_buffer_in,
802 buflib_buffer_out,
803 buflib_free,
804 buflib_shrink,
805 buflib_get_data,
806 buflib_get_name,
794}; 807};
795 808
796int plugin_load(const char* plugin, const void* parameter) 809int plugin_load(const char* plugin, const void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 9bfe3fa16d..d566a5dc13 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -91,6 +91,7 @@ void* plugin_get_buffer(size_t *buffer_size);
91#include "list.h" 91#include "list.h"
92#include "tree.h" 92#include "tree.h"
93#include "color_picker.h" 93#include "color_picker.h"
94#include "buflib.h"
94#include "buffering.h" 95#include "buffering.h"
95#include "tagcache.h" 96#include "tagcache.h"
96#include "viewport.h" 97#include "viewport.h"
@@ -928,6 +929,23 @@ struct plugin_api {
928 the API gets incompatible */ 929 the API gets incompatible */
929 struct entry* (*tree_get_entries)(struct tree_context* t); 930 struct entry* (*tree_get_entries)(struct tree_context* t);
930 struct entry* (*tree_get_entry_at)(struct tree_context* t, int index); 931 struct entry* (*tree_get_entry_at)(struct tree_context* t, int index);
932
933 /* the buflib memory management library */
934 void (*buflib_init)(struct buflib_context* ctx, void* buf, size_t size);
935 size_t (*buflib_available)(struct buflib_context* ctx);
936 int (*buflib_alloc)(struct buflib_context* ctx, size_t size);
937 int (*buflib_alloc_ex)(struct buflib_context* ctx, size_t size,
938 const char* name, struct buflib_callbacks *ops);
939 int (*buflib_alloc_maximum)(struct buflib_context* ctx, const char* name,
940 size_t* size, struct buflib_callbacks *ops);
941 void (*buflib_buffer_in)(struct buflib_context* ctx, int size);
942 void* (*buflib_buffer_out)(struct buflib_context* ctx, size_t* size);
943 int (*buflib_free)(struct buflib_context* ctx, int handle);
944 bool (*buflib_shrink)(struct buflib_context* ctx, int handle,
945 void* new_start, size_t new_size);
946 void* (*buflib_get_data)(struct buflib_context* ctx, int handle);
947 const char* (*buflib_get_name)(struct buflib_context* ctx, int handle);
948
931}; 949};
932 950
933/* plugin header */ 951/* plugin header */
diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES
index 6f17c70b90..2c0fc2a611 100644
--- a/apps/plugins/lib/SOURCES
+++ b/apps/plugins/lib/SOURCES
@@ -7,7 +7,6 @@ configfile.c
7fixedpoint.c 7fixedpoint.c
8playback_control.c 8playback_control.c
9rgb_hsv.c 9rgb_hsv.c
10buflib.c
11highscore.c 10highscore.c
12simple_viewer.c 11simple_viewer.c
13display_text.c 12display_text.c
diff --git a/apps/plugins/lib/buflib.c b/apps/plugins/lib/buflib.c
deleted file mode 100644
index 930e49d02e..0000000000
--- a/apps/plugins/lib/buflib.c
+++ /dev/null
@@ -1,349 +0,0 @@
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*
16* This program is free software; you can redistribute it and/or
17* modify it under the terms of the GNU General Public License
18* as published by the Free Software Foundation; either version 2
19* of the License, or (at your option) any later version.
20*
21* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22* KIND, either express or implied.
23*
24****************************************************************************/
25
26#include <stdlib.h> /* for abs() */
27#include "buflib.h"
28/* The main goal of this design is fast fetching of the pointer for a handle.
29 * For that reason, the handles are stored in a table at the end of the buffer
30 * with a fixed address, so that returning the pointer for a handle is a simple
31 * table lookup. To reduce the frequency with which allocated blocks will need
32 * to be moved to free space, allocations grow up in address from the start of
33 * the buffer. The buffer is treated as an array of union buflib_data. Blocks
34 * start with a length marker, which is included in their length. Free blocks
35 * are marked by negative length, allocated ones use the second buflib_data in
36 * the block to store a pointer to their handle table entry, so that it can be
37 * quickly found and updated during compaction. The allocator functions are
38 * passed a context struct so that two allocators can be run, for example, one
39 * per core may be used, with convenience wrappers for the single-allocator
40 * case that use a predefined context.
41 */
42
43/* Initialize buffer manager */
44void
45buflib_init(struct buflib_context *ctx, void *buf, size_t size)
46{
47 union buflib_data *bd_buf = buf;
48
49 /* Align on sizeof(buflib_data), to prevent unaligned access */
50 ALIGN_BUFFER(bd_buf, size, sizeof(union buflib_data));
51 size /= sizeof(union buflib_data);
52 /* The handle table is initialized with no entries */
53 ctx->handle_table = bd_buf + size;
54 ctx->last_handle = bd_buf + size;
55 ctx->first_free_handle = bd_buf + size - 1;
56 ctx->first_free_block = bd_buf;
57 ctx->buf_start = bd_buf;
58 /* A marker is needed for the end of allocated data, to make sure that it
59 * does not collide with the handle table, and to detect end-of-buffer.
60 */
61 ctx->alloc_end = bd_buf;
62 ctx->compact = true;
63}
64
65/* Allocate a new handle, returning 0 on failure */
66static inline
67union buflib_data* handle_alloc(struct buflib_context *ctx)
68{
69 union buflib_data *handle;
70 /* first_free_handle is a lower bound on free handles, work through the
71 * table from there until a handle containing NULL is found, or the end
72 * of the table is reached.
73 */
74 for (handle = ctx->first_free_handle; handle >= ctx->last_handle; handle--)
75 if (!handle->ptr)
76 break;
77 /* If the search went past the end of the table, it means we need to extend
78 * the table to get a new handle.
79 */
80 if (handle < ctx->last_handle)
81 {
82 if (handle >= ctx->alloc_end)
83 ctx->last_handle--;
84 else
85 return NULL;
86 }
87 handle->val = -1;
88 return handle;
89}
90
91/* Free one handle, shrinking the handle table if it's the last one */
92static inline
93void handle_free(struct buflib_context *ctx, union buflib_data *handle)
94{
95 handle->ptr = 0;
96 /* Update free handle lower bound if this handle has a lower index than the
97 * old one.
98 */
99 if (handle > ctx->first_free_handle)
100 ctx->first_free_handle = handle;
101 if (handle == ctx->last_handle)
102 ctx->last_handle++;
103 else
104 ctx->compact = false;
105}
106
107/* Shrink the handle table, returning true if its size was reduced, false if
108 * not
109 */
110static inline
111bool
112handle_table_shrink(struct buflib_context *ctx)
113{
114 bool rv;
115 union buflib_data *handle;
116 for (handle = ctx->last_handle; !(handle->ptr); handle++);
117 if (handle > ctx->first_free_handle)
118 ctx->first_free_handle = handle - 1;
119 rv = handle == ctx->last_handle;
120 ctx->last_handle = handle;
121 return rv;
122}
123
124/* Compact allocations and handle table, adjusting handle pointers as needed.
125 * Return true if any space was freed or consolidated, false otherwise.
126 */
127static bool
128buflib_compact(struct buflib_context *ctx)
129{
130 union buflib_data *block = ctx->first_free_block, *new_block;
131 int shift = 0, len;
132 /* Store the results of attempting to shrink the handle table */
133 bool ret = handle_table_shrink(ctx);
134 for(; block != ctx->alloc_end; block += len)
135 {
136 len = block->val;
137 /* This block is free, add its length to the shift value */
138 if (len < 0)
139 {
140 shift += len;
141 len = -len;
142 continue;
143 }
144 /* If shift is non-zero, it represents the number of places to move
145 * blocks down in memory. Calculate the new address for this block,
146 * update its entry in the handle table, and then move its contents.
147 */
148 if (shift)
149 {
150 new_block = block + shift;
151 block[1].ptr->ptr = new_block + 2;
152 rb->memmove(new_block, block, len * sizeof(union buflib_data));
153 }
154 }
155 /* Move the end-of-allocation mark, and return true if any new space has
156 * been freed.
157 */
158 ctx->alloc_end += shift;
159 ctx->first_free_block = ctx->alloc_end;
160 ctx->compact = true;
161 return ret || shift;
162}
163
164/* Shift buffered items by size units, and update handle pointers. The shift
165 * value must be determined to be safe *before* calling.
166 */
167static void
168buflib_buffer_shift(struct buflib_context *ctx, int shift)
169{
170 rb->memmove(ctx->buf_start + shift, ctx->buf_start,
171 (ctx->alloc_end - ctx->buf_start) * sizeof(union buflib_data));
172 union buflib_data *ptr;
173 for (ptr = ctx->last_handle; ptr < ctx->handle_table; ptr++)
174 if (ptr->ptr)
175 ptr->ptr += shift;
176 ctx->first_free_block += shift;
177 ctx->buf_start += shift;
178 ctx->alloc_end += shift;
179}
180
181/* Shift buffered items up by size bytes, or as many as possible if size == 0.
182 * Set size to the number of bytes freed.
183 */
184void*
185buflib_buffer_out(struct buflib_context *ctx, size_t *size)
186{
187 if (!ctx->compact)
188 buflib_compact(ctx);
189 size_t avail = ctx->last_handle - ctx->alloc_end;
190 size_t avail_b = avail * sizeof(union buflib_data);
191 if (*size && *size < avail_b)
192 {
193 avail = (*size + sizeof(union buflib_data) - 1)
194 / sizeof(union buflib_data);
195 avail_b = avail * sizeof(union buflib_data);
196 }
197 *size = avail_b;
198 void *ret = ctx->buf_start;
199 buflib_buffer_shift(ctx, avail);
200 return ret;
201}
202
203/* Shift buffered items down by size bytes */
204void
205buflib_buffer_in(struct buflib_context *ctx, int size)
206{
207 size /= sizeof(union buflib_data);
208 buflib_buffer_shift(ctx, -size);
209}
210
211/* Allocate a buffer of size bytes, returning a handle for it */
212int
213buflib_alloc(struct buflib_context *ctx, size_t size)
214{
215 union buflib_data *handle, *block;
216 bool last = false;
217 /* This really is assigned a value before use */
218 int block_len;
219 size = (size + sizeof(union buflib_data) - 1) /
220 sizeof(union buflib_data) + 2;
221handle_alloc:
222 handle = handle_alloc(ctx);
223 if (!handle)
224 {
225 /* If allocation has failed, and compaction has succeded, it may be
226 * possible to get a handle by trying again.
227 */
228 if (!ctx->compact && buflib_compact(ctx))
229 goto handle_alloc;
230 else
231 return 0;
232 }
233
234buffer_alloc:
235 for (block = ctx->first_free_block;; block += block_len)
236 {
237 /* If the last used block extends all the way to the handle table, the
238 * block "after" it doesn't have a header. Because of this, it's easier
239 * to always find the end of allocation by saving a pointer, and always
240 * calculate the free space at the end by comparing it to the
241 * last_handle pointer.
242 */
243 if(block == ctx->alloc_end)
244 {
245 last = true;
246 block_len = ctx->last_handle - block;
247 if ((size_t)block_len < size)
248 block = NULL;
249 break;
250 }
251 block_len = block->val;
252 /* blocks with positive length are already allocated. */
253 if(block_len > 0)
254 continue;
255 block_len = -block_len;
256 /* The search is first-fit, any fragmentation this causes will be
257 * handled at compaction.
258 */
259 if ((size_t)block_len >= size)
260 break;
261 }
262 if (!block)
263 {
264 /* Try compacting if allocation failed, but only if the handle
265 * allocation did not trigger compaction already, since there will
266 * be no further gain.
267 */
268 if (!ctx->compact && buflib_compact(ctx))
269 {
270 goto buffer_alloc;
271 } else {
272 handle->val=1;
273 handle_free(ctx, handle);
274 return 0;
275 }
276 }
277
278 /* Set up the allocated block, by marking the size allocated, and storing
279 * a pointer to the handle.
280 */
281 block->val = size;
282 block[1].ptr = handle;
283 handle->ptr = block + 2;
284 /* If we have just taken the first free block, the next allocation search
285 * can save some time by starting after this block.
286 */
287 if (block == ctx->first_free_block)
288 ctx->first_free_block += size;
289 block += size;
290 /* alloc_end must be kept current if we're taking the last block. */
291 if (last)
292 ctx->alloc_end = block;
293 /* Only free blocks *before* alloc_end have tagged length. */
294 else if ((size_t)block_len > size)
295 block->val = size - block_len;
296 /* Return the handle index as a positive integer. */
297 return ctx->handle_table - handle;
298}
299
300/* Free the buffer associated with handle_num. */
301void
302buflib_free(struct buflib_context *ctx, int handle_num)
303{
304 union buflib_data *handle = ctx->handle_table - handle_num,
305 *freed_block = handle->ptr - 2,
306 *block = ctx->first_free_block,
307 *next_block = block;
308 /* We need to find the block before the current one, to see if it is free
309 * and can be merged with this one.
310 */
311 while (next_block < freed_block)
312 {
313 block = next_block;
314 next_block += abs(block->val);
315 }
316 /* If next_block == block, the above loop didn't go anywhere. If it did,
317 * and the block before this one is empty, we can combine them.
318 */
319 if (next_block == freed_block && next_block != block && block->val < 0)
320 block->val -= freed_block->val;
321 /* Otherwise, set block to the newly-freed block, and mark it free, before
322 * continuing on, since the code below exects block to point to a free
323 * block which may have free space after it.
324 */
325 else
326 {
327 block = freed_block;
328 block->val = -block->val;
329 }
330 next_block = block - block->val;
331 /* Check if we are merging with the free space at alloc_end. */
332 if (next_block == ctx->alloc_end)
333 ctx->alloc_end = block;
334 /* Otherwise, the next block might still be a "normal" free block, and the
335 * mid-allocation free means that the buffer is no longer compact.
336 */
337 else {
338 ctx->compact = false;
339 if (next_block->val < 0)
340 block->val += next_block->val;
341 }
342 handle_free(ctx, handle);
343 handle->ptr = NULL;
344 /* If this block is before first_free_block, it becomes the new starting
345 * point for free-block search.
346 */
347 if (block < ctx->first_free_block)
348 ctx->first_free_block = block;
349}
diff --git a/apps/plugins/lib/buflib.h b/apps/plugins/lib/buflib.h
deleted file mode 100644
index 47ad57f526..0000000000
--- a/apps/plugins/lib/buflib.h
+++ /dev/null
@@ -1,58 +0,0 @@
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*
16* This program is free software; you can redistribute it and/or
17* modify it under the terms of the GNU General Public License
18* as published by the Free Software Foundation; either version 2
19* of the License, or (at your option) any later version.
20*
21* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22* KIND, either express or implied.
23*
24****************************************************************************/
25
26#ifndef _BUFLIB_H_
27#include <plugin.h>
28
29union buflib_data
30{
31 intptr_t val;
32 union buflib_data *ptr;
33};
34
35struct buflib_context
36{
37 union buflib_data *handle_table;
38 union buflib_data *first_free_handle;
39 union buflib_data *last_handle;
40 union buflib_data *first_free_block;
41 union buflib_data *buf_start;
42 union buflib_data *alloc_end;
43 bool compact;
44};
45
46void buflib_init(struct buflib_context *context, void *buf, size_t size);
47int buflib_alloc(struct buflib_context *context, size_t size);
48void buflib_free(struct buflib_context *context, int handle);
49void* buflib_buffer_out(struct buflib_context *ctx, size_t *size);
50void buflib_buffer_in(struct buflib_context *ctx, int size);
51
52
53
54static inline void* buflib_get_data(struct buflib_context *context, int handle)
55{
56 return (void*)(context->handle_table[-handle].ptr);
57}
58#endif
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index e93f2d2951..c13aca1a95 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -33,7 +33,6 @@
33#include "lib/grey.h" 33#include "lib/grey.h"
34#include "lib/mylcd.h" 34#include "lib/mylcd.h"
35#include "lib/feature_wrappers.h" 35#include "lib/feature_wrappers.h"
36#include "lib/buflib.h"
37 36
38 37
39 38
@@ -924,7 +923,7 @@ void create_track_index(const int slide_index)
924 int string_index = 0, track_num; 923 int string_index = 0, track_num;
925 int disc_num; 924 int disc_num;
926 size_t out = 0; 925 size_t out = 0;
927 track_names = (char *)buflib_buffer_out(&buf_ctx, &out); 926 track_names = rb->buflib_buffer_out(&buf_ctx, &out);
928 borrowed += out; 927 borrowed += out;
929 int avail = borrowed; 928 int avail = borrowed;
930 tracks = (struct track_data*)(track_names + borrowed); 929 tracks = (struct track_data*)(track_names + borrowed);
@@ -980,7 +979,7 @@ retry:
980 if (!free_slide_prio(0)) 979 if (!free_slide_prio(0))
981 goto fail; 980 goto fail;
982 out = 0; 981 out = 0;
983 buflib_buffer_out(&buf_ctx, &out); 982 rb->buflib_buffer_out(&buf_ctx, &out);
984 avail += out; 983 avail += out;
985 borrowed += out; 984 borrowed += out;
986 985
@@ -1457,7 +1456,7 @@ static inline void lla_insert_before(int *head, int i, int p)
1457static inline void free_slide(int i) 1456static inline void free_slide(int i)
1458{ 1457{
1459 if (cache[i].hid != empty_slide_hid) 1458 if (cache[i].hid != empty_slide_hid)
1460 buflib_free(&buf_ctx, cache[i].hid); 1459 rb->buflib_free(&buf_ctx, cache[i].hid);
1461 cache[i].index = -1; 1460 cache[i].index = -1;
1462 lla_pop_item(&cache_used, i); 1461 lla_pop_item(&cache_used, i);
1463 lla_insert_tail(&cache_free, i); 1462 lla_insert_tail(&cache_free, i);
@@ -1521,7 +1520,7 @@ int read_pfraw(char* filename, int prio)
1521 sizeof( pix_t ) * bmph.width * bmph.height; 1520 sizeof( pix_t ) * bmph.width * bmph.height;
1522 1521
1523 int hid; 1522 int hid;
1524 while (!(hid = buflib_alloc(&buf_ctx, size)) && free_slide_prio(prio)); 1523 while (!(hid = rb->buflib_alloc(&buf_ctx, size)) && free_slide_prio(prio));
1525 1524
1526 if (!hid) { 1525 if (!hid) {
1527 rb->close( fh ); 1526 rb->close( fh );
@@ -1529,7 +1528,7 @@ int read_pfraw(char* filename, int prio)
1529 } 1528 }
1530 1529
1531 rb->yield(); /* allow audio to play when fast scrolling */ 1530 rb->yield(); /* allow audio to play when fast scrolling */
1532 struct dim *bm = buflib_get_data(&buf_ctx, hid); 1531 struct dim *bm = rb->buflib_get_data(&buf_ctx, hid);
1533 1532
1534 bm->width = bmph.width; 1533 bm->width = bmph.width;
1535 bm->height = bmph.height; 1534 bm->height = bmph.height;
@@ -1694,7 +1693,7 @@ static inline struct dim *get_slide(const int hid)
1694 1693
1695 struct dim *bmp; 1694 struct dim *bmp;
1696 1695
1697 bmp = buflib_get_data(&buf_ctx, hid); 1696 bmp = rb->buflib_get_data(&buf_ctx, hid);
1698 1697
1699 return bmp; 1698 return bmp;
1700} 1699}
@@ -2697,7 +2696,7 @@ int main(void)
2697 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); 2696 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
2698 } 2697 }
2699 2698
2700 buflib_init(&buf_ctx, (void *)buf, buf_size); 2699 rb->buflib_init(&buf_ctx, (void *)buf, buf_size);
2701 2700
2702 if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0))) 2701 if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0)))
2703 { 2702 {
@@ -2832,7 +2831,7 @@ int main(void)
2832 case PF_BACK: 2831 case PF_BACK:
2833 if ( pf_state == pf_show_tracks ) 2832 if ( pf_state == pf_show_tracks )
2834 { 2833 {
2835 buflib_buffer_in(&buf_ctx, borrowed); 2834 rb->buflib_buffer_in(&buf_ctx, borrowed);
2836 borrowed = 0; 2835 borrowed = 0;
2837 track_index = -1; 2836 track_index = -1;
2838 pf_state = pf_cover_out; 2837 pf_state = pf_cover_out;