mm_malloc and related code
This commit is contained in:
parent
cedb5d607c
commit
aa8ffbba68
216
mm.c
Normal file
216
mm.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mm.h"
|
||||||
|
#include "memlib.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct boundary_tag {
|
||||||
|
int inuse:1;
|
||||||
|
int size:31;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FENCE is used for heap prologue/epilogue. */
|
||||||
|
const struct boundary_tag FENCE = {
|
||||||
|
.inuse = 1,
|
||||||
|
.size = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
struct block {
|
||||||
|
struct boundary_tag header;
|
||||||
|
char payload[0];
|
||||||
|
struct list_elem elem;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Basic constants and macros */
|
||||||
|
#define WSIZE sizeof(struct boundary_tag) /* Word and header/footer size (bytes) */
|
||||||
|
#define DSIZE 2*WSIZE
|
||||||
|
#define MIN_BLOCK_SIZE_WORDS 8 /* Minimum block size in words */
|
||||||
|
#define CHUNKSIZE (1<<10) /* Extend heap by this amount (words) */
|
||||||
|
|
||||||
|
#define NUM_LISTS 8 /* Number of free lists */
|
||||||
|
|
||||||
|
static inline size_t max(size_t x, size_t y) {
|
||||||
|
return x > y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static size_t align(size_t size) {
|
||||||
|
return (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct list free_lists[NUM_LISTS];
|
||||||
|
static size_t list_sizes[NUM_LISTS];
|
||||||
|
|
||||||
|
/* Function prototypes for internal helper routines */
|
||||||
|
static struct block *extend_heap(size_t words, int realloc);
|
||||||
|
static void place(struct block *blck, size_t asize);
|
||||||
|
static struct list* find_list(int not_empty, size_t size);
|
||||||
|
static struct block *find_fit(size_t num_words);
|
||||||
|
|
||||||
|
/* Return size of block is free */
|
||||||
|
static size_t blk_size(struct block *blk) {
|
||||||
|
return blk->header.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Given a block, obtain pointer to next block.
|
||||||
|
Not meaningful for right-most block. */
|
||||||
|
static struct block *next_blk(struct block *blk) {
|
||||||
|
assert(blk_size(blk) != 0);
|
||||||
|
return (struct block *)((void *)blk + WSIZE * blk->header.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a block, obtain its footer boundary tag */
|
||||||
|
static struct boundary_tag * get_footer(struct block *blk) {
|
||||||
|
return ((void *)blk + WSIZE * blk->header.size)
|
||||||
|
- sizeof(struct boundary_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set a block's size and inuse bit in header and footer */
|
||||||
|
static void set_header_and_footer(struct block *blk, int size, int inuse) {
|
||||||
|
blk->header.inuse = inuse;
|
||||||
|
blk->header.size = size;
|
||||||
|
* get_footer(blk) = blk->header; /* Copy header to footer */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Mark a block as used and set its size. */
|
||||||
|
static void set_block_used(struct block *blk, int size) {
|
||||||
|
set_header_and_footer(blk, size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Mark a block as free and set its size. */
|
||||||
|
static void set_block_free(struct block *blk, int size) {
|
||||||
|
set_header_and_footer(blk, size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The mm malloc routine returns a pointer to an allocated block payload of at
|
||||||
|
* least size bytes. The entire allocated block should lie within the heap region and should
|
||||||
|
* not overlap with any other allocated chunk.
|
||||||
|
*/
|
||||||
|
void *mm_malloc(size_t size) {
|
||||||
|
struct block *blck;
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t words = max(MIN_BLOCK_SIZE_WORDS, align(size + DSIZE) / WSIZE);
|
||||||
|
|
||||||
|
/* Find fit for size */
|
||||||
|
if ((blck = find_fit(words)) != NULL) {
|
||||||
|
place(blck, words);
|
||||||
|
return blck->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((blck = extend_heap(words, 0)) == NULL){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
place(blck, words);
|
||||||
|
return blck->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extend heap with free block and return its block pointer
|
||||||
|
* Does not add new block to free list if called by realloc
|
||||||
|
*/
|
||||||
|
static struct block *extend_heap(size_t words, int realloc)
|
||||||
|
{
|
||||||
|
void *blck = mem_sbrk(words * WSIZE);
|
||||||
|
|
||||||
|
if (blck == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Initialize free block header, footer and epilogue header. */
|
||||||
|
struct block * blk = blck - sizeof(FENCE);
|
||||||
|
set_block_free(blk, words);
|
||||||
|
next_blk(blk)->header = FENCE;
|
||||||
|
|
||||||
|
if (realloc) {
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
list_push_front(find_list(0, words), &blk->elem);
|
||||||
|
|
||||||
|
// NOT IMPLEMENTED YET
|
||||||
|
//return coalesce(blk);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate block of memory at address blck
|
||||||
|
*/
|
||||||
|
static void place(struct block *blck, size_t asize) {
|
||||||
|
size_t csize = blk_size(blck);
|
||||||
|
|
||||||
|
/* Remove block from free list */
|
||||||
|
list_remove(&blck->elem);
|
||||||
|
|
||||||
|
size_t remaining_size = csize - asize;
|
||||||
|
if (remaining_size >= MIN_BLOCK_SIZE_WORDS) {
|
||||||
|
set_block_used(blck, asize);
|
||||||
|
blck = next_blk(blck);
|
||||||
|
set_block_free(blck, remaining_size);
|
||||||
|
|
||||||
|
/* Add remaining free block back into list */
|
||||||
|
list_push_front(find_list(0, remaining_size), &blck->elem);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
set_block_used(blck, csize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find free list with blocks of given size
|
||||||
|
*/
|
||||||
|
static struct list* find_list(int not_empty, size_t n_words) {
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_LISTS; i++) {
|
||||||
|
if ((n_words < list_sizes[i]) || (i == (NUM_LISTS - 1))) {
|
||||||
|
if (not_empty && list_empty(&free_lists[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return &free_lists[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a fit for a block with num_words
|
||||||
|
*/
|
||||||
|
static struct block *find_fit(size_t num_words)
|
||||||
|
{
|
||||||
|
struct list* free_list = find_list(1, num_words);
|
||||||
|
|
||||||
|
if (free_list == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for block from selected free list*/
|
||||||
|
for (struct list_elem* e = list_back(free_list); e != list_head(free_list); e = list_prev(e)) {
|
||||||
|
struct block* bp = list_entry(e, struct block, elem);
|
||||||
|
if (num_words <= blk_size(bp)) {
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user