Operating Systems Spring 2011

Exercise 3: A Multi-threaded Output Device

He who holds me by a thread is not strong; the thread is strong.
                                                                    Antonio Porchia, Voices

Due Date: 10/4/2011

Before you start, don't forget to read the course guidelines!

Assignment

Consider an output device in multi-threaded system that accepts output tasks from several client threads concurrently. Each client thread task comprises of writing a block of data to the output device as a single uninterrupted atomic operation. A trivial implementation is to have a single lock that protects the device, where each client thread gets the lock, performs the operation and then releases the lock. Your task is to implement an efficient non-blocking package, which is delivered in the form of a static library. In other words, you will implement a daemon thread that queues client threads' output tasks requests and write these tasks asynchronously to the device, which is simulated, in this exercise, as an output disk file.

The public interface of your library is given by outputdevice.h and explained below. Obviously, there are few internal functions (and data structures) that you might find necessary to implement. These functions are not visible outside the library; therefore, you are not restricted in their number, signatures, and content as they are part of your private implementation.

int initdevice(char *filename)

The function creates the output file filename if it does not exist and opens the output file for writing (appending if the file exists). This function should be called prior to any other functions as a necessary precondition for their success.

Return values are 0 on success, otherwise -1.

int write2device(char *buffer, int length)

The function writes the input buffer (which is of length size) to the output file. The buffer may be freed once this call returns (You should deal with any memory management issues). Note this is non-blocking package you are required to implement, therefore, you should return ASAP, even if the buffer has not yet been written to the disk.

On success, the function returns a task_id (>= 0), which identifies this write operation. Note that you should reuse task_ids when they become available. On failure, -1 will be returned.

void flush2device(int task_id)

The function blocks until the specified task_id has been written to the file. The task_id is a value that was previously returned by write2device function. In case of error, the function should cause the process to exit (not return -1).

void closedevice()

The function closes the output file and resets the system so that it is possible to call initdevice again. All pending task_ids should be written to the output disk file. Any attempt to write new buffers while the system is shutting down should cause an error.

Error Messages STDERR

Message Error Error Description
"system error\n" When system call fails
"Output device library error\n" The rest

Background reading and Resources

  1. Carefully read the pthread man-pages, which grouped into 3 major classes:
    1. Thread management: Working directly on threads.
    2. Mutexes: Dealing with synchronization ("mutual exclusion").
    3. Condition variables: Communication between threads that share a mutex.
  2. POSIX Threads Programming a good tutorial

Submission

Submit a tar file on-line containing the following: Do not change the header file. Your exercise should work with our version of outputdevice.h.

Guidelines