Compare commits
11 Commits
overflowch
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
20ae0f9ec2 | ||
|
b48ada3663 | ||
|
1d1c70c945 | ||
|
2b68e9884e | ||
|
e4933103ab | ||
|
9637fb3db3 | ||
|
08198ed242 | ||
|
cabd49cb4f | ||
|
aa8ffbba68 | ||
|
cedb5d607c | ||
|
e4275ea995 |
@ -13,10 +13,10 @@
|
|||||||
* but note that this is a choice (my actual solution chooses
|
* but note that this is a choice (my actual solution chooses
|
||||||
* to count everything in bytes instead.)
|
* to count everything in bytes instead.)
|
||||||
*
|
*
|
||||||
* You may use this code as a starting point for your implementation
|
* You should use this code as a starting point for your
|
||||||
* if you want.
|
* implementation.
|
||||||
*
|
*
|
||||||
* Adapted for CS3214 Summer 2020 by gback
|
* First adapted for CS3214 Summer 2020 by gback
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -142,9 +142,10 @@ int mm_init(void)
|
|||||||
{
|
{
|
||||||
assert (offsetof(struct block, payload) == 4);
|
assert (offsetof(struct block, payload) == 4);
|
||||||
assert (sizeof(struct boundary_tag) == 4);
|
assert (sizeof(struct boundary_tag) == 4);
|
||||||
|
|
||||||
/* Create the initial empty heap */
|
/* Create the initial empty heap */
|
||||||
struct boundary_tag * initial = mem_sbrk(4 * sizeof(struct boundary_tag));
|
struct boundary_tag * initial = mem_sbrk(4 * sizeof(struct boundary_tag));
|
||||||
if (initial == (void *)-1)
|
if (initial == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* We use a slightly different strategy than suggested in the book.
|
/* We use a slightly different strategy than suggested in the book.
|
||||||
@ -176,9 +177,12 @@ void *mm_malloc(size_t size)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Adjust block size to include overhead and alignment reqs. */
|
/* Adjust block size to include overhead and alignment reqs. */
|
||||||
size += 2 * sizeof(struct boundary_tag); /* account for tags */
|
size_t bsize = align(size + 2 * sizeof(struct boundary_tag)); /* account for tags */
|
||||||
|
if (bsize < size)
|
||||||
|
return NULL; /* integer overflow */
|
||||||
|
|
||||||
/* Adjusted block size in words */
|
/* Adjusted block size in words */
|
||||||
size_t awords = max(MIN_BLOCK_SIZE_WORDS, align(size)/WSIZE); /* respect minimum size */
|
size_t awords = max(MIN_BLOCK_SIZE_WORDS, bsize/WSIZE); /* respect minimum size */
|
||||||
|
|
||||||
/* Search the free list for a fit */
|
/* Search the free list for a fit */
|
||||||
if ((bp = find_fit(awords)) != NULL) {
|
if ((bp = find_fit(awords)) != NULL) {
|
||||||
@ -270,9 +274,9 @@ void *mm_realloc(void *ptr, size_t size)
|
|||||||
|
|
||||||
/* Copy the old data. */
|
/* Copy the old data. */
|
||||||
struct block *oldblock = ptr - offsetof(struct block, payload);
|
struct block *oldblock = ptr - offsetof(struct block, payload);
|
||||||
size_t oldsize = blk_size(oldblock) * WSIZE;
|
size_t oldpayloadsize = blk_size(oldblock) * WSIZE - 2 * sizeof(struct boundary_tag);
|
||||||
if (size < oldsize) oldsize = size;
|
if (size < oldpayloadsize) oldpayloadsize = size;
|
||||||
memcpy(newptr, ptr, oldsize);
|
memcpy(newptr, ptr, oldpayloadsize);
|
||||||
|
|
||||||
/* Free the old block. */
|
/* Free the old block. */
|
||||||
mm_free(ptr);
|
mm_free(ptr);
|
||||||
@ -298,7 +302,7 @@ static struct block *extend_heap(size_t words)
|
|||||||
{
|
{
|
||||||
void *bp = mem_sbrk(words * WSIZE);
|
void *bp = mem_sbrk(words * WSIZE);
|
||||||
|
|
||||||
if ((intptr_t) bp == -1)
|
if (bp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Initialize free block header/footer and the epilogue header.
|
/* Initialize free block header/footer and the epilogue header.
|
||||||
@ -349,7 +353,7 @@ team_t team = {
|
|||||||
/* First member's full name */
|
/* First member's full name */
|
||||||
"Godmar Back",
|
"Godmar Back",
|
||||||
"gback@cs.vt.edu",
|
"gback@cs.vt.edu",
|
||||||
/* Second member's full name (leave blank if none) */
|
/* Second member's full name (leave as empty strings if none) */
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
};
|
};
|
||||||
|
440
mm.c
Normal file
440
mm.c
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
/*
|
||||||
|
* mm.c - Dynamic Memory Allocator
|
||||||
|
*
|
||||||
|
* This is an external, segregated free list implementation with multiple lists that hold blocks of
|
||||||
|
* different size ranges. The size ranges for our 8 lists are determined by powers of 2.
|
||||||
|
* - 1st list holds blocks that are 8 * 1 = 8 words.
|
||||||
|
* - 2nd list holds blocks that are 8 * 2 = 16 words. (the constant 8 is the minimum block size)
|
||||||
|
* - 3rd list holds blocks that are 8 * 4 = 32 words.
|
||||||
|
* (and so on)
|
||||||
|
*
|
||||||
|
* When a free block is inserted to a list, it's placed in the front, and when a free block is
|
||||||
|
* removed from a list, it's taken from the back. In other words, last in, first out (LIFO) was
|
||||||
|
* implemented.
|
||||||
|
*
|
||||||
|
* The lists are stored in an array (free_lists) based on their max size.
|
||||||
|
*
|
||||||
|
* An array is used to store the max sizes (list_sizes), and is checked when a free block is added
|
||||||
|
* to a list.
|
||||||
|
*
|
||||||
|
* Both allocated and free blocks use the same structure (block) and are stored in the heap with the
|
||||||
|
* pointer heap_listp.
|
||||||
|
* - Each block has a header and a footer, which store the size in 31 bits, and 1 bit for determining
|
||||||
|
* whether it is free.
|
||||||
|
* - Blocks have a payload which holds hold necessary data.
|
||||||
|
* - They also have a list_elem struct so blocks can be stored in lists.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.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 (in 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 (in 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global variables:
|
||||||
|
*/
|
||||||
|
static struct block *heap_listp = 0;
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
static struct block *coalesce(struct block *bp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a block, obtains previous's block footer. Works for left-most block also.
|
||||||
|
*/
|
||||||
|
static struct boundary_tag * prev_blk_footer(struct block *blk) {
|
||||||
|
return &blk->header - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns if block is free.
|
||||||
|
*/
|
||||||
|
static bool blk_free(struct block *blk) {
|
||||||
|
return !blk->header.inuse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns size of block.
|
||||||
|
*/
|
||||||
|
static size_t blk_size(struct block *blk) {
|
||||||
|
return blk->header.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a block, obtains pointer to previous block. Not meaningful for left-most block.
|
||||||
|
*/
|
||||||
|
static struct block *prev_blk(struct block *blk) {
|
||||||
|
struct boundary_tag *prevfooter = prev_blk_footer(blk);
|
||||||
|
assert(prevfooter->size != 0);
|
||||||
|
return (struct block *)((void *)blk - WSIZE * prevfooter->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a block, obtains 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets 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; // copies header to footer
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets a block as used and sets its size.
|
||||||
|
*/
|
||||||
|
static void set_block_used(struct block *blk, int size) {
|
||||||
|
set_header_and_footer(blk, size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets a block as free and sets its size. Adds the block to a free list.
|
||||||
|
*/
|
||||||
|
static void set_block_free(struct block *blk, int size) {
|
||||||
|
set_header_and_footer(blk, size, 0);
|
||||||
|
list_push_front(find_list(0, size), &blk->elem); // (LIFO)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes the memory manager.
|
||||||
|
*/
|
||||||
|
int mm_init(void)
|
||||||
|
{
|
||||||
|
assert (offsetof(struct block, payload) == 4);
|
||||||
|
assert (sizeof(struct boundary_tag) == 4);
|
||||||
|
|
||||||
|
// Creates the initial empty heap.
|
||||||
|
struct boundary_tag * initial = mem_sbrk(4 * sizeof(struct boundary_tag));
|
||||||
|
if (initial == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* We use a slightly different strategy than suggested in the book. Rather than placing a
|
||||||
|
* min-sized prologue block at the beginning of the heap, we simply place two fences. The
|
||||||
|
* consequence is that coalesce() must call prev_blk_footer() and not prev_blk() because
|
||||||
|
* prev_blk() cannot be called on the left-most block.
|
||||||
|
*/
|
||||||
|
initial[2] = FENCE; // prologue header
|
||||||
|
heap_listp = (struct block *)&initial[3];
|
||||||
|
initial[3] = FENCE; // epilogue header
|
||||||
|
|
||||||
|
// Initializes the free_lists.
|
||||||
|
for (int i = 0; i < NUM_LISTS; i++)
|
||||||
|
list_init(&free_lists[i]);
|
||||||
|
|
||||||
|
// Initializes list_sizes (powers of 2).
|
||||||
|
for (int i = 0; i < NUM_LISTS; i++) {
|
||||||
|
int size = 1;
|
||||||
|
for (int j = 0; j < i; j++)
|
||||||
|
size *= 2;
|
||||||
|
list_sizes[i] = MIN_BLOCK_SIZE_WORDS * (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extends the empty heap with a free block of CHUNKSIZE bytes.
|
||||||
|
if (extend_heap(CHUNKSIZE) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a pointer to an allocated block with a payload of at least the given size in (bytes). The
|
||||||
|
* entire allocated block should lie within the heap region and should not overlap with other
|
||||||
|
* allocated blocks.
|
||||||
|
*/
|
||||||
|
void *mm_malloc(size_t size) {
|
||||||
|
if (size == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct block *blck;
|
||||||
|
size_t words = max(MIN_BLOCK_SIZE_WORDS, align(size + DSIZE) / WSIZE);
|
||||||
|
|
||||||
|
// Attempts to find a block from the free lists that fit.
|
||||||
|
if ((blck = find_fit(words)) != NULL) {
|
||||||
|
place(blck, words); // malloc successful
|
||||||
|
return blck->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to extend the heap to accomodate.
|
||||||
|
if ((blck = extend_heap(words)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
place(blck, words);
|
||||||
|
return blck->payload; // malloc successful
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frees the block pointed by the given pointer.
|
||||||
|
*/
|
||||||
|
void mm_free(void *bp) {
|
||||||
|
// Asserts that mm_init() was called.
|
||||||
|
assert (heap_listp != 0);
|
||||||
|
|
||||||
|
if (bp == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Finds a block from the given pointer and frees it.
|
||||||
|
struct block *blk = bp - offsetof(struct block, payload);
|
||||||
|
set_block_free(blk, blk_size(blk));
|
||||||
|
|
||||||
|
coalesce(blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frees the block pointed by the given pointer.
|
||||||
|
*/
|
||||||
|
void *mm_realloc(void *ptr, size_t size) {
|
||||||
|
size_t bytesize;
|
||||||
|
void *new_ptr;
|
||||||
|
|
||||||
|
// Equivalent to mallocing.
|
||||||
|
if (ptr == NULL)
|
||||||
|
return mm_malloc(size);
|
||||||
|
|
||||||
|
// Equivalent to freeing.
|
||||||
|
if (size == 0) {
|
||||||
|
mm_free(ptr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct block *oldblock = ptr - offsetof(struct block, payload);
|
||||||
|
bool prev_alloc = prev_blk_footer(oldblock)->inuse;
|
||||||
|
bool next_alloc = !blk_free(next_blk(oldblock));
|
||||||
|
|
||||||
|
// CASE 1: The next block is free.
|
||||||
|
if (!next_alloc) {
|
||||||
|
struct block *right;
|
||||||
|
right = next_blk(oldblock);
|
||||||
|
list_remove(&right->elem);
|
||||||
|
set_block_used(oldblock, blk_size(oldblock) + blk_size(next_blk(oldblock)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blk_size(oldblock) >= size) {
|
||||||
|
return oldblock->payload; // reallocing was successful
|
||||||
|
}
|
||||||
|
|
||||||
|
// CASE 2: The previous block is free.
|
||||||
|
if (!prev_alloc) {
|
||||||
|
struct block *left;
|
||||||
|
left = prev_blk(oldblock);
|
||||||
|
list_remove(&left->elem);
|
||||||
|
set_block_used(left, blk_size(oldblock) + blk_size(left));
|
||||||
|
oldblock = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blk_size(oldblock) >= size) {
|
||||||
|
bytesize = blk_size(oldblock) * WSIZE;
|
||||||
|
if(size < bytesize)
|
||||||
|
bytesize = size;
|
||||||
|
memcpy(oldblock->payload, ptr, bytesize);
|
||||||
|
return oldblock->payload; // reallocing was successful
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEFAULT:
|
||||||
|
new_ptr = mm_malloc(size);
|
||||||
|
if(!new_ptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct block *copyblk = ptr - offsetof(struct block, payload);
|
||||||
|
bytesize = blk_size(copyblk) * WSIZE;
|
||||||
|
if(size < bytesize)
|
||||||
|
bytesize = size;
|
||||||
|
memcpy(new_ptr, ptr, bytesize);
|
||||||
|
|
||||||
|
mm_free(oldblock->payload);
|
||||||
|
|
||||||
|
return new_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Combines adjacent free blocks. Returns a pointer to the coalesced block.
|
||||||
|
*/
|
||||||
|
static struct block *coalesce(struct block *bp)
|
||||||
|
{
|
||||||
|
int prev_alloc = prev_blk_footer(bp)->inuse; // previous block allocated?
|
||||||
|
int next_alloc = !blk_free(next_blk(bp)); // next block allocated?
|
||||||
|
size_t size = blk_size(bp);
|
||||||
|
|
||||||
|
// CASE 1: Both are allocated, nothing to coalesce.
|
||||||
|
if (prev_alloc && next_alloc)
|
||||||
|
return bp;
|
||||||
|
|
||||||
|
// CASE 2: Next block is free, combine with next block.
|
||||||
|
else if (prev_alloc && !next_alloc) {
|
||||||
|
list_remove(&bp->elem);
|
||||||
|
list_remove(&next_blk(bp)->elem);
|
||||||
|
size_t new_size = size + blk_size(next_blk(bp));
|
||||||
|
set_block_free(bp, new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CASE 3: Previous block is free, combine with previous block.
|
||||||
|
else if (!prev_alloc && next_alloc) {
|
||||||
|
list_remove(&prev_blk(bp)->elem);
|
||||||
|
list_remove(&bp->elem);
|
||||||
|
size_t new_size = blk_size(prev_blk(bp)) + size;
|
||||||
|
bp = prev_blk(bp);
|
||||||
|
set_block_free(bp, new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CASE 4: Previous and next blocks are free, combine with both.
|
||||||
|
else if (!prev_alloc && !next_alloc) {
|
||||||
|
list_remove(&prev_blk(bp)->elem);
|
||||||
|
list_remove(&bp->elem);
|
||||||
|
list_remove(&next_blk(bp)->elem);
|
||||||
|
size_t new_size = blk_size(prev_blk(bp)) + size + blk_size(next_blk(bp));
|
||||||
|
bp = prev_blk(bp);
|
||||||
|
set_block_free(bp, new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extends the heap with free block and return its block pointer.
|
||||||
|
*/
|
||||||
|
static struct block *extend_heap(size_t words) {
|
||||||
|
void *blck = mem_sbrk(words * WSIZE);
|
||||||
|
|
||||||
|
if (blck == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Initializes a free block header, footer, and epilogue header. */
|
||||||
|
struct block * blk = blck - sizeof(FENCE);
|
||||||
|
set_block_free(blk, words);
|
||||||
|
next_blk(blk)->header = FENCE;
|
||||||
|
|
||||||
|
return coalesce(blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocates block of memory at address block.
|
||||||
|
*/
|
||||||
|
static void place(struct block *blck, size_t asize) {
|
||||||
|
// Removes the block since it's no longer free.
|
||||||
|
list_remove(&blck->elem);
|
||||||
|
|
||||||
|
size_t csize = blk_size(blck);
|
||||||
|
size_t remaining_size = csize - asize;
|
||||||
|
|
||||||
|
// Determines if the block has extra space that can be freed.
|
||||||
|
if (remaining_size >= MIN_BLOCK_SIZE_WORDS) {
|
||||||
|
set_block_used(blck, asize);
|
||||||
|
blck = next_blk(blck);
|
||||||
|
set_block_free(blck, remaining_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_block_used(blck, csize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finds a free list that can fit a block with the given size (in words).
|
||||||
|
*
|
||||||
|
* not_empty == 0, find "any" list
|
||||||
|
* not_empty == 1, find a non-empty list
|
||||||
|
*/
|
||||||
|
static struct list* find_list(int not_empty, size_t n_words) {
|
||||||
|
// Parses the segregated free lists.
|
||||||
|
for (int i = 0; i < NUM_LISTS; i++) {
|
||||||
|
/*
|
||||||
|
* Attempts to return the current list if...
|
||||||
|
* a.) the given size is less than/equal to the current list's max size.
|
||||||
|
* b.) the current list is the last one.
|
||||||
|
*/
|
||||||
|
if ((n_words <= list_sizes[i]) || (i == (NUM_LISTS - 1))) {
|
||||||
|
// Continues searching if a non-empty list is needed and the current list is empty.
|
||||||
|
if (not_empty && list_empty(&free_lists[i]))
|
||||||
|
continue;
|
||||||
|
return &free_lists[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finds a free block that fits the given size (in words).
|
||||||
|
*/
|
||||||
|
static struct block *find_fit(size_t num_words) {
|
||||||
|
// Selects a free list that contains a free block that fits.
|
||||||
|
struct list* free_list = find_list(1, num_words);
|
||||||
|
|
||||||
|
if (free_list == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Searches for a free block from the selected free list that fits. (LIFO)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
team_t team = {
|
||||||
|
"Micah Moore Felicia Seo",
|
||||||
|
"Micah Moore",
|
||||||
|
"micahmoore@vt.edu",
|
||||||
|
"Felicia Seo",
|
||||||
|
"seofelicia@vt.edu",
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user