CS360 Midterm 2. March 29, 2018. Answers and Grading


Question 1 - 15 Points

I'm going to be honest -- I was disappointed with how few students approached part two correctly. The program seemed straightforward to me -- fill a buffer incrementally and flush it when it gets full. Only 8 students out of 52 approached it correctly. The rest either ignored the fact that buf was of a fixed size, or they ignored buf altogether.

Part 1: b -- you are making lots of write() calls on small values, resulting in too much system call overhead.

Part 2: Fill the buffer incrementally, and then write it either when it gets full, or at the end of write_ints: The answer is in the file p1.c.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int buf[1024];

void write_ints(int fd, int size, int *ints, char *select)
{
  int i, j;

  j = 0;

  for (i = 0; i < size; i++) {
    if (select[i] != 0) {
      buf[j] = ints[i];
      j++;
      if (j == 1024) {
        write(fd, buf, 1024*sizeof(int));
        j = 0;
      }
    }
  }
  if (j != 0) write(fd, buf, j*sizeof(int));
  return;
}

Grading

3 points for part 1 (which pretty much everyone got), and 12 for part 2. The answers for part two fall into five categories:
  1. Doing it correctly - 12 points.
  2. Ignoring the buffer, and instead compacting ints so that the selected integers are in the front. This got 11 points; I took off one because it destroys ints, and the original does not.
  3. Identifying contiguous integers in ints and writing those with one write() call rather than one write() per integer. That does reduce the number of writes, but only if ints has a lot of contiguous integers. If it doesn't, then this won't improve matters much. This was 10 points.
  4. Copying the selected integers to buf and then writing buf at the end. This is a good solution, except for the fact that if there are more than 1024 selected integers, it will overrun memory. This was 9 points.
  5. Other answers, which were often some variant of the above, but confused.


Question 2 - 15 Points

A. You want to check to see that they have the same inode numbers. For that, you can do ls -i.

B. You call stat() and look at the "mode", which is in the variable st_mode. There is a macro which tells you whether the mode specifies that the file is a directory.

C. Directories hold bindings of names to inode numbers.

D. If you use r2, you will have to spill it, so that you can reset it when your procedure is done. An example is when you are implementing an arithmetic expression that requires more than two registers.

E. One reason is that you don't have write permissions on f1. A second reason is that f1 is a directory, so you aren't allowed to write to it. A third reason is that your program has too many open files. A fourth reason, is that someone deleted the file between your ls call and your program (which you had to specify).

Grading

Three points each.


Question 3 - XX Points

b:
  push #4                / Allocate i
  st %g0 -> [fp]         / Set i to zero
  b l2                   / Go to the boolean expression of the for loop.
l1:
  ld [fp] -> %r0         / i++
  add %r0, %g1 -> %r0
  st %r0 -> [fp]
l2:
  ld [fp] -> %r0         / Do (i < 10) and branch on the negation
  mov #10 -> %r1
  cmp %r0, %r1
  bge l3

  ld [fp+12] -> %r0      / j += i
  ld [fp] -> %r1
  add %r0, %r1 -> %r0
  st %r0 -> [fp+12];
  b l1
l3:
  ld [fp+12] -> %r0      / return j
  ret

c:                         /             ld
  ld [fp+16] -> %r0        /              |
  mov #4 -> %r1            /              + -- This gives you &(p[k])
  mul %r0, %r1 -> %r0      /             / \
  ld [fp+12] -> %r1        /            p   *
  add %r0, %r1 -> %r0      /               / \
  ld [r0] -> %r0           /              k   4
  ret                      /

d:
  st %r2 -> [sp]--      /  Spill r2
  jsr g                 /  Push g() onto the stack
  st %r0 -> [sp]--      /
  mov #5 -> %r0         /  Push 5 onto the stack
  st %r0 -> [sp]--      /
  jsr e                 /  Call e(5, g())
  pop #8                /  Pop the arguments off the stack
  mov %r0 -> %r2        /  Move the return value to r2, so that f() doesn't overwrite it
  jsr f                 /  Call f()
  add %r0, %r2 -> %r0   /  Add f() to e(5, g())
  ld ++[sp] -> %r2      /  Unspill r2
  ret                   /

Grading

Because the exam started 15 minutes late, I instructed the students not to do this question.

Question 4 - 20 Points

At the point where we call "jsr y", our stack looks as follows:
Address     Value     Description
--------  --------    ---------------------
0x300438   unknown    unused                  <-----------sp
0x30043c        11    First argument to y
0x300440         7    Second argument to y
0x300444         5    m in z()                <-----------fp
--------  --------    ---------------------               pc = 0x3458
We call y() which pushes fp and pc+4 onto the stack. y() allocates four bytes for i, then changes i to 77 and k to 6. It returns 77. So, at the point where y() returns, we have:
Address     Value     Description
--------  --------    ---------------------
0x30042c   unknown    unused                  <-----------sp                       
0x300430        77    i in y()                <-----------fp
0x300434  0x300444    Saved fp in z()
0x300438    0x345c    Saved pc in z()                                          
0x30043c        11    j in y()           
0x300440         6    k in y()            
0x300444         5    m in z()                            r0 = 77
--------  --------    ---------------------               pc = ?
So, the following are the answers:

Grading

Two points per answer.


Question 5 - 24 Points

Part A: Here are the blocks on the free list, together with size, flink, and blink (you were asked to just show the addresses and sizes. I'm putting flink and blink so that it's easier to see how the free blocks are chained together):
Address     Size         Flink         Blink
----------  ---------    ----------    ----------
0x78649d48  0x10 = 16    0x78649da0    0x0 (NULL)
0x78649da0  0x18 = 24    0x78649d30    0x78649d48
0x78649d30  0x18 = 24    0x78649df8    0x78649da0
0x78649df8  0x18 = 24    0x0 (NULL)    0x78649d30
----------  ---------    ----------    ----------
Part B: We simply walk through the blocks of memory. Add the size to the address to get the address of the next block. The lines in black are the allocated blocks. The colored lines are blocks that are on the free list.
Address     Size         Address of the next block:
----------  ---------    --------------------------
0x78649d20  0x10 = 16    0x7864930
0x78649d30  0x18 = 24    0x7864948
0x78649d48  0x10 = 16    0x7864958
0x78649d58  0x18 = 24    0x7864970
0x78649d70  0x20 = 32    0x7864990
0x78649d90  0x10 = 16    0x78649a0
0x78649da0  0x18 = 24    0x78649b8
0x78649db8  0x10 = 16    0x78649c8
0x78649dc8  0x18 = 24    0x78649e0
0x78649de0  0x18 = 24    0x78649f8
0x78649df8  0x18 = 24    0x7864e10
----------  ---------    --------------------------
Part C: You'll need a block whose size is at least 24 bytes, so the first free block will not do. The second one, starting at 0x78649da0 will work, so you need to return a pointer eight bytes greater than the beginning of the block. The answer is: 0x78649da8.

Part D: It will not segfault, because it is in the same page as the end of the heap (0x78649e0c), and the operating system / hardware do address protection checks at the page granularity. For that reason addresses 0x78649e10 to 0x78649fff are all valid.

Part E: This is a problem, because we have a block of free memory that is "after" the end of the heap. The problem will manifest in the following sequence of operations:

Other sequences are possible, but they have to include grabbing more memory with sbrk(), and using that block on the free list, in either order.

Grading

Eight points for parts A and B. Three points for part C, giving half credit for da0, and 0.5 for d4c, dfc and d38. Three points for part D and two for part E. You had to say "No" and something about paging for full credit on part D. If you gave a good explanation for part E, given that you said "yes" to part D, you received full credit.