X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Fmalloc.c;h=f6f803b9b6dc437a25876928679ab393176c086d;hb=fd2a5afa946474ba0839de0e9da238dbaecbd6a5;hp=0cb5f9d997def46ce1570b40eb5d9e1195216f3c;hpb=1d50ca8650fb96c13add16ef5659cc7aa6d4ab4b;p=pintos-anon diff --git a/src/threads/malloc.c b/src/threads/malloc.c index 0cb5f9d..f6f803b 100644 --- a/src/threads/malloc.c +++ b/src/threads/malloc.c @@ -5,9 +5,9 @@ #include #include #include -#include "threads/mmu.h" #include "threads/palloc.h" #include "threads/synch.h" +#include "threads/vaddr.h" /* A simple implementation of malloc(). @@ -57,7 +57,7 @@ struct arena /* Free block. */ struct block { - list_elem free_elem; /* Free list element. */ + struct list_elem free_elem; /* Free list element. */ }; /* Our set of descriptors. */ @@ -80,7 +80,7 @@ malloc_init (void) d->block_size = block_size; d->blocks_per_arena = (PGSIZE - sizeof (struct arena)) / block_size; list_init (&d->free_list); - lock_init (&d->lock, "malloc"); + lock_init (&d->lock); } } @@ -161,7 +161,7 @@ calloc (size_t a, size_t b) void *p; size_t size; - /* Calculate block size. */ + /* Calculate block size and make sure it fits in size_t. */ size = a * b; if (size < a || size < b) return NULL; @@ -174,53 +174,93 @@ calloc (size_t a, size_t b) return p; } -/* Frees block P, which must have been previously allocated with - malloc() or calloc(). */ -void -free (void *p) +/* Returns the number of bytes allocated for BLOCK. */ +static size_t +block_size (void *block) { - struct block *b; - struct arena *a; - struct desc *d; - - if (p == NULL) - return; + struct block *b = block; + struct arena *a = block_to_arena (b); + struct desc *d = a->desc; - b = p; - a = block_to_arena (b); - d = a->desc; + return d != NULL ? d->block_size : PGSIZE * a->free_cnt - pg_ofs (block); +} - if (d == NULL) +/* Attempts to resize OLD_BLOCK to NEW_SIZE bytes, possibly + moving it in the process. + If successful, returns the new block; on failure, returns a + null pointer. + A call with null OLD_BLOCK is equivalent to malloc(NEW_SIZE). + A call with zero NEW_SIZE is equivalent to free(OLD_BLOCK). */ +void * +realloc (void *old_block, size_t new_size) +{ + if (new_size == 0) + { + free (old_block); + return NULL; + } + else { - /* It's a big block. Free its pages. */ - palloc_free_multiple (a, a->free_cnt); - return; + void *new_block = malloc (new_size); + if (old_block != NULL && new_block != NULL) + { + size_t old_size = block_size (old_block); + size_t min_size = new_size < old_size ? new_size : old_size; + memcpy (new_block, old_block, min_size); + free (old_block); + } + return new_block; } +} + +/* Frees block P, which must have been previously allocated with + malloc(), calloc(), or realloc(). */ +void +free (void *p) +{ + if (p != NULL) + { + struct block *b = p; + struct arena *a = block_to_arena (b); + struct desc *d = a->desc; + + if (d != NULL) + { + /* It's a normal block. We handle it here. */ #ifndef NDEBUG - memset (b, 0xcc, d->block_size); + /* Clear the block to help detect use-after-free bugs. */ + memset (b, 0xcc, d->block_size); #endif - lock_acquire (&d->lock); + lock_acquire (&d->lock); - /* Add block to free list. */ - list_push_front (&d->free_list, &b->free_elem); + /* Add block to free list. */ + list_push_front (&d->free_list, &b->free_elem); - /* If the arena is now entirely unused, free it. */ - if (++a->free_cnt >= d->blocks_per_arena) - { - size_t i; + /* If the arena is now entirely unused, free it. */ + if (++a->free_cnt >= d->blocks_per_arena) + { + size_t i; - ASSERT (a->free_cnt == d->blocks_per_arena); - for (i = 0; i < d->blocks_per_arena; i++) + ASSERT (a->free_cnt == d->blocks_per_arena); + for (i = 0; i < d->blocks_per_arena; i++) + { + struct block *b = arena_to_block (a, i); + list_remove (&b->free_elem); + } + palloc_free_page (a); + } + + lock_release (&d->lock); + } + else { - struct block *b = arena_to_block (a, i); - list_remove (&b->free_elem); + /* It's a big block. Free its pages. */ + palloc_free_multiple (a, a->free_cnt); + return; } - palloc_free_page (a); } - - lock_release (&d->lock); } /* Returns the arena that block B is inside. */