2022-03-05 12:43:06 -05:00
|
|
|
#include <criterion/criterion.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include "debug.h"
|
|
|
|
#include "sfmm.h"
|
|
|
|
#define TEST_TIMEOUT 15
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Assert the total number of free blocks of a specified size.
|
|
|
|
* If size == 0, then assert the total number of all free blocks.
|
|
|
|
*/
|
|
|
|
void assert_free_block_count(size_t size, int count) {
|
|
|
|
int cnt = 0;
|
|
|
|
for(int i = 0; i < NUM_FREE_LISTS; i++) {
|
|
|
|
sf_block *bp = sf_free_list_heads[i].body.links.next;
|
|
|
|
while(bp != &sf_free_list_heads[i]) {
|
|
|
|
if(size == 0 || size == ((bp->header ^ MAGIC) & 0xfffffff0))
|
|
|
|
cnt++;
|
|
|
|
bp = bp->body.links.next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(size == 0) {
|
|
|
|
cr_assert_eq(cnt, count, "Wrong number of free blocks (exp=%d, found=%d)",
|
|
|
|
count, cnt);
|
|
|
|
} else {
|
|
|
|
cr_assert_eq(cnt, count, "Wrong number of free blocks of size %ld (exp=%d, found=%d)",
|
|
|
|
size, count, cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Assert the total number of quick list blocks of a specified size.
|
|
|
|
* If size == 0, then assert the total number of all quick list blocks.
|
|
|
|
*/
|
|
|
|
void assert_quick_list_block_count(size_t size, int count) {
|
|
|
|
int cnt = 0;
|
|
|
|
for(int i = 0; i < NUM_QUICK_LISTS; i++) {
|
|
|
|
sf_block *bp = sf_quick_lists[i].first;
|
|
|
|
while(bp != NULL) {
|
|
|
|
if(size == 0 || size == ((bp->header ^ MAGIC) & 0xfffffff0)) {
|
|
|
|
cnt++;
|
|
|
|
if(size != 0) {
|
|
|
|
// Check that the block is in the correct list for its size.
|
|
|
|
int index = (size - 32) >> 4;
|
|
|
|
cr_assert_eq(index, i, "Block %p (size %ld) is in wrong quick list for its size "
|
|
|
|
"(expected %d, was %d)",
|
|
|
|
&bp->header, (bp->header ^ MAGIC) & 0xfffffff0, index, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bp = bp->body.links.next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(size == 0) {
|
|
|
|
cr_assert_eq(cnt, count, "Wrong number of quick list blocks (exp=%d, found=%d)",
|
|
|
|
count, cnt);
|
|
|
|
} else {
|
|
|
|
cr_assert_eq(cnt, count, "Wrong number of quick list blocks of size %ld (exp=%d, found=%d)",
|
|
|
|
size, count, cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, malloc_an_int, .timeout = TEST_TIMEOUT) {
|
|
|
|
sf_errno = 0;
|
|
|
|
size_t sz = sizeof(int);
|
|
|
|
int *x = sf_malloc(sz);
|
|
|
|
|
|
|
|
cr_assert_not_null(x, "x is NULL!");
|
|
|
|
|
|
|
|
*x = 4;
|
|
|
|
|
|
|
|
cr_assert(*x == 4, "sf_malloc failed to give proper space for an int!");
|
|
|
|
sf_block *bp = (sf_block *)((char *)x - 16);
|
2022-03-20 05:07:04 -04:00
|
|
|
cr_assert((((bp->header ^ MAGIC) >> 32) & 0xffffffff) == sz,
|
2022-03-05 12:43:06 -05:00
|
|
|
"Malloc'ed block payload size (%ld) not what was expected (%ld)!",
|
2022-03-20 05:07:04 -04:00
|
|
|
(((bp->header ^ MAGIC) >> 32) & 0xffffffff), sz);
|
2022-03-05 12:43:06 -05:00
|
|
|
|
|
|
|
assert_quick_list_block_count(0, 0);
|
|
|
|
assert_free_block_count(0, 1);
|
|
|
|
assert_free_block_count(944, 1);
|
|
|
|
|
|
|
|
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
|
|
|
cr_assert(sf_mem_start() + PAGE_SZ == sf_mem_end(), "Allocated more than necessary!");
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, malloc_four_pages, .timeout = TEST_TIMEOUT) {
|
|
|
|
sf_errno = 0;
|
|
|
|
|
|
|
|
void *x = sf_malloc(4032);
|
|
|
|
cr_assert_not_null(x, "x is NULL!");
|
|
|
|
assert_quick_list_block_count(0, 0);
|
|
|
|
assert_free_block_count(0, 0);
|
|
|
|
cr_assert(sf_errno == 0, "sf_errno is not 0!");
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, malloc_too_large, .timeout = TEST_TIMEOUT) {
|
|
|
|
sf_errno = 0;
|
|
|
|
void *x = sf_malloc(98304);
|
|
|
|
|
|
|
|
cr_assert_null(x, "x is not NULL!");
|
|
|
|
assert_quick_list_block_count(0, 0);
|
|
|
|
assert_free_block_count(0, 1);
|
|
|
|
assert_free_block_count(24528, 1);
|
|
|
|
cr_assert(sf_errno == ENOMEM, "sf_errno is not ENOMEM!");
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, free_quick, .timeout = TEST_TIMEOUT) {
|
|
|
|
sf_errno = 0;
|
|
|
|
size_t sz_x = 8, sz_y = 32, sz_z = 1;
|
|
|
|
/* void *x = */ sf_malloc(sz_x);
|
|
|
|
void *y = sf_malloc(sz_y);
|
|
|
|
/* void *z = */ sf_malloc(sz_z);
|
|
|
|
|
|
|
|
sf_free(y);
|
|
|
|
|
|
|
|
assert_quick_list_block_count(0, 1);
|
|
|
|
assert_quick_list_block_count(48, 1);
|
|
|
|
assert_free_block_count(0, 1);
|
|
|
|
assert_free_block_count(864, 1);
|
|
|
|
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, free_no_coalesce, .timeout = TEST_TIMEOUT) {
|
|
|
|
sf_errno = 0;
|
|
|
|
size_t sz_x = 8, sz_y = 200, sz_z = 1;
|
|
|
|
/* void *x = */ sf_malloc(sz_x);
|
|
|
|
void *y = sf_malloc(sz_y);
|
|
|
|
/* void *z = */ sf_malloc(sz_z);
|
|
|
|
|
|
|
|
sf_free(y);
|
|
|
|
|
|
|
|
assert_quick_list_block_count(0, 0);
|
|
|
|
assert_free_block_count(0, 2);
|
2022-03-12 02:10:51 -05:00
|
|
|
assert_free_block_count(208, 1);
|
|
|
|
assert_free_block_count(704, 1);
|
2022-03-05 12:43:06 -05:00
|
|
|
|
|
|
|
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, free_coalesce, .timeout = TEST_TIMEOUT) {
|
|
|
|
sf_errno = 0;
|
|
|
|
size_t sz_w = 8, sz_x = 200, sz_y = 300, sz_z = 4;
|
|
|
|
/* void *w = */ sf_malloc(sz_w);
|
|
|
|
void *x = sf_malloc(sz_x);
|
|
|
|
void *y = sf_malloc(sz_y);
|
|
|
|
/* void *z = */ sf_malloc(sz_z);
|
|
|
|
|
|
|
|
sf_free(y);
|
|
|
|
sf_free(x);
|
|
|
|
|
|
|
|
assert_quick_list_block_count(0, 0);
|
|
|
|
assert_free_block_count(0, 2);
|
2022-03-12 02:10:51 -05:00
|
|
|
assert_free_block_count(384, 1);
|
|
|
|
assert_free_block_count(528, 1);
|
2022-03-05 12:43:06 -05:00
|
|
|
|
|
|
|
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, freelist, .timeout = TEST_TIMEOUT) {
|
|
|
|
size_t sz_u = 200, sz_v = 150, sz_w = 50, sz_x = 150, sz_y = 200, sz_z = 250;
|
|
|
|
void *u = sf_malloc(sz_u);
|
|
|
|
/* void *v = */ sf_malloc(sz_v);
|
|
|
|
void *w = sf_malloc(sz_w);
|
|
|
|
/* void *x = */ sf_malloc(sz_x);
|
|
|
|
void *y = sf_malloc(sz_y);
|
|
|
|
/* void *z = */ sf_malloc(sz_z);
|
|
|
|
|
|
|
|
sf_free(u);
|
|
|
|
sf_free(w);
|
|
|
|
sf_free(y);
|
|
|
|
|
|
|
|
assert_quick_list_block_count(0, 1);
|
|
|
|
assert_free_block_count(0, 3);
|
2022-03-12 02:10:51 -05:00
|
|
|
assert_free_block_count(208, 2);
|
|
|
|
assert_free_block_count(928, 1);
|
2022-03-05 12:43:06 -05:00
|
|
|
|
|
|
|
// First block in list should be the most recently freed block not in quick list.
|
|
|
|
int i = 3;
|
|
|
|
sf_block *bp = sf_free_list_heads[i].body.links.next;
|
|
|
|
cr_assert_eq(&bp->header, (char *)y - 8,
|
|
|
|
"Wrong first block in free list %d: (found=%p, exp=%p)",
|
|
|
|
i, &bp->header, (char *)y - 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, realloc_larger_block, .timeout = TEST_TIMEOUT) {
|
|
|
|
size_t sz_x = sizeof(int), sz_y = 10, sz_x1 = sizeof(int) * 20;
|
|
|
|
void *x = sf_malloc(sz_x);
|
|
|
|
/* void *y = */ sf_malloc(sz_y);
|
|
|
|
x = sf_realloc(x, sz_x1);
|
|
|
|
|
|
|
|
cr_assert_not_null(x, "x is NULL!");
|
|
|
|
sf_block *bp = (sf_block *)((char *)x - 16);
|
|
|
|
cr_assert((bp->header ^ MAGIC) & THIS_BLOCK_ALLOCATED, "Allocated bit is not set!");
|
|
|
|
cr_assert(((bp->header ^ MAGIC) & 0xfffffff0) == 96,
|
|
|
|
"Realloc'ed block size (%ld) not what was expected (%ld)!",
|
|
|
|
(bp->header ^ MAGIC) & 0xfffffff0, 96);
|
|
|
|
cr_assert((((bp->header ^ MAGIC) >> 32) & 0xffffffff) == sz_x1,
|
|
|
|
"Realloc'ed block payload size (%ld) not what was expected (%ld)!",
|
|
|
|
(((bp->header ^ MAGIC) >> 32) & 0xffffffff), sz_x1);
|
|
|
|
|
|
|
|
assert_quick_list_block_count(0, 1);
|
|
|
|
assert_quick_list_block_count(32, 1);
|
|
|
|
assert_free_block_count(0, 1);
|
|
|
|
assert_free_block_count(816, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, realloc_smaller_block_splinter, .timeout = TEST_TIMEOUT) {
|
|
|
|
size_t sz_x = sizeof(int) * 20, sz_y = sizeof(int) * 16;
|
|
|
|
void *x = sf_malloc(sz_x);
|
|
|
|
void *y = sf_realloc(x, sz_y);
|
|
|
|
|
|
|
|
cr_assert_not_null(y, "y is NULL!");
|
|
|
|
cr_assert(x == y, "Payload addresses are different!");
|
|
|
|
|
|
|
|
sf_block *bp = (sf_block *)((char *)x - 16);
|
|
|
|
cr_assert((bp->header ^ MAGIC) & THIS_BLOCK_ALLOCATED, "Allocated bit is not set!");
|
|
|
|
cr_assert(((bp->header ^ MAGIC) & 0xfffffff0) == 96,
|
|
|
|
"Realloc'ed block size (%ld) not what was expected (%ld)!",
|
|
|
|
(bp->header ^ MAGIC) & 0xfffffff0, 96);
|
|
|
|
cr_assert((((bp->header ^ MAGIC) >> 32) & 0xffffffff) == sz_y,
|
|
|
|
"Realloc'ed block payload size (%ld) not what was expected (%ld)!",
|
|
|
|
(((bp->header ^ MAGIC) >> 32) & 0xffffffff), sz_y);
|
|
|
|
|
|
|
|
// There should be only one free block.
|
|
|
|
assert_quick_list_block_count(0, 0);
|
|
|
|
assert_free_block_count(0, 1);
|
|
|
|
assert_free_block_count(880, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Test(sfmm_basecode_suite, realloc_smaller_block_free_block, .timeout = TEST_TIMEOUT) {
|
|
|
|
size_t sz_x = sizeof(double) * 8, sz_y = sizeof(int);
|
|
|
|
void *x = sf_malloc(sz_x);
|
|
|
|
void *y = sf_realloc(x, sz_y);
|
|
|
|
|
|
|
|
cr_assert_not_null(y, "y is NULL!");
|
|
|
|
|
|
|
|
sf_block *bp = (sf_block *)((char *)x - 16);
|
|
|
|
cr_assert((bp->header ^ MAGIC) & THIS_BLOCK_ALLOCATED, "Allocated bit is not set!");
|
|
|
|
cr_assert(((bp->header ^ MAGIC) & 0xfffffff0) == 32,
|
|
|
|
"Realloc'ed block size (%ld) not what was expected (%ld)!",
|
|
|
|
(bp->header ^ MAGIC) & 0xfffffff0, 32);
|
|
|
|
cr_assert((((bp->header ^ MAGIC) >> 32) & 0xffffffff) == sz_y,
|
|
|
|
"Realloc'ed block payload size (%ld) not what was expected (%ld)!",
|
|
|
|
(((bp->header ^ MAGIC) >> 32) & 0xffffffff), sz_y);
|
|
|
|
|
|
|
|
// After realloc'ing x, we can return a block of size 48
|
|
|
|
// to the freelist. This block will go into the main freelist and be coalesced.
|
|
|
|
// Note that we don't put split blocks into the quick lists because their sizes are not sizes
|
|
|
|
// that were requested by the client, so they are not very likely to satisfy a new request.
|
|
|
|
assert_quick_list_block_count(0, 0);
|
|
|
|
assert_free_block_count(0, 1);
|
|
|
|
assert_free_block_count(944, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//############################################
|
|
|
|
//STUDENT UNIT TESTS SHOULD BE WRITTEN BELOW
|
|
|
|
//DO NOT DELETE THESE COMMENTS
|
|
|
|
//############################################
|
|
|
|
|
|
|
|
//Test(sfmm_student_suite, student_test_1, .timeout = TEST_TIMEOUT) {
|
|
|
|
//}
|