diff options
Diffstat (limited to 'firmware/chunk_alloc.c')
-rw-r--r-- | firmware/chunk_alloc.c | 125 |
1 files changed, 70 insertions, 55 deletions
diff --git a/firmware/chunk_alloc.c b/firmware/chunk_alloc.c index 85ad5d3489..30959e393d 100644 --- a/firmware/chunk_alloc.c +++ b/firmware/chunk_alloc.c | |||
@@ -40,17 +40,22 @@ | |||
40 | * offset / sizeof(data) or index * sizeof(data) to convert | 40 | * offset / sizeof(data) or index * sizeof(data) to convert |
41 | */ | 41 | */ |
42 | 42 | ||
43 | struct chunk | 43 | struct chunk_alloc |
44 | { | 44 | { |
45 | int handle; /* data handle of buflib allocated bytes */ | 45 | int handle; /* data handle of buflib allocated bytes */ |
46 | size_t max_start_offset; /* start of last allocation */ | 46 | size_t max_start_offset; /* start of last allocation */ |
47 | }; | 47 | }; |
48 | 48 | ||
49 | #define CHUNK_ARRSZ(n) (sizeof(struct chunk) * n) | 49 | #define CHUNK_ARRSZ(n) (sizeof(struct chunk_alloc) * n) |
50 | 50 | ||
51 | static struct chunk* get_chunk_array(struct buflib_context *ctx, int handle) | 51 | static struct chunk_alloc* get_chunk_array(struct buflib_context *ctx, int handle) |
52 | { | 52 | { |
53 | return (struct chunk*)buflib_get_data(ctx, handle); | 53 | return (struct chunk_alloc*)buflib_get_data_pinned(ctx, handle); |
54 | } | ||
55 | |||
56 | static void put_chunk_array(struct buflib_context *ctx, struct chunk_alloc *data) | ||
57 | { | ||
58 | buflib_put_data_pinned(ctx, data); | ||
54 | } | 59 | } |
55 | 60 | ||
56 | /* shrink or grow chunk allocation | 61 | /* shrink or grow chunk allocation |
@@ -63,8 +68,8 @@ bool chunk_realloc(struct chunk_alloc_header *hdr, | |||
63 | size_t chunk_size, size_t max_chunks) | 68 | size_t chunk_size, size_t max_chunks) |
64 | { | 69 | { |
65 | struct buflib_context *ctx = hdr->context; | 70 | struct buflib_context *ctx = hdr->context; |
66 | struct chunk *new_chunk = NULL; | 71 | struct chunk_alloc *new_chunk = NULL; |
67 | struct chunk *old_chunk; | 72 | struct chunk_alloc *old_chunk; |
68 | size_t min_chunk = 1; | 73 | size_t min_chunk = 1; |
69 | int new_handle = 0; | 74 | int new_handle = 0; |
70 | 75 | ||
@@ -83,10 +88,8 @@ bool chunk_realloc(struct chunk_alloc_header *hdr, | |||
83 | } | 88 | } |
84 | if (hdr->chunk_handle > 0) /* handle existing chunk */ | 89 | if (hdr->chunk_handle > 0) /* handle existing chunk */ |
85 | { | 90 | { |
86 | logf("%s %ld chunks (%ld bytes) => %ld chunks (%ld bytes)", __func__, | 91 | logf("%s %ld chunks => %ld chunks", __func__, hdr->count, max_chunks); |
87 | hdr->count, CHUNK_ARRSZ(hdr->count), max_chunks, CHUNK_ARRSZ(max_chunks)); | ||
88 | 92 | ||
89 | buflib_pin(ctx, hdr->chunk_handle); | ||
90 | old_chunk = get_chunk_array(ctx, hdr->chunk_handle); | 93 | old_chunk = get_chunk_array(ctx, hdr->chunk_handle); |
91 | 94 | ||
92 | if (new_chunk != NULL) /* copy any valid old chunks to new */ | 95 | if (new_chunk != NULL) /* copy any valid old chunks to new */ |
@@ -94,6 +97,7 @@ bool chunk_realloc(struct chunk_alloc_header *hdr, | |||
94 | min_chunk = MIN(max_chunks, hdr->current + 1); | 97 | min_chunk = MIN(max_chunks, hdr->current + 1); |
95 | logf("%s copying %ld chunks", __func__, min_chunk); | 98 | logf("%s copying %ld chunks", __func__, min_chunk); |
96 | memcpy(new_chunk, old_chunk, CHUNK_ARRSZ(min_chunk)); | 99 | memcpy(new_chunk, old_chunk, CHUNK_ARRSZ(min_chunk)); |
100 | put_chunk_array(ctx, new_chunk); | ||
97 | } | 101 | } |
98 | /* free any chunks that no longer fit */ | 102 | /* free any chunks that no longer fit */ |
99 | for (size_t i = max_chunks; i <= hdr->current; i++) | 103 | for (size_t i = max_chunks; i <= hdr->current; i++) |
@@ -101,7 +105,7 @@ bool chunk_realloc(struct chunk_alloc_header *hdr, | |||
101 | logf("%s discarding chunk[%ld]", __func__, i); | 105 | logf("%s discarding chunk[%ld]", __func__, i); |
102 | buflib_free(ctx, old_chunk[i].handle); | 106 | buflib_free(ctx, old_chunk[i].handle); |
103 | } | 107 | } |
104 | buflib_unpin(ctx, hdr->chunk_handle); | 108 | put_chunk_array(ctx, old_chunk); |
105 | 109 | ||
106 | if (max_chunks < hdr->count && max_chunks > 0) | 110 | if (max_chunks < hdr->count && max_chunks > 0) |
107 | { | 111 | { |
@@ -122,10 +126,9 @@ bool chunk_realloc(struct chunk_alloc_header *hdr, | |||
122 | } | 126 | } |
123 | else | 127 | else |
124 | { | 128 | { |
125 | logf("chunk_alloc_init %ld chunks (%ld bytes)", | 129 | logf("chunk_alloc_init %ld chunks", hdr->count); |
126 | hdr->count, (hdr->count)); | ||
127 | } | 130 | } |
128 | 131 | hdr->cached_chunk.handle = 0; /* reset last chunk to force new lookup */ | |
129 | hdr->chunk_handle = new_handle; | 132 | hdr->chunk_handle = new_handle; |
130 | hdr->chunk_size = chunk_size; | 133 | hdr->chunk_size = chunk_size; |
131 | hdr->count = max_chunks; | 134 | hdr->count = max_chunks; |
@@ -152,20 +155,16 @@ bool chunk_alloc_init(struct chunk_alloc_header *hdr, | |||
152 | size_t chunk_size, size_t max_chunks) | 155 | size_t chunk_size, size_t max_chunks) |
153 | { | 156 | { |
154 | /* initialize header */ | 157 | /* initialize header */ |
155 | hdr->chunk_handle = 0; | 158 | memset(hdr, 0, sizeof(struct chunk_alloc_header)); |
156 | hdr->chunk_bytes_total = 0; | ||
157 | hdr->chunk_bytes_free = 0; | ||
158 | hdr->current = 0; | ||
159 | hdr->context = ctx; | 159 | hdr->context = ctx; |
160 | hdr->count = 0; | ||
161 | 160 | ||
162 | return chunk_realloc(hdr, chunk_size, max_chunks); | 161 | return chunk_realloc(hdr, chunk_size, max_chunks); |
163 | } | 162 | } |
164 | 163 | ||
165 | /* shrink current chunk to size used */ | 164 | /* shrink current chunk to size used */ |
166 | static void finalize(struct chunk_alloc_header *hdr, struct chunk *chunk_array) | 165 | static void finalize(struct chunk_alloc_header *hdr, struct chunk_alloc *chunk_array) |
167 | { | 166 | { |
168 | /*Note calling functions check if chunk_bytes_free > 0*/ | 167 | /* Note calling functions check if chunk_bytes_free > 0 */ |
169 | size_t idx = hdr->current; | 168 | size_t idx = hdr->current; |
170 | if (idx >= hdr->count) | 169 | if (idx >= hdr->count) |
171 | return; | 170 | return; |
@@ -186,8 +185,10 @@ void chunk_alloc_finalize(struct chunk_alloc_header *hdr) | |||
186 | { | 185 | { |
187 | if (hdr->chunk_bytes_free > 0) | 186 | if (hdr->chunk_bytes_free > 0) |
188 | { | 187 | { |
189 | struct chunk *chunk = get_chunk_array(hdr->context, hdr->chunk_handle); | 188 | struct chunk_alloc *chunk; |
189 | chunk = get_chunk_array(hdr->context, hdr->chunk_handle); | ||
190 | finalize(hdr, chunk); | 190 | finalize(hdr, chunk); |
191 | put_chunk_array(hdr->context, chunk); | ||
191 | } | 192 | } |
192 | } | 193 | } |
193 | 194 | ||
@@ -197,19 +198,19 @@ void chunk_alloc_finalize(struct chunk_alloc_header *hdr) | |||
197 | */ | 198 | */ |
198 | size_t chunk_alloc(struct chunk_alloc_header *hdr, size_t size) | 199 | size_t chunk_alloc(struct chunk_alloc_header *hdr, size_t size) |
199 | { | 200 | { |
201 | size_t virtual_offset = CHUNK_ALLOC_INVALID; | ||
200 | size_t idx = hdr->current; | 202 | size_t idx = hdr->current; |
201 | int handle = hdr->chunk_handle; | 203 | int handle = hdr->chunk_handle; |
202 | struct buflib_context *ctx = hdr->context; | 204 | struct buflib_context *ctx = hdr->context; |
203 | 205 | ||
204 | buflib_pin(ctx, handle); | 206 | struct chunk_alloc *chunk = get_chunk_array(ctx, handle); |
205 | struct chunk *chunk = get_chunk_array(ctx, handle); | ||
206 | 207 | ||
207 | while (size > 0) | 208 | while (size > 0) |
208 | { | 209 | { |
209 | if (idx >= hdr->count) | 210 | if (idx >= hdr->count) |
210 | { | 211 | { |
211 | logf("%s Error OOM -- out of chunks", __func__); | 212 | logf("%s Error OOM -- out of chunks", __func__); |
212 | break; | 213 | break; /* Out of chunks */ |
213 | } | 214 | } |
214 | hdr->current = idx; | 215 | hdr->current = idx; |
215 | 216 | ||
@@ -222,7 +223,7 @@ size_t chunk_alloc(struct chunk_alloc_header *hdr, size_t size) | |||
222 | if (chunk[idx].handle <= 0) | 223 | if (chunk[idx].handle <= 0) |
223 | { | 224 | { |
224 | logf("%s Error OOM", __func__); | 225 | logf("%s Error OOM", __func__); |
225 | goto fail; /* OOM */ | 226 | break; /* OOM */ |
226 | } | 227 | } |
227 | 228 | ||
228 | hdr->chunk_bytes_total = new_alloc_size; | 229 | hdr->chunk_bytes_total = new_alloc_size; |
@@ -237,14 +238,17 @@ size_t chunk_alloc(struct chunk_alloc_header *hdr, size_t size) | |||
237 | 238 | ||
238 | if(size <= hdr->chunk_bytes_free) /* request will fit */ | 239 | if(size <= hdr->chunk_bytes_free) /* request will fit */ |
239 | { | 240 | { |
240 | size_t offset = chunk[idx].max_start_offset; | 241 | virtual_offset = chunk[idx].max_start_offset; |
241 | chunk[idx].max_start_offset += size; | 242 | chunk[idx].max_start_offset += size; |
242 | hdr->chunk_bytes_free -= size; | 243 | hdr->chunk_bytes_free -= size; |
244 | |||
245 | if (hdr->cached_chunk.handle == chunk[idx].handle) | ||
246 | hdr->cached_chunk.max_offset = chunk[idx].max_start_offset; | ||
247 | |||
243 | /*logf("%s hdr idx[%ld] offset[%ld] size: %ld", | 248 | /*logf("%s hdr idx[%ld] offset[%ld] size: %ld", |
244 | __func__, idx, offset, size);*/ | 249 | __func__, idx, offset, size);*/ |
245 | 250 | ||
246 | buflib_unpin(ctx, handle); | 251 | break; /* Success */ |
247 | return offset; | ||
248 | } | 252 | } |
249 | else if (hdr->chunk_bytes_free > 0) /* shrink the current chunk */ | 253 | else if (hdr->chunk_bytes_free > 0) /* shrink the current chunk */ |
250 | { | 254 | { |
@@ -252,26 +256,42 @@ size_t chunk_alloc(struct chunk_alloc_header *hdr, size_t size) | |||
252 | } | 256 | } |
253 | idx++; | 257 | idx++; |
254 | } | 258 | } |
255 | fail: | 259 | |
256 | buflib_unpin(ctx, handle); | 260 | put_chunk_array(ctx, chunk); |
257 | return CHUNK_ALLOC_INVALID; | 261 | return virtual_offset; |
258 | } | 262 | } |
259 | 263 | ||
260 | /* returns chunk idx given virtual offset */ | 264 | /* retrieves chunk given virtual offset |
261 | static size_t chunk_find_data_idx(struct chunk_alloc_header *hdr, | 265 | * returns actual offset |
262 | size_t offset, struct chunk **chunk) | 266 | */ |
267 | static size_t chunk_get_at_offset(struct chunk_alloc_header *hdr, size_t offset) | ||
263 | { | 268 | { |
264 | size_t idx; | 269 | if ((hdr->cached_chunk.handle > 0) |
265 | *chunk = get_chunk_array(hdr->context, hdr->chunk_handle); | 270 | && (offset >= hdr->cached_chunk.min_offset) |
266 | /*logf("%s search for offset[%ld]", __func__, offset);*/ | 271 | && (offset < hdr->cached_chunk.max_offset)) |
267 | for (idx = hdr->current; idx < hdr->count; idx--) | 272 | { |
273 | /* convert virtual offset to real internal offset */ | ||
274 | return offset - hdr->cached_chunk.min_offset; | ||
275 | } | ||
276 | |||
277 | /* chunk isn't cached perform new lookup */ | ||
278 | struct chunk_alloc *chunk = get_chunk_array(hdr->context, hdr->chunk_handle); | ||
279 | logf("%s search for offset[%ld]", __func__, offset); | ||
280 | for (size_t idx = hdr->current; idx < hdr->count; idx--) | ||
268 | { | 281 | { |
269 | if (offset < (*chunk)[idx].max_start_offset | 282 | size_t min_offset = (idx == 0 ? 0 : chunk[idx - 1].max_start_offset); |
270 | && (idx == 0 || offset >= (*chunk)[idx - 1].max_start_offset)) | 283 | if (offset < chunk[idx].max_start_offset && offset >= min_offset) |
271 | { | 284 | { |
272 | /*logf("%s found hdr idx[%ld] max offset[%ld]", | 285 | logf("%s found hdr idx[%ld] min offset[%ld] max offset[%ld]", |
273 | __func__, idx, (*chunk)[idx].max_start_offset);*/ | 286 | __func__, idx, min_offset, chunk[idx].max_start_offset); |
274 | return idx; | 287 | |
288 | /* store found chunk */ | ||
289 | hdr->cached_chunk.handle = chunk[idx].handle; | ||
290 | hdr->cached_chunk.max_offset = chunk[idx].max_start_offset; | ||
291 | hdr->cached_chunk.min_offset = min_offset; | ||
292 | put_chunk_array(hdr->context, chunk); | ||
293 | /* convert virtual offset to real internal offset */ | ||
294 | return offset - hdr->cached_chunk.min_offset; | ||
275 | } | 295 | } |
276 | } | 296 | } |
277 | panicf("%s Error offset %d does not exist", __func__, (unsigned int)offset); | 297 | panicf("%s Error offset %d does not exist", __func__, (unsigned int)offset); |
@@ -284,19 +304,14 @@ static size_t chunk_find_data_idx(struct chunk_alloc_header *hdr, | |||
284 | */ | 304 | */ |
285 | void* chunk_get_data(struct chunk_alloc_header *hdr, size_t offset) | 305 | void* chunk_get_data(struct chunk_alloc_header *hdr, size_t offset) |
286 | { | 306 | { |
287 | struct chunk *chunk; | 307 | size_t real = chunk_get_at_offset(hdr, offset); |
288 | size_t idx = chunk_find_data_idx(hdr, offset, &chunk); | 308 | logf("%s offset: %ld real: %ld", __func__, offset, real); |
289 | if (idx > 0) | 309 | return buflib_get_data_pinned(hdr->context, hdr->cached_chunk.handle) + real; |
290 | offset -= chunk[idx - 1].max_start_offset; | ||
291 | logf("%s adjusted offset: %ld", __func__, offset); | ||
292 | buflib_pin(hdr->context, chunk[idx].handle); | ||
293 | return buflib_get_data(hdr->context, chunk[idx].handle) + offset; | ||
294 | } | 310 | } |
295 | 311 | ||
296 | /* release a pinned buffer, chunk can't be moved till pin count == 0 */ | 312 | /* release a pinned buffer, chunk can't be moved till pin count == 0 */ |
297 | void chunk_put_data(struct chunk_alloc_header *hdr, size_t offset) | 313 | void chunk_put_data(struct chunk_alloc_header *hdr, void* data, size_t offset) |
298 | { | 314 | { |
299 | struct chunk *chunk; | 315 | size_t real = chunk_get_at_offset(hdr, offset); |
300 | size_t idx = chunk_find_data_idx(hdr, offset, &chunk); | 316 | buflib_put_data_pinned(hdr->context, data - real); |
301 | buflib_unpin(hdr->context, chunk[idx].handle); | ||
302 | } | 317 | } |