|
@@ -49,6 +49,23 @@ struct autosized_block {
|
49
|
49
|
char data[0];
|
50
|
50
|
};
|
51
|
51
|
|
|
52
|
+/**
|
|
53
|
+ * Address for zero-length memory blocks
|
|
54
|
+ *
|
|
55
|
+ * @c malloc(0) or @c realloc(ptr,0) will return the special value @c
|
|
56
|
+ * NOWHERE. Calling @c free(NOWHERE) will have no effect.
|
|
57
|
+ *
|
|
58
|
+ * This is consistent with the ANSI C standards, which state that
|
|
59
|
+ * "either NULL or a pointer suitable to be passed to free()" must be
|
|
60
|
+ * returned in these cases. Using a special non-NULL value means that
|
|
61
|
+ * the caller can take a NULL return value to indicate failure,
|
|
62
|
+ * without first having to check for a requested size of zero.
|
|
63
|
+ *
|
|
64
|
+ * Code outside of malloc.c do not ever need to refer to the actual
|
|
65
|
+ * value of @c NOWHERE; this is an internal definition.
|
|
66
|
+ */
|
|
67
|
+#define NOWHERE ( ( void * ) ~( ( intptr_t ) 0 ) )
|
|
68
|
+
|
52
|
69
|
/** List of free memory blocks */
|
53
|
70
|
static LIST_HEAD ( free_blocks );
|
54
|
71
|
|
|
@@ -193,6 +210,66 @@ void free_memblock ( void *ptr, size_t size ) {
|
193
|
210
|
}
|
194
|
211
|
}
|
195
|
212
|
|
|
213
|
+/**
|
|
214
|
+ * Reallocate memory
|
|
215
|
+ *
|
|
216
|
+ * @v old_ptr Memory previously allocated by malloc(), or NULL
|
|
217
|
+ * @v new_size Requested size
|
|
218
|
+ * @ret new_ptr Allocated memory, or NULL
|
|
219
|
+ *
|
|
220
|
+ * Allocates memory with no particular alignment requirement. @c
|
|
221
|
+ * new_ptr will be aligned to at least a multiple of sizeof(void*).
|
|
222
|
+ * If @c old_ptr is non-NULL, then the contents of the newly allocated
|
|
223
|
+ * memory will be the same as the contents of the previously allocated
|
|
224
|
+ * memory, up to the minimum of the old and new sizes. The old memory
|
|
225
|
+ * will be freed.
|
|
226
|
+ *
|
|
227
|
+ * If allocation fails the previously allocated block is left
|
|
228
|
+ * untouched and NULL is returned.
|
|
229
|
+ *
|
|
230
|
+ * Calling realloc() with a new size of zero is a valid way to free a
|
|
231
|
+ * memory block.
|
|
232
|
+ */
|
|
233
|
+void * realloc ( void *old_ptr, size_t new_size ) {
|
|
234
|
+ struct autosized_block *old_block;
|
|
235
|
+ struct autosized_block *new_block;
|
|
236
|
+ size_t old_total_size;
|
|
237
|
+ size_t new_total_size;
|
|
238
|
+ size_t old_size;
|
|
239
|
+ void *new_ptr = NOWHERE;
|
|
240
|
+
|
|
241
|
+ /* Allocate new memory if necessary. If allocation fails,
|
|
242
|
+ * return without touching the old block.
|
|
243
|
+ */
|
|
244
|
+ if ( new_size ) {
|
|
245
|
+ new_total_size = ( new_size +
|
|
246
|
+ offsetof ( struct autosized_block, data ) );
|
|
247
|
+ new_block = alloc_memblock ( new_total_size, 1 );
|
|
248
|
+ if ( ! new_block )
|
|
249
|
+ return NULL;
|
|
250
|
+ new_block->size = new_total_size;
|
|
251
|
+ new_ptr = &new_block->data;
|
|
252
|
+ }
|
|
253
|
+
|
|
254
|
+ /* Copy across relevant part of the old data region (if any),
|
|
255
|
+ * then free it. Note that at this point either (a) new_ptr
|
|
256
|
+ * is valid, or (b) new_size is 0; either way, the memcpy() is
|
|
257
|
+ * valid.
|
|
258
|
+ */
|
|
259
|
+ if ( old_ptr && ( old_ptr != NOWHERE ) ) {
|
|
260
|
+ old_block = container_of ( old_ptr, struct autosized_block,
|
|
261
|
+ data );
|
|
262
|
+ old_total_size = old_block->size;
|
|
263
|
+ old_size = ( old_total_size -
|
|
264
|
+ offsetof ( struct autosized_block, data ) );
|
|
265
|
+ memcpy ( new_ptr, old_ptr,
|
|
266
|
+ ( ( old_size < new_size ) ? old_size : new_size ) );
|
|
267
|
+ free_memblock ( old_block, old_total_size );
|
|
268
|
+ }
|
|
269
|
+
|
|
270
|
+ return new_ptr;
|
|
271
|
+}
|
|
272
|
+
|
196
|
273
|
/**
|
197
|
274
|
* Allocate memory
|
198
|
275
|
*
|
|
@@ -203,15 +280,7 @@ void free_memblock ( void *ptr, size_t size ) {
|
203
|
280
|
* will be aligned to at least a multiple of sizeof(void*).
|
204
|
281
|
*/
|
205
|
282
|
void * malloc ( size_t size ) {
|
206
|
|
- size_t total_size;
|
207
|
|
- struct autosized_block *block;
|
208
|
|
-
|
209
|
|
- total_size = size + offsetof ( struct autosized_block, data );
|
210
|
|
- block = alloc_memblock ( total_size, 1 );
|
211
|
|
- if ( ! block )
|
212
|
|
- return NULL;
|
213
|
|
- block->size = total_size;
|
214
|
|
- return &block->data;
|
|
283
|
+ return realloc ( NULL, size );
|
215
|
284
|
}
|
216
|
285
|
|
217
|
286
|
/**
|
|
@@ -225,12 +294,7 @@ void * malloc ( size_t size ) {
|
225
|
294
|
* If @c ptr is NULL, no action is taken.
|
226
|
295
|
*/
|
227
|
296
|
void free ( void *ptr ) {
|
228
|
|
- struct autosized_block *block;
|
229
|
|
-
|
230
|
|
- if ( ptr ) {
|
231
|
|
- block = container_of ( ptr, struct autosized_block, data );
|
232
|
|
- free_memblock ( block, block->size );
|
233
|
|
- }
|
|
297
|
+ realloc ( ptr, 0 );
|
234
|
298
|
}
|
235
|
299
|
|
236
|
300
|
/**
|