CMSC 421: Principles of Operating Systems

Homework 4: Stroll Down Memory Lane

This homework is due on Tuesday, November 1, 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 16.04 as follows:

  gcc --std=c99 -Wall -O2 -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 a next-fit allocation 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 16 page frames, where each frame holds 64 bytes, for 1024 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 to standard output.
 *
 * Display to standard output the following:
 * - Memory contents, one frame per line, 16 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.
 * - Current memory allocations, one line of 16 characters, where each
 *   character corresponds to a frame. Indicate reserved frames with
 *   R, free memory with f.
 */
void my_malloc_stats(void);

Part 2: Simple Memory Allocator

Next, implement a next-fit memory allocator. In a next-fit memory allocator, the first allocation begins with the first frame. The next time an allocation occurs, begin at the frame following the previous allocation (regardless if the previous allocation was freed). Continue allocating until either the end of memory is reached or there are insufficient frames remaining; at that point allocations restart with first frame.

Use your next-fit allocator to implement these functions with these given signatures. Note the @a and @c in the comments; those are Doxygen documentation commands.

/**
 * Allocate and return a contiguous memory block that is within the
 * memory region.
 *
 * The size of the returned block will be at least @a size bytes,
 * rounded up to the next 64-byte increment.
 *
 * @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() or
 * my_realloc().
 *
 * If @a ptr is not a pointer returned by my_malloc() or my_realloc(),
 * then send a SIGSEGV signal to the calling process. Likewise,
 * calling my_free() on a previously freed region results in a
 * SIGSEGV.
 *
 * @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 next-fit allocation strategy. Because each page frame is 64 bytes, my_malloc() must round up to the next 64-byte boundary when reserving space, and the returned address must be frame-aligned. Your function allocates using the space reserved in step 1 above.

For my_free(), your program deallocates space that was returned by my_malloc() or my_realloc() (see below). 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 300 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:

/**
 * Change the size of the memory block pointed to by @a ptr.
 *
 * - If @a ptr is @c NULL, then treat this as if a call to
 *   my_malloc() for the requested size.
 * - Else if @a size is @c 0, then treat this as if a call to
 *   my_free().
 * - Else if @a ptr is not a pointer returned by my_malloc() or
 *   my_realloc(), then send a SIGSEGV signal to the calling process.
 *
 * Otherwise reallocate @a ptr as follows:
 *
 * - If @a size is smaller than the previously allocated size, then
 *   reduce the size of the memory block. Mark the excess memory as
 *   available. Memory sizes are rounded up to the next 64-byte
 *   increment.
 * - If @a size is the same size as the previously allocated size,
 *   then do nothing.
 * - If @a size is greater than the previously allocated size, then
 *   allocate a new contiguous block of at least @a size bytes,
 *   rounded up to the next 64-byte increment. Copy the contents from
 *   the old to the new block, then free the old block.
 *
 * @param ptr Pointer to memory region to reallocate.
 * @param size Number of bytes to reallocate.
 *
 * @return If allocating a new memory block or if resizing a block,
 * then pointer to allocated memory; @a ptr will become invalid. If
 * freeing a memory region or if allocation fails, return @c NULL. If
 * out of memory, set errno to @c ENOMEM.
 */
void *my_realloc(void *ptr, size_t size);
  

Your my_realloc() (if size is not 0) must use the same next-fit allocation strategy as my_malloc(). Likewise, the returned pointer must be frame-aligned.

Part 4: Testing

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

/**
 * Unit test of your memory allocator implementation. This will
 * 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.

Note how this code implements a basic testing framework, that prints what it is about to test, if the test passes or fails, and the sum of passed and failed tests. Read over hw4_test.c; for the projects you will need to write your own unit tests. If you continue your career in software engineering, be familiar with other unit testing frameworks.

Sample Output

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

Test 1: Display initialized memory
Memory contents:
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
Memory allocations:
  ffffffffffffffff
Test 2: Simple allocations
Test 3: Simple freeing
Memory contents:
  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..................................
  BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  BBBBBB..........................................................
  CCCCCCCC........................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
Memory allocations:
  fRRRffffffffffff
Test 4: Out of memory condition
Test 5: Double-free
Caught signal 11: Segmentation fault: 11!
Memory contents:
  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..................................
  BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  BBBBBB..........................................................
  CCCCCCCC........................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
Memory allocations:
  fffRffffffffffff
Test 6: Increasing memory
Memory contents:
  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..................................
  BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  BBBBBB..........................................................
  CCCCCCCC........................................................
  DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
  DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
  DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
  D...............................................................
  DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
  DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
  DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
  D...............................................................
  ................................................................
  ................................................................
  ................................................................
  ................................................................
Memory allocations:
  fffRffffRRRRRRRf
Test 7: Decreasing memory
Memory contents:
  FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  BBBBBB..........................................................
  CCCCCCCC........................................................
  GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
  GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
  GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
  GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  EEEEEEEEEEEEEEEE................................................
  ................................................................
Memory allocations:
  RRfRRRRRRRffffff
12 tests passed, 0 tests failed.

Other Hints and Notes

Extra Credit

You may earn an additional 5% on this assignment by implementing the following function:

/**
 * Format a string into a newly allocated memory block.
 *
 * Calculate the length that a formatted string (as per snprintf())
 * would be, then allocate contiguous memory block(s) of at least that
 * length. Then output the resulting string, including terminating
 * null character ('\0') to that memory. The starting address of the
 * memory block is written to the pointer pointed to by @a strp. The
 * pointer can be freed via my_free() afterwards.
 *
 * @param strp Pointer to where to write pointer to.
 *
 * @param fmt Format specification, as per snprintf().
 *
 * @return Number of bytes allocated (excluding terminating null
 * byte), if memory allocation succeeds. If out of memory, @a strp is
 * @c NULL, or some other error occurs, return -1.
 */
int my_asprintf(char **strp, const char *fmt, ...);
  

If you choose to perform this extra credit, put a comment at the top of your file, alerting the grader.