CS 702 - Operating Systems - Fall 2007
Project 3


Loyola College > Department of Computer Science > Dr. James Glenn > CS 702 > Projects > Project 3

Due

Wednesday, November 28th at 11:59pm. Projects will be penalized 20% for each day after the due date. Projects will not be accepted more than four days late.

Objectives

Introduction

You have been given code (see the Files section below) that implements a user-level threading system for Linux and g++ 3.x using cooperative multitasking (check that you are running a compatible version of g++ with the command g++ --version). Threads are implemented as instances of the Thread class. Threads are started by calling their start method, which then calls the run method. Subclasses of Thread should override run to define the behavior of the threads. Threads can call Thread::yield to allow other threads to gain control of the CPU.

The Scheduler class defines a set of static methods that manage the threads. Scheduler maintains a queue called readyQ of pointers to Thread objects. Whenever a thread yields, it is placed on the back of the queue (in threadYielded) and another thread is chosen to run (by scheduleThread). When there are no threads left to run, the system terminates.

As given, there is no mechanism for thread synchronization or I/O.

Assignment

There are four parts to this assignment:

To implement condition variables, you will have to implement the blockThread(Thread*, const Condition*), wakeupOne(const Condition *) and wakeupAll(const Condition *) methods in the Scheduler class. Test your modifications with the wait_test.x program. Before making your modifications, thread 1 will finish before thread 3 even though thread 1 calls wait to block until thread 3 terminates. Once your modifications are correct, thread 1 will terminate after thread 3.

To implement monitors, you must implement the enter, leave, suspend, and reenter methods in the Monitor class.

The current implementation of Thread::sleep does nothing. If you change it to use the system sleep call, then the sleeping thread will block the entire thread system. Instead, you should change it so it calls the block(Blocker *) method in the Thread class. The Blocker object should be created to record information the scheduler will need to determine when to restart the thread (in this case, the time at which the thread should wake up). Thread::block(const Blocker *) has been written so it calls Scheduler::blockThread(Thread *, const Blocker *); you should change this method so it saves the information it is given and schedules another thread. You should also change scheduleThread so it will check the threads that have called sleep and move them back to the ready queue once they've slept long enough. You can use gettimeofday from sys/time.h to determine the current time (measured in microseconds since January 1, 1970):

  struct timeval tv;
  gettimeofday(&tv, NULL);
  // tv.tv_sec * 1000000LL + tv.tv_usec is now microseconds since 1/1/1970
(do man gettimeofday for more details).

The current implementation of Thread::getchar simply calls the getchar method from stdio.h to read a character from the keyboard. If no character is available, this will block the entire thread system. You should change Thread::getchar so it calls Thread::block(const Blocker *) before it tries to read. This time, the Blocker object should record that the blocked thread is trying to read from the keyboard. The scheduler will have to be modified so that if threads are waiting for keyboard input it will use select from sys/select.h to determine of those threads can be moved back to the ready queue:

  fd_set readfds, writefds, exceptfds;
  FD_ZERO(&readfds);
  FD_SET(0, &readfds); // stdin = descriptor 0
  FD_ZERO(&writefds);
  FD_ZERO(&exceptfds);
 
  timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = 0;
 
  int result = select(fd + 1, &readfds, &writefds, &exceptfds, &timeout);

  // result is 1 if there is keyboard input available
(do man select for more details).

Files

You will need the archive p3.tar.gz (or p3_cygwin.tar.gz for use with Cygwin); you can extract the files contained in the archive with the command
zcat p3.tar.gz | tar xvf -

and then build the program with the commands using the supplied makefile with the command make.

If you do not have NASM installed, you can try using the preassembled object files thread_asm.o and scheduler_asm.o.

Advice

The STL queue class is probably not suitable for the blocked queue since you can't iterate through an STL queue. You can use list instead.

For debugging, you may want a method that prints the the addresses of the threads on the ready queue and the blocked list.

You may want to treat threads that have blocked using wait and threads that are blocking on a timer or on I/O differently.

Grading

Your grade will be determined by how many test cases execute correctly. There will be additional test cases besides the one in the given archive. If you cannot get the published tests to work, you should write simpler tests to show what functionality you have been able to implement.

Submissions

Submit an archive containing the files necessary to build and run your completed program. Send the archive as an attachment to an e-mail. sent