/Teaching/System Level Programming/Assignments/A4
Pull from upstream before solving this task.
Task: Interprocess Communication (IPC)
This assignment aims to teach you the basics of interprocess communication (IPC), its use and how you can realize it.
Main Idea
Everybody of us has used interprocess communication already. Mostly unintentionally at this point in your studies. This is why we wanted to take this specific topic into this semester’s course.
To understand the concept of IPC, some major concepts must be learned and understood beforehand.
- Virtual Memory
- Process vs. Thread
- Shared Resources
- Locking
Some of those terms are already familiar to you, others not. We will not entirely go into details for this assignment, but it’s always useful looking up information based on those keywords.
Implementation details: Airport Communication
For this assignment you will have to implement a simple airport communication system, which consists of one tower process and multiple concurrent service/plane processes communicating with each other using shared memory.
The tower process is the initial process, creating and owning the shared memory objects of the airport; it also spawns all service and plane processes. For initializing the shared memory, CAREFULLY take a look at the defines in common.h
. It not only contains the expected shared memory object names, but also flags for permissions, all the pre-defined structs, and the shm_locks_t
struct where you must put all your shared locks.
This assignment focuses on your understanding of shared memory, shared synchronization, processes, implementing the radio transceiver, IPC, and cleaning up everything properly again. Other aspects of this assignment, this especially includes the airport logic, are already fully implemented for you, except for potential missing synchronization for shared memory accesses.
You MUST NOT change predefined function signatures, sequences of checks or similar. Exploits will automatically result in deductions! Do not remove or add any usleep or assert statements!
Airport Structure
The airport within this assignment is a very watered-down version of a real-life airport. We have modelled three key participants of an airport:
- Tower: It is the controller of the live action at an airport and always has the final say regarding all movements around the airport. Within this assignment, there ever only exists one tower.
- Plane: Transports passengers from/to the airport. Each plane is a separate process, and is either inbound (wants to land and de-board), or outbound (wants to board and take off).
- Service: Small utility vehicles providing various services (fuel, baggage, food, etc.) to planes. Each plane is serviced once.
In order for all participants to be able to communicate with each other, there is a tower frequency installed within shared memory (shm_tower_freq_t
struct). It is the key struct over which messages are sent. The shm_locks_t
holds the shared synchronization primitives added by you.
To use the tower frequency, each participant needs to be able to both transmit and receive messages, which is accomplished by the radio transceiver in transceiver.h
. Each participant process has a local instance of this transceiver, as well as a local message send queue. Your task will be to implement this in transceiver.c
, which is key for the IPC aspect of this assignment.
There are no bad actors on the frequency nor valid participants sending junk messages. Not locally, not on the test system. You thus don’t need to worry about cases where a message is sent but the receiver participant does not exist, this will not happen, assuming your implementation of shared memory and the transceiver is correct.
Your Tasks (in no particular order)
- Set up shared synchronization primitives
- Add all necessary mutexes, semaphores and/or condition variables to the struct declaration of
shm_locks_t
incommon.h
- Initialize them in the function
initLocks()
intower.c
- Add all necessary mutexes, semaphores and/or condition variables to the struct declaration of
- Set up shared memory in
tower.c
,plane.c
, andservice.c
- Create shared memory objects in the functions
initAirportSHM()
,initPlaneSHM()
andinitServiceSHM()
- Map the shared objects into the process’ memory in the functions
initAirportMappings()
,initPlaneMappings()
andinitServiceMappings()
- Initialize the mapping in
initPlaneState()
- Create shared memory objects in the functions
- Spawn the service vehicle and plane processes in
tower.c
- Start the correct executable with the needed arguments for each service vehicle in
spawnServiceVehicles()
- Start the correct executable with the needed arguments for a plane process in
spawnPlane()
- Start the correct executable with the needed arguments for each service vehicle in
- Implement clean up in
tower.c
,plane.c
, andservice.c
- Wait for all spawned processes to terminate in the function
waitForSpawnedProcesses()
- Clean up shared mutexes, condition variables and/or semaphores in the function
cleanupAirportResources()
- Remove all mappings and shared memory objects in the functions
cleanupAirportResources()
,cleanupPlaneResources()
andcleanupServiceResources()
. Set closed file descriptors to-1
and pointers to unmapped memory regions toNULL
.
- Wait for all spawned processes to terminate in the function
- Ensure sufficient synchronization between the participants of the airport in
tower.c
,plane.c
andservice.c
- Go through the main communication loops in the functions
starttower()
,startplane()
andstartservice()
- Add synchronization wherever it is needed
- Go through the main communication loops in the functions
- Implement all functions of the radio transceiver
- Look at the docstrings of the functions in
transceiver.h
and implement them accordingly intransceiver.c
- Make sure of proper synchronization. Add mutexes, semaphores and/or condition variables to the struct
RadioTransceiver
intransceiver.h
- Optionally declare/implement custom transceiver utility functions in
transceiver.h
/transceiver.c
- Look at the docstrings of the functions in
- Optional: Create custom utility functions in
common.h
andcommon.c
Communication Protocol Reference
This section serves as a reference for the communication protocol. As it is already implemented for you, it simply lists the commands and who sends what to whom, without going into details. You can use it to compare your airport’s behavior to the reference behavior.
Inbound Plane Communication Protocol
This protocol applies to inbound planes only.
plane -> tower: HELLO tower -> plane: HELLO plane -> tower: REQUEST_LANDING (optional) tower -> plane: EXPECT_RUNWAY { runway_idx } plane -> tower: ACKNOWLEDGE (/optional) tower -> plane: CLEAR_TO_LAND { runway_idx } plane -> tower: ACKNOWLEDGE plane: doLanding() plane -> tower: LANDING_COMPLETE { runway_idx } tower -> plane: ACKNOWLEDGE plane -> tower: REQUEST_GATE tower: possibly do later tower -> plane: TAXI_TO_GATE { gate_idx } plane -> tower: ACKNOWLEDGE plane: doTaxiToGate() plane -> tower: REQUEST_SERVICE { gate_idx } tower -> plane: ACKNOWLEDGE tower: possibly do later tower -> service: SERVICE_BEGIN { plane_idx } service -> tower: ACKNOWLEDGE service: doServiceActions() service -> tower: SERVICE_COMPLETE tower -> service: ACKNOWLEDGE service -> plane: SERVICE_COMPLETE plane -> service: ACKNOWLEDGE plane -> tower: DEBOARDING_COMPLETE tower -> plane: ACKNOWLEDGE plane -> tower: BYE tower -> plane: BYE Plane: exits process after this message
Outbound Plane Communication Protocol
This protocol applies to outbound planes only.
plane -> tower: HELLO tower -> plane: HELLO plane -> tower: REQUEST_GATE tower: possibly do later tower -> plane: TAXI_TO_GATE { gate_idx } plane -> tower: ACKNOWLEDGE plane: doTaxiToGate() plane -> tower: REQUEST_SERVICE { gate_idx } tower -> plane: ACKNOWLEDGE tower: possibly do later tower -> service: SERVICE_BEGIN { plane_idx } service -> tower: ACKNOWLEDGE service: doServiceActions() service -> tower: SERVICE_COMPLETE tower -> service: ACKNOWLEDGE service -> plane: SERVICE_COMPLETE plane -> service: ACKNOWLEDGE plane -> tower: BOARDING_COMPLETE tower -> plane: ACKNOWLEDGE plane -> tower: REQUEST_TAKEOFF (optional) tower -> plane: EXPECT_RUNWAY { runway_idx } plane -> tower: ACKNOWLEDGE (/optional) tower -> plane: CLEAR_TO_TAKEOFF { runway_idx } plane -> tower: ACKNOWLEDGE plane: doTakeOffApproach() plane -> tower: TAKEOFF_COMPLETE { runway_idx } tower -> plane: ACKNOWLEDGE plane -> tower: BYE tower -> plane: BYE Plane: exits process after this message
Service Termination Protocol
This protocol applies to service vehicle termination only.
tower -> service: SERVICE_TERMINATE service -> tower: ACKNOWLEDGE Service: exits process after this message
Some further hints
What to do before you start?
- Pull from upstream!
- Try to understand the program structure.
- Carefully read the Manpages and/or the POSIX standard on the needed functions.
- Only begin, if you understand the basic concept of processes, virtual memory, shared resources as well as mapping them. Bruteforcing will lead to a severe amount of wasted time.
tower.h
,plane.h
,service.h
, and theMakefile
MUST NOT be changed and will cause a deduction of 100% on the test system.- You are not allowed to alter existing code or add new code, except within the
TODO STUDENT
blocks. If you need to add custom utility functions, there are areas marked for this incommon.h
andcommon.c
as well as intransceiver.h
andtransceiver.c
. - Do not push binary files or any other junk files.
- Carefully read the TODOs and header docstrings. Some contain crucial information!
Build and run your airport with the provided Makefile on your local machine with make all
(compiles all sources) and make run
(starts the airport). Solely relying on the test system will not get you far.
Play around with the NUM_{RUNWAYS|GATES|SERVICES|PLANES_TO_SPAWN}
constants in common.h
and check how your airport behaves under heady load. Note that your airport communication will be stress-tested on the test system, so it is heavily advised to also stress-test your airport on your local machine.
What is this anti-ghost thing?
It is a convenience tool ensuring any processes you spawned (services and planes) are terminated when the tower exists. When you implement waitForSpawnedProcesses()
properly, anti-ghost does nothing, else it will send a termination signal to processes not cleaned up by you. This tool is there because you else have to deal with ghost processes when your tower crashes, which then act on the still open shared memory segment and cause funny bugs. Anti-ghost only runs on your local machine, and does not exist on the test system. Relying on the anti-ghost is thus not a valid approach for proper cleanup of all processes.
The tool’s output is only informative. The test system is authoritative in determining if you implemented the wait logic correctly.
Submission
Modify the files in your git repository. You can find this assignment’s files in the A4
directory.
Tag the submission with A4
and push it to the server. You may remove and re-push the A4
tag any time you like before the deadline.
Assignment Tutors
If you have any questions regarding this assignment, go to Discord and read through the SLP channels. The probability that your question was already answered or some discussions will lead you in the right direction is quite high. If not so, just create a new thread with the A4
flair applied.
If you have a more direct question regarding your specific solution, you can also ask the tutors who organize this assignment:
Patrick Goldinger, patrick.goldinger@tugraz.at
Simon Schiller, simon.schiller@student.tugraz.at