CS354 Spring 2003

Final Exam


Name: ____________________________________________


Question
Max
Grade
T/F
20pts

1-7
30 pts

8.
10 pts.

9.
10 pts.

10.
10pts.

11.
10pts.

12.
10pts.

Total:
100pts.



Part 1. Answer True/False (T/F) (1 point each)

____ Most of the CPU  time is spent in user mode.
____ a.out is an executable file format used in early versions of Windows.
____ The backing-store of the Text segment is swap space.
____ The stack of one thread could potentially be modified by another thread.
____ Premature frees are a serious problem in short lived programs.

____ A page size has to be a power of 2.
____ The page table register is always updated during a context switch.
____ By default, when a thread calls mutex_lock for the same lock twice, the second mutex_lock call will be ignored.
____ All pages in physical memory that are replaced are written back to the disk.
____ The call realloc( NULL, 100) will cause a SEGV.

____ calloc( 8, 1 ) allocates 8 bytes initialized with 1s.
____ BEST FIT is faster than FIRST FIT.
____ Copy on write is used during fork().
____ An object returned by malloc could have an address like 0x100280.
____ The order of mutex_unlock()'s could lead to deadlocks.

____ Most processes in a system are in wait state.
____ Non-accessed pages are prefered for replacement instead of modified pages.
____ A free list that has two blocks of 20 and 80 bytes has a fragmentation of 80%.
____ A call to fork() by a process that has two POSIX threads will create a child process with two threads.
____ During starvation a thread waits for a resource or mutex lock that may never be available.
 

Part 2. Short Questions

1. (4 pts) Enumerate the steps of the life cycle of a C program as covered in class.
 
 
 
 
 
 
 
 
 
 

2. (4 pts) A parent process P1 calls fork() and creates a child process P2. Explain step by step what the OS will do when a page is modified by process P1.
 
 
 
 
 
 
 
 
 

3. (4 pts) Explain how the clock algorithm for page replacement works. Explain how it is improved using also the modify bit.
 
 
 
 
 
 
 
 

4. (4 pts) Give one example of a premature free?

 

 
 
     Give one example of a memory leak 
 
 



5. (4 pts) Assume that we the allocator described in project 7 is used with the following code:

    int * a = (int *) malloc( sizeof(int) );
    int * b = (int *) malloc( sizeof(int));
    b[ 0 ] = 3;
    a[ 1 ] = 5;
    printf( "b=%d\n", b[0] );
    free( b );

    What is  the value printed?
     
   

     Explain what is going to happen during the free() call.



6. (5 pts) The following three threads have access to six databases. Each database has its own mutex lock.
Could the following threads enter in a deadlock? If that is the case draw the graph that shows the loop that represents this deadlock, and draw in the right side the code that could prevent the deadlock. Give specific mutex numbers when drawing the graphs
If the threads cannot enter into a deadlock, give an alteration of the the mutex_lock call sequence that may lead to a deadlock and draw a graph with the loop that represents this deadlock.


thread1()
{
    for ( int i = 0; i < 10000; i++ ) {
        for ( int j = 0; j < 2; j++ ) {
           for ( int k = 0; k < 2; k++ ) {
      mutex_lock( &mutex[ j ]);
      mutex_lock( &mutex[ k ]);

            // Call some code

      mutex_unlock(  &mutex[ j ]);
      mutex_unlock(  &mutex[ k ]);
     }
    }

  }
}

thread2()
{
    for ( int i = 0; i < 10000; i++ ) {
          for ( int j = 0; j < 2; j++ ) {
             for ( int k = 0; k < 2; k++ ) {
        mutex_lock( &mutex[ j ]);
        mutex_lock( &mutex[ k ]);

              // Call some code

        mutex_unlock( &mutex[ j ]);
        mutex_unlock( &mutex[ k ]);

      }
    }

   }
}

7. (5 pts) Add the necessary code to the insert() and removeFirst() functions to make them synchronized.  removeFirst() will have to wait if the list is empty. insert() will have to wait  if there are already 10 elements in the list. Use condition variables. Add also the variables you need.

struct List {
  int val;
  int next;
};

struct List * head = NULL;

// More variables


void insert( int val )
{


  List tmp = new List;

  tmp->val = val;

  tmp->next = head;

  head = tmp;

}

Struct List * removeFirst()
{

  List tmp = head;


  head = tmp->next;

}

Part 3 Long Questions. (10 points each)

 
8. (10 pts) IMPORTANT: Use condition variables in this problem. Complete the class MReadNWriteLock that is a generalization of the  read/write locks but that limits the number of readers to M and the number of writers to N. This kind of  locks allows at most M readers or N writers but not both. For example, if at least one thread is holding the lock in write mode, reader threads will have to wait but not writer threads. If at least one thread is holding the lock in read mode, writer threads will have to wait. It is possible to have up to M reader threads. If thread M+1 tries to read, it will block until another reader thread unlocks the lock. It is possible to have up to N writer threads. If thread N+1 tries to write, it will block until another writer thread unlocks the lock.
class MReadNWriteLock {
  /* Add other fields here */
 
 
 
 
 

public:
  MReadNWriteLock( int m );
  readLock();
  writeLock();
  readUnlock();
  writeUnlock();
};

MReadNWriteLock ::MReadNWriteLock ( int m )
{
 
 
 
 
 
 
 
 

}

void
MReadNWriteLock ::readLock()
{
 
 
 
 
 
 
 

}

void
MReadNWriteLock ::writeLock()
{
 
 
 
 
 
 
 

}

void
MReadNWriteLock ::readUnlock()
{
 
 
 
 
 
 
 

}

void
MReadNWriteLock ::writeUnlock()
{
 
 
 
 
 
 
 
 

}
 


 

9. ( 10 pts.) From your malloc implementation write the code that maps the block size to the corresponding free list index. Return the corresponding list index even if the list is empty.

int sizeToFreeListIndex( int sizeRequested )
{
  // Return the index of the corresponding free list from the sizeRequested.
  // sizeRequested is the size passed to malloc()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

}
 


 

10. (10 pts.) From your implementation in project 7, write the code for free(ptr) that determines if the left object is free and coalesces it with the object being freed if possible.

void free( char * ptr ) {

  . . . .

  // Determine if left object is freed and coalesce with the freed object if possible.


























}



 

11. ( 10 pts.) Write a procedure that executes the function
"grep filter1 file1 | grep filter2 > file2"

using fork, execvp, pipes and output redirection.


int grepFilter1GrepFilter2( char * filter1, char * file1,
                            char * filter2, char * file2
)

{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

}


 


 
12. (10 pts.) IMPORTANT:Use condition variables and mutex locks for synchronization in this problem. Implement a name table class using an array of TableEntry struct's. The constructor NameTable(max) will allocate space for a table with n entries. The function add(var,val) will block until there is space in the table, then it will search for an entry in the table that is unused ( _var and _val are NULL) and it will add the var and val strings in that entry. Duplicated values are allowed.
The function lookupAndRemove(var) will lookup the string var in the table, will clean up the entry from the table,  and it will return the corresponding value. If the variable does not exist, lookupAndRemove(var) will wait until that variable is added with the add() function. Add the condition variables and mutexes that are necessary and the code that implements the behavior described.
struct TableEntry {
  char * _var;
  char * _val;
  // Other variables here

  
};

class NameTable {
  // Max length of table
  int _max; 

  // Array of TableEntry entries 
  TableEntry * _table;

  // Other variables here
 
 

public:
  NameTable(int max) {
   


struct TableEntry {
  char * _var;
  char * _val;
  // Other variables here

  
};

class NameTable {
  // Max length of table
  int _max; 

  // Array of TableEntry entries 
  TableEntry * _table;

  // Other variables here
  

public:
  NameTable(int max) {


   



  }

  void add(char *var, char *val) {






    




  }

  char * lookupAndRemove(char * var) { 









 

 

    }

};