THE PROBLEM

CS 3750 -- Operating Systems I
Statement of the "Packet Protocol" Concurrent Programming Problem

User #0    User #1
  |  \    /  |
  |   \  /   |
  |    \/    |
  |    /\    |
  |   /  \   |
  |  /    \  |
Buffer #0  Buffer #1
  |  \    /  |
  |   \  /   |
  |    \/    |
  |    /\    |
  |   /  \   |
  |  /    \  |
Agent #0  Agent #1
Write the synchronization for a program that uses four threads in one task to simulate the situation depicted in the diagram above. There are two user threads and two agent threads.

The idea depicted by the diagram can be stated this way: There are two different types of packets, say ethernet packets and token ring packets. User #0 and User #1 are long-running applications that sometimes need to send a packet. Each user sometimes needs to send an ethernet packet, and each user sometimes needs to send a token ring packet.

Buffer #0 and Buffer #1 are two different specialized communication endpoints. Buffer #0 is designed for ethernet packets - only ethernet packets, and Buffer #1 is exclusively for token-ring packets. When a user thread has a packet it needs to send, it has to copy the packet into the buffer that corresponds to the packet type.

Agent #0 and Agent #1 are responsible for servicing Buffer #0 and Buffer #1, by copying out and then transmitting packets. The agents are not "specialists." Each agent is able to service either buffer. (This might be a performance advantage. Suppose one of the buffers gets two packets in a row, and one of the agents copies out the second packet while the first agent is busy transmitting the first packet.) Agent #0 and Agent #1 both continually scan both buffers, looking for one that is full and not yet being serviced by the other agent.

Clearly these threads have to synchronize some of their actions with each other. For example, we can't have two users writing data into the same buffer at the same time. We can't have an agent copying a packet out of a buffer while a user is writing a packet into the buffer. We can't have the same packet copied out (and transmitted) twice.

User threads run in a loop, for as long as desired. In each iteration of the loop, a user: The "packet" contains only the id number of the user (0 or 1) and a current packet serial number. To keep the program simple, the threads don't actually put any message data into the buffers. However, as you write your solution code, keep in mind that it is supposed to work flawlessly, no matter how much data is in each packet.

agents also run in a loop, as long as users are active. In each iteration, an agent: In creating the synchronization code, you may find it is convenient to use one or more flags or status variables associated with each buffer. (However, remember that such variables are typically shared among two or more threads, so it is a critical section problem to regulate access to them.)

Your program must carefully prevent concurrent threads from corrupting the contents of shared variables. On the other hand, a thread must never unnecessarily prevent another thread from making progress.

To enforce exclusive access to shared buffers, and to prevent critical operation from being performed out of order, you must use semaphores implemented by sem.h and sem.cpp. The exact manner in which you employ the semaphores is for you to decide.

users will write a specific output immediately after they place a packet in a buffer. Example:
Copy IN:        Packet #0 of USER #1 into buffer #0
The threads must be synchronized in such a way that a line of output like the one above is always written on the screen before the message of an agent appears on the screen, saying the agent has copied this packet out of the buffer.

Agents have to cooperate to make sure that only one agent copies out each packet. Each agent can and will copy packets out of either buffer, in effect 'competing' with the other agent to copy out as many packets as possible as soon as possible. The agents must be programmed in such a way that if one agent is delayed for some reason, the other agent must automatically 'take over' and do all the work, copying all packets from both buffers. If one agent is busy working with the packet from one buffer, and if there is a packet in the other buffer that needs to be copied, then there must be nothing to prevent the other agent from immediately working on the other buffer. Agents will write a specific output immediately after they copy a packet from a buffer. Example:
AGENT #1 copies packet #145 of USER #0 from buffer #1.
After a message on the screen announces that a user has copied a packet into a buffer, the very next message about the buffer has to be the one announcing that the same packet has been copied out.

So, for example, after we see this message,
Copy IN:        Packet #145 of USER #0 into buffer #1
the next message having to do with buffer #1 has to be
AGENT #0 copies packet #145 of USER #0 from buffer #1.
or
AGENT #1 copies packet #145 of USER #0 from buffer #1.
Note: User and agent messages must be formatted so that the packet, user, and buffer numbers all line up in columns. This will make it a lot easier to check outputs. The shell program provided to you formats the statements this way.

To test your program, you will use code in critical places that delays each thread by a random amount of time. We do this by generating a random integer n, and then making the thread execute

	for (i = 0; i < n; i += 1)  sched_yield();