CMSC 421: Principles of Operating Systems

Homework 4: Memory Allocator

This homework is due on Wednesday, October 28, at 11:59:59 PM (Eastern daylight time). You must use submit to turn in your homework like so: submit cs421_jtang hw4 hw4.c

Your program must be named hw4.c, and it will be compiled on Ubuntu 14.04 as follows:

  gcc --std=c99 -Wall -O2 -pthread -o hw4 hw4.c hw4_test.c
There must not be any compilation warnings in your submission; warnings will result in grading penalties. In addition, your code must be properly indented and have a file header comment, as described on the coding conventions page.

In this homework, you are writing a memory allocator from scratch. You will implement the first-fit algorithm. As proof that your code works, your program will run instructor-provided unit tests that will exercise all functions.

Part 1: Memory Region

Your program will simulate a machine's memory system. The machine has 8 page frames, where each frame holds 32 bytes, for 256 bytes total. Declare this "memory" as a global array. When your program starts, initialize its contents to 0.

Implement the following function with this given signature:

/**
 * Display information about memory allocations.
 *
 * Display to standard output the following:
 * - Memory contents, one frame per line, 8 lines total. Display the
 *   actual bytes stored in memory. If the byte is unprintable (ASCII
 *   value less than 32 or greater than 126, then display a dot
 *   instead.
 * - Memory allocations, one line of 32 characters, where each
 *   character corresponds to a frame. Indicate reserved frames with
 *   R, free memory with f.
 *
 * This is a thread-safe function.
 */
void my_malloc_stats(void);

Part 2: Simple Memory Allocator

Next, implement a first-fit memory allocator. You must implement these functions with these given signatures:

/**
 * Allocate and return a contiguous memory block that is within the
 * memory mapped region.
 *
 * The size of the returned block will be at least @a size bytes,
 * rounded up to the next 32-byte increment.
 *
 * This is a thread-safe function.
 *
 * @param size Number of bytes to allocate. If @c 0, your code may do
 * whatever it wants; my_malloc() of @c 0 is "implementation defined",
 * meaning it is up to you if you want to return @c NULL, segfault,
 * whatever.
 *
 * @return Pointer to allocated memory, or @c NULL if no space could
 * be found. If out of memory, set errno to @c ENOMEM.
 */
void *my_malloc(size_t size);

/**
 * Deallocate a memory region that was returned by my_malloc().
 *
 * If @a ptr is not a pointer returned by my_malloc(), then send a
 * SIGSEGV signal to the calling process. Likewise, calling my_free()
 * on a previously freed region results in a SIGSEGV.
 *
 * This is a thread-safe function.
 *
 * @param ptr Pointer to memory region to free. If @c NULL, do
 * nothing.
 */
void my_free(void *ptr);

For my_malloc(), you are to implement a first-fit allocation strategy. Because each page frame is 32 bytes, my_malloc() must round up to the next 32-byte boundary when reserving space, and the returned address must be frame-aligned. Your functions allocate using the space reserved in step 1 above.

For my_free(), your program deallocates space that was returned by my_malloc(). Thus, if my_malloc() previously allocated 5 frames and returned the address to the first frame, calling my_free() will deallocate all 5 frames (not just the first).

In your code, add a comment block describing how you track which frames are allocated and how large each memory block is. Specifically, describe how your code would handle these two scenarios:

  1. How would a call to my_free() would know to deallocate 5 frames if the user had previously called my_malloc() for 130 bytes?
  2. How does my_free() know it needs to send a SEGFAULT if the user tries to free a pointer that points into the middle of a memory block?

Part 3: Advanced Memory Allocator

Next, implement this function with this given signature:

/**
 * Allocate an array of memory and set it to zero.
 *
 * This allocates a contiguous memory block equal to @a nmemb times @a
 * size bytes, rounded up to the next 32-byte increment. The returned
 * memory will be initialized to 0.
 *
 * This is a thread-safe function.
 *
 * @param nmemb Number of elements to allocated. If @c 0, your code
 * may do whatever it wants. When @a nmemb is @c, it is
 * "implementation defined", meaning it is up to you if you want to
 * return @c NULL, segfault, whatever.
 *
 * @param size Number of bytes per element to allocate. If @c 0, your
 * code may do whatever it wants. When @a size is @c 0, it is
 * "implementation defined", meaning it is up to you if you want to
 * return @c NULL, segfault, whatever.
 *
 * @return Pointer to allocated memory, or @c NULL if no space could
 * be found. If out of memory, set errno to @c ENOMEM.
 */
void *my_calloc(size_t nmemb, size_t size);
  

Your my_calloc() (if nmemb and size are not 0) should use the same first-fit allocation strategy as my_malloc(). Likewise, the returned pointer must be frame-aligned.

Part 4: Threading and Testing

The final step is to ensure that your functions are thread-safe. If a thread is in the middle of any the above functions, another thread calling one of these functions must block.

Within your Ubuntu VM, use the wget command to fetch the unit test code file http://www.csee.umbc.edu/~jtang/cs421.f15/homework/hw4_test.c. This file declares a function with the following signature:

/**
 * Unit test of your memory allocator implementation. This will spawn
 * one or more threads that will simultaneously allocate and free
 * memory regions.
 */
extern void hw4_test(void);
In your main() function, after you have initialized your memory, call hw4_test().

The grader will use a different unit test code file during grading. You may not make any assumptions about what hw4_test() will do other than that its code will compile and that it will not have compilation warnings.

Sample Output

Here is a sample output from running the program using the above hw4_test.c.

Memory contents:
  ................................
  ................................
  ................................
  ................................
  ................................
  ................................
  ................................
  ................................
Memory allocations:
  ffffffff
Memory contents:
  CCCCCCCCAAAAAAAAAAAAAAAAAAAAAA..
  BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  B...............................
  ................................
  ................................
  ................................
  ................................
  ................................
Memory allocations:
  fRRfffff
Out of memory! Reason: Cannot allocate memory
Good, memory was zeroed.
Memory contents:
  DDDDDDDDDDDDDDDD................
  BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  B...............................
  ................................
  ................................
  ................................
  ................................
  ................................
Memory allocations:
  RRRfffff
Memory contents:
  DDDDDDDDDDDDDDDD................
  FFFFFFFFFF......................
  ................................
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
  GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
  GGGGGG..........................
Memory allocations:
  RRRffRRR
Caught signal 11: Segmentation fault!

Other Hints and Notes

Extra Credit

Sorry, there is no extra credit available for this assignment.