#include <stdio.h> #include <stdlib.h> void *my_malloc(size_t size); void my_free(void *ptr); void *free_list_begin(); void *free_list_next(void *node); void coalesce_free_list();
my_malloc() and my_free() should work just like malloc() and free() as discussed in lecture. My_malloc() is a buffered interface to sbrk(), doling out heap memory for programs that call it. It does so by managing a free list of memory, using sbrk() to add memory to the free list. When a user calls my_malloc(s), you will return a pointer to at least s bytes of memory, aligned on an 8-byte quantity. As described in class, you will also reserve eight bytes before the pointer. In the first four of these bytes, you should store the size of the memory chunk allocated, which includes everything -- the user's memory, the bookkeeping bytes and any padding..
You may not call sbrk() with a value less than 8192. You should only call sbrk() with a value greater than 8192 if my_malloc() was called with a value greater than 8176.
When the user calls my_free(p), the chunk of memory should be returned to the free list. You do not have to coalesce free list entries when you call my_free().
Free_list_begin() returns a pointer to the first node on the free list. If the free list is empty, it should return NULL. The first four bytes on a free list node should contain the size of the node (including all metadata, like the size and pointers).
Free_list_next(n) takes a pointer to a free list node and returns a pointer to the next node on the free list. If n is the last node on the free list, then free_list_next(n) should return NULL.
Finally, coalesce_free_list() should process the free list and combine all adjacent entries.
Let's take some simple examples. First, suppose the user calls my_malloc(9990). Your program will pad 9990 to a multiple of eight (9992) and add 8 bytes for bookkeeping. That's 10000 bytes. Since that is bigger than 8192, you'll call sbrk(10000). Suppose that returns 0x10800. You will put the number 10000 at address 0x10800 and return 0x10808 to the user. There is no free list right now, so Free_list_begin() will return NULL.
Now suppose the user calls my_free(0x10808). Those 10000 bytes now turn into a free list node. The first four bytes remain 10000, but we'll modify some stuff to make the free list work. Free_list_begin() will return 0x10800 and Free_list_next(0x10800) will return NULL.
Suppose the user calls my_malloc(4992). That is a multiple of eight, so you will add eight bytes and carve 5000 bytes off your free list node. Personally, I'd carve it off the back of the free list node -- it's easier code to write. When this is done, the state of memory is as follows:
Now, suppose I call coalesce_free_list(). This will combine the two free list nodes into one so that the state of memory is as follows: