Project #9: Multicore Interprocess Communication (IPC)

Submit: Turn in your entire xinu-hw9 directory source files using the turnin command on morbius.mscsnet.mu.edu or one of the other Systems Lab machines. Please run "make clean" in the compile/ subdirectory just before submission to reduce unnecessary space consumption.

Work should be completed in pairs. Be certain to include both names in the comment block at the top of all source code files, with a TA-BOT:MAILTO comment line including any addresses that should automatically receive results. It would be courteous to confirm with your partner when submitting the assignment.

Message Passing

Preparation

Make a fresh copy of your work thus far.
      cp -R xinu-hw8 xinu-hw9

There is no new tarball for the project. All of your modifications will be made to existing files, or to brand new files that you will create.

Message Passing

While the semaphores explored in a previous assignment do a decent job of allowing cooperating processes to communicate, many operating systems provide a more general mechanism for inter-process communication (IPC).

Build a simple message passing system for IPC between processes in your embedded operating system.

This can be accomplished in several steps.

Function send() takes a PID and a message, and sends it to the specified process. Function send() should perform error checking on the process ID, and check whether the destination process already has a message. If the destination process already has a message, send() should instead place the outgoing message in its own PCB's msgout field, enqueue itself on the destination process's msgqueue, and set its own state to PRSEND before yielding the processor.

Function sendnow() takes a PID and a message, and sends it to the specified process. Function sendnow() should perform error checking on the process ID, and should return a SYSERR if the intended destination already has a message waiting. If the intended destination process is already waiting for a message, sendnow() should unblock that process and yield the processor. Function sendnow() should not block.

Function recv() returns the message sent to the current process. If there is no message already, recv() should block, that is, put the current process into the PRRECV state and reschedule. If recv() sees other processes waiting to send in its msgqueue, it should dequeue the process, grab the message from that process's msgout field, and unblock that process before returning.

Function recvnow() returns the message sent to the current process. If there is no message already, recv() should not block, that is, it does not wait, and instead immediately returns a SYSERR.

Garbage In, Garbage Out

The C programming language generally does not include a garbage collector, and instead relies on programmers to be meticulous about free()ing any dynamic memory they may have malloc()ed.

While a full-blown garbage collector requires tracking all possible references to a dynamically-allocated memory location, (which is notoriously intractable in C,) we can nevertheless implement a simple per-process collector that tracks every call of malloc() made by each process, and then automatically calls free() on any remaining blocks when a process is kill()ed.

Add a new field declaration to the PCB struct, memblk *myblocks, which is initialized to NULL in create().

Add code to malloc.c to add each new block from getmem() to the current process's myblocks list. (Hint: You can make another call to getmem() to make space for this new information; you can repurpose the length payload field of a memblk struct to keep track of the new block.

Add code to free.c to deregister a chunk from the process's myblocks list.

Add code kill.c to call freemem() on any remaining dynamically-allocated blocks in a process's PCB.

Notes


[back]

[Revised 2020 Mar 24 15:11 DWB]