CS560 Midterm Exam: March 16, 2006

James S. Plank

Answer All Questions


Question 1: 6 points

When a process is not currently executing, there are certain things that the operating system must maintain on behalf of the process, so that when the process starts executing again, it does so correctly. On the list below identify the things that the operating system must maintain on behalf of a non-executing process.

Answer this question using the answer sheet -- do not answer it here.

a.Interrupt vector.
b.Information about open files.
c.Register state.
d.Timer interrupt.
e.Control status register.
f.Console interrupt.
g.Memory management information (e.g. main_memory pointer).
h.Kernel/User mode bit.
i.Context switches.
j.Information about CPU speed.
k.The process' cache.
l.The PC location of the process' next instruction.
m.Turnaround time.
n.Disk controller information.

Question 2: 6 points

In the kthreads library, kt_fork() is implemented by allocating a new stack and TCB for the process, and then setting the state of the TCB to STARTING before appending it to the ready queue.

When the scheduler determines that it is time to schedule this new thread, detail for me exactly how it does so, from the time that the scheduler is called by a blocking thread to the time that the new thread is executing its procedure and arguments.


Question 3: 6 points

With you in the room, a colleague named Freddy says the following to your boss: "It's stupid to have both mutexes and semaphores in one thread system, because a mutex is equivalent to a semaphore whose initial value is one." Your boss agrees with him, and then after he leaves, asks you whether you think Freddy is correct.

Merit raises are going to be decided next week, and you have just been given a very nice opportunity to make sure that you, and not Freddy, get that merit raise. You need to be a positive thinker, validating that Freddy has the seeds of a good point, but then you need to demonstrate to your boss that Freddy is being shortsighted. What do you say to your boss?


Question 4: 10 points

Behold the typedef for a resource:

typedef struct {
  int instance;
  char *name;
  Semaphore *s;
} Resource;

In our system, resources are uniquely identified by the combination of their names and instance numbers.

Here are implementations of procedures called lock_multiple() and unlock_multiple(), which processes use to lock and unlock multiple resources:

void lock_multiple(Dllist resources) 
{
  Dllist tmp;
  Resource *r;

  dll_traverse(tmp, resources) {
    r = (Resource *) tmp->val.v;
    P(r->s);
  }
  return;
}

void unlock_multiple(Dllist resources) 
{
  Dllist tmp;
  Resource *r;

  dll_traverse(tmp, resources) {
    r = (Resource *) tmp->val.v;
    V(r->s);
  }
  return;
}

Clearly, if resources may be any list of resources, lock_multiple() and unlock_multiple() can deadlock. Rewrite them so that they cannot deadlock so long as:

In your solution, state why deadlock is prevented, and why the two above conditions are necessary to prevent deadlock with your answer.

You may not add any global variables to the system, and you may not augment the definition of a Resource. You also may not look at a semaphore's value.


Question 5: 10 points

Recall the job file job-10-cpu-vi-wav.txt from the scheduling simulator:

CPU-A  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-B  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-C  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-D  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-E  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-F  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-G  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-H  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-I  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
CPU-J  UNI 0 0 SERIAL UNI 10 10    UNI 0  0   UNI 180000000 180000000 UNI 1 1 CONSOLE
VI-1  EXP 1800 20 SERIAL  EXP 900 10    EXP 2 .2   EXP 500 0     UNI 1  1 CONSOLE
VI-2  EXP 1800 20 SERIAL  EXP 900 10    EXP 2 .2   EXP 500 0     UNI 1  1 CONSOLE
WAV   UNI    0  0 SERIAL  NORM 300 0    UNI 1  1   UNI 100 100   UNI .168 .168 CD-ROM

This job file has 10-CPU-bound processes, each of which runs for 10 iterations of 180 seconds of CPU time before pausing for trivial IO. It also has two VI processes, which feature very large sleep times, emulating a user typing at a vi console, and a WAV process which simulates a CD player. When this is simulated on a machine with a 50 millisecond timer interrupt and a context switch overhead of 200 microseconds, we see the following usage statistics:

ss-fcfsp job-10-cpu-vi-wav.txt machine-2.txt 100 100 QUIT=1000000

Time: 1000000.000000

Job Stats (Averages unless specified)

Name Completed Elapsed CPU RQ CS Sleep IO IO-Wait Max RQ Max IO-Wait
CPU-A 55 18086.186 1800.000 16278.248 7.937 0.000 0.001 0.000 0.453 0.000
CPU-B 55 18083.919 1800.000 16275.982 7.936 0.000 0.001 0.000 0.452 0.000
CPU-C 55 18081.610 1800.000 16273.675 7.935 0.000 0.001 0.000 0.453 0.000
CPU-D 55 18091.963 1800.000 16284.023 7.938 0.000 0.001 0.000 0.453 0.000
CPU-E 55 18090.888 1800.000 16282.948 7.939 0.000 0.001 0.000 0.454 0.000
CPU-F 55 18090.895 1800.000 16282.955 7.939 0.000 0.001 0.000 0.452 0.000
CPU-G 55 18091.356 1800.000 16283.417 7.938 0.000 0.001 0.000 0.454 0.000
CPU-H 55 18088.099 1800.000 16280.161 7.937 0.000 0.001 0.000 0.453 0.000
CPU-I 55 18085.833 1800.000 16277.896 7.937 0.000 0.001 0.000 0.455 0.000
CPU-J 55 18094.326 1800.000 16286.386 7.940 0.000 0.001 0.000 0.453 0.000
VI-1 263 2081.723 0.435 341.471 0.175 1739.555 0.087 0.000 0.502 0.000
VI-2 261 2008.683 0.419 329.326 0.169 1678.685 0.084 0.000 0.502 0.000
WAV 2041 489.677 0.031 133.132 0.062 309.595 46.858 0.000 0.502 0.000

Overall Stats

CPU Utilization Job Throughput Turnaround Time Avg. Wait Time Max. RQ Wait Time Max. IO Wait Time
99.54% 0.00312 3858.71 3019.70 0.502 0.000

Answer the following questions:


Prototypes

typedef struct dllist {
  struct dllist *flink;
  struct dllist *blink;
  Jval val;
} *Dllist;

extern Dllist new_dllist();
extern void free_dllist(Dllist);
extern void dll_append(Dllist, Jval);
extern void dll_prepend(Dllist, Jval);
extern void dll_insert_b(Dllist, Jval);
extern void dll_insert_a(Dllist, Jval);
extern void dll_delete_node(Dllist);
extern int dll_empty(Dllist);
extern Jval dll_val(Dllist);

#define dll_traverse(ptr, list) \
  for (ptr = list->flink; ptr != list; ptr = ptr->flink)
#define dll_rtraverse(ptr, list) \
  for (ptr = list->blink; ptr != list; ptr = ptr->blink)

typedef struct jrb_node {
  unsigned char red;
  unsigned char internal;
  unsigned char left;
  unsigned char roothead;  /* (bit 1 is root, bit 2 is head) */
  struct jrb_node *flink;
  struct jrb_node *blink;
  struct jrb_node *parent;
  Jval key;
  Jval val;
} *JRB;

extern JRB make_jrb();   /* Creates a new rb-tree */
extern JRB jrb_insert_str(JRB tree, char *key, Jval val);
extern JRB jrb_insert_int(JRB tree, int ikey, Jval val);
extern JRB jrb_insert_dbl(JRB tree, double dkey, Jval val);
extern JRB jrb_insert_gen(JRB tree, Jval key, Jval val, int (*func)(Jval,Jval));
extern JRB jrb_find_str(JRB root, char *key);
extern JRB jrb_find_int(JRB root, int ikey);
extern JRB jrb_find_dbl(JRB root, double dkey);
extern JRB jrb_find_gen(JRB root, Jval, int (*func)(Jval, Jval));
extern void jrb_delete_node(JRB node);  
extern void jrb_free_tree(JRB root);  
 
#define jrb_traverse(ptr, lst) \
  for (ptr = list->flink; ptr != list; ptr = ptr->flink)
#define jrb_rtraverse(ptr, lst) \
  for (ptr = list->blink; ptr != list; ptr = ptr->blink)

typedef union {
    int i;
    double d;
    void *v;
    char *s;
    char c;
    ...
  } Jval;  

extern Jval new_jval_i(int);
extern Jval new_jval_d(double);
extern Jval new_jval_v(/* void */);
extern Jval new_jval_s(char *);
extern Jval new_jval_c(char);
...
extern int jval_i(Jval);
extern double jval_d(Jval);
extern void *jval_v(Jval);
extern char *jval_s(Jval);
extern char jval_c(Jval);
...