Project 2 - Performing Interprocess Services

Due 11:59 pm on October 15th, 2008 (First day after fall break)

Note:

The project has been simplified. Please reread the requirements as they have changed.

Goal

Your goal in this project is to create a service that can be accessed from any process on the system. In order to support this service, you will be creating a library of calls to access this service. This service must allow blocking (synchronous) calls, Quality of Service (QoS), and nonblocking (asynchronous) calls to it. You may work in pairs on this project. You may share ideas with other pairs, but you may not share code. You also may not download code or use any other external libraries without consulting the instructor or TA first.

To get full credit for this project you must implement the following:

Each will be discussed in turn.

You must submit your deliverables to the TA, Scott McManus (smcmanus@cc), by 11:59 pm on Wednesday, October 15th, 2008 (the first day after fall break). If you do not get an email acknowledgment, then the TA has not received it. Email to any other address will be ignored.

Overview

In Xen, there is a domain called Dom0 which, among other things, handles requests from operating systems for performing I/O. The operating systems place their data for the operation (e.g., a file write) on a ring buffer, and Dom0 handles the requests in turn.

You will be creating an analog of Dom0 which will handle requests for a service. You will be defining a sample service that makes sense to you. Some examples include:

All of these examples have a common theme - a process requests something from the service, and the service performs some action and sends back a response.

There are some more requirements for this service. First, this service will need to support synchronous calls, which means that the caller has to block until the call is complete and the result is delivered. All of the data carried in this service must be done in shared memory. Next, this service must support Quality of Service (QoS) mechanisms which implement fairness among the processes. Finally, the service will need to support asynchronous calls, where the caller will call the service and then continue to run while the service request is being processed. Note that the asynchronous call must have some method to deliver the result back to the caller while the caller is still executing.

Synchronous (Blocking) Communication

Your job is to build a library for accessing such a service. This library will consist of: an API for sending requests and getting back a response (in the same function call); a library (or at least object files) that your applications can link in; and a service process that will manage the input requests and send back a response.

The library you write will need an initialization function that establishes the control structures that you may want to use in your library - queue(s), any common shared memory region you want to use in your library, and so on. Next, you will need functions for your library that allows blocking (synchronous) calls to the service that you create. Here, a blocking/synchronous call means that the sender will block until the caller has gotten a response from the service.

Your design must incorporate the concept of a service process that actually executes the service. The service process can use one or more queues on which to queue up requests; how many you choose to use is left to your design. Note that you will need to use shared memory for all of the data that is sheperded back and forth. The service process also can be started as a daemon if you wish, which also means that the service process can be started as a separate process from the command line (which will almost certainly be needed).

Since you have freedom in your design, you must document the design itself, any logic as to why you chose it, any shortcomings that the design may have, and any part of your design that you failed to implement.

In order to get full credit for this section, you must create the synchronous service, the library & API to support the service, and write up its design as described.

Quality of Service

So far your service allows any process to use it, but it has no concept of fairness. For example, suppose in 1 second that process P1 first sends 100 requests, then process P2 sends 10 requests, and then process P3 sends 2 requests. If all of process P1's requests are answered first, then service is denied to processes P2 and P3. Alternately, it's not clear how many requests of P1 should be serviced before P2's and P3's requests are serviced.

Here you will be developing a Quality of Service (QoS) mechanism for your shared memory service. The mechanism must take into account both fractional access and message priority. For fractional access, the service process alternates servicing requests among processes according to the fraction of the service that they've been granted. For example, if there are 4 processes that are each granted 25% of the write access, then the QoS mechanism would essentially round-robin access among the 4 processes. In another example, process A may be granted 1/2 of the service requests, process B may be granted 1/3 of the service requests, and process C may be granted 1/6 of the service requests. Then over the course of 6 messages the service process will handle 6 * 1/2 = 3 of A's messages, 6 * 1/3 = 2 of B's messages, and 6 * 1/6 = 1 of C's messages (though not necessarily in that order). Designing this QoS mechanism is also one of your tasks.

Your sender should also be able to set the priority of the request. By default, the request has the default lowest priority. However, the caller may choose a higher priority than the default priority. Your design does not need a complicated priority scheme, but your priority QoS policy must account for at least one priority level above normal priority.

Note that a high-priority request will count as a message against the fractional policy. In the previous example with processes A, B, and C, where the processes had 1/2, 1/3, and 1/6 of the queue, respectively, suppose that process B sends a single high-priority request. Normally B would have 6 * 1/3 = 2 requests to send over the course of any 6 requests, but now it will have only 1 message that it can transmit - its high-priority request took the slot that its normal-priority request used. The idea is that, although a process's high-priority requests will be handled first, a process cannot (as easily) cheat its QoS request allocation. Put another way, if all processes decide to use a higher priority for their requests, then the high-priority scheme will still defer to the fractional access policy previously described.

Again, you have full control over the design that you implement. For example, you may choose to implement a single queue that the service process must re-examined to determine what message to process next, or you may choose to implement multiple queues - say, one queue per communicating process plus a high-priority queue. Since there is such freedom in choosing your design, you must document it, the reasons why you chose it, any shortcomings it may have, and what in your design was not implemented.

For full credit, you must implement and document the QoS mechanism as described.

Asynchronous Communication

There are times when a process will send a request, but it does not want to wait for the response. This form of request is called asynchronous because the process does not have a specific time ordering with respect to its computations and the receipt of a response. At first glance this may seem easier than synchronous (blocking) communication because the sender does not have to wait for a message, but that is not the case. The transmitting process must still potentially need to know when a message has been acknowledged - there may be structures (including the message itself) that can be cleaned up once the message has been received, or certain application logic may start up or continue once the recipient has acknowledged the message.

For this part of the project you will need to implement asynchronous communication. You have a choice as to how the message sender can choose to determine that a message has been delivered. The first choice is to implement a blocking function call that determines if a message has been delivered or not. The second choice is to let the message sender register a callback function that is called when the original message has been received. This also requires that the callback function be called with a reference to the original message. In either case, you will need to think about how to notify the calling process that the request is complete and to deliver any data in the response.

The library you implement must have some way to specify a blocking call versus a nonblocking call. Ideally, it should be possible to have both uncompleted synchronous and uncompleted asynchronous calls pending completion at the same time.

As before, you have a lot of latitude on your design and you must document it, its shortcomings (if any), and shortfalls in implementation.

For full credit on this section, you must implement the asynchronous facility and write up its design as previously described.

Sample Application

Your sample application must exercise all the functionality of your library and service - synchronous requests, QoS, and asynchronous requests must all be demonstrated. In particular, your asynchronous service application must force nonordering in your computation: when the service process receives a message, the service process must do some amount of nontrivial processing with that request. (That way you can demonstrate the queue management in your service process.)

Here are some ideas as to what your application can be; these are repeated from the beginning of the project description:

You will receive full credit for this section if your application meets these criteria. You may be asked to demo your application to show that it works.

Documentation/Write Up

Finally, your documentation/write up needs to describe your design, what you've implemented, and what your sample application performs. It should describe your API, your service process, and anything else that is significant in your project. If there is missing functionality or functionality that doesn't work as required, then it must be documented. You will receive full credit for this section if these requirements are met.

Hints and Tips

First, you will need some sort of queue to send messages to another process, and you will need to lock access to that queue. For that it is recommended that you check out the POSIX library's message queue and semaphores. The message queue is available via functions that start with "msg" - msgget, which creates the queue; msgsnd, which places a message on a queue; and msgrcv, which pulls a request off of a queue. The semaphore access is similar, with semget being the primary function of interest.

You should also become familiar with shared memory functions such as the following:

You can also consider the following memory mapping functions, which can be a replacement for shmget:

What makes the shmget/shmat more attractive than shm_open/mmap is that they are part of the POSIX library, which also has access to the potentially useful semaphore and message queue brethren. These calls basically replace "shm" with "sem" (for "sem"aphore) and "msg" (for message queue). What you use is up to you and your partner. Any other external library must be cleared by the TA or the instructor first.

Here are some general hints and tips:

Useful Resources

Brecht et al, "Evaluating Network Processing Efficiency with Processor Partitioning and Asynchronous I/O" , EuroSys 2006