Browse Source

Implemented realloc(), and changed the semantics of malloc(0) to allow

for realloc(0) being a valid way to free memory.
tags/v0.9.3
Michael Brown 17 years ago
parent
commit
c4677c7e73
2 changed files with 80 additions and 15 deletions
  1. 79
    15
      src/core/malloc.c
  2. 1
    0
      src/include/malloc.h

+ 79
- 15
src/core/malloc.c View File

@@ -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
 /**

+ 1
- 0
src/include/malloc.h View File

@@ -11,6 +11,7 @@
11 11
 
12 12
 extern void * alloc_memblock ( size_t size, size_t align );
13 13
 extern void free_memblock ( void *ptr, size_t size );
14
+extern void * realloc ( void *old_ptr, size_t new_size );
14 15
 extern void * malloc ( size_t size );
15 16
 extern void free ( void *ptr );
16 17
 extern void mpopulate ( void *start, size_t len );

Loading…
Cancel
Save