BACKGROUND. SysV Interprocess communication (IPC) is the standard (portable) way of communicating among related (parent and child) and unrelated processes. This lab introduces *two* of the three components of the SysV IPC suite--message queues and shared memory. The two processes that communicate will be a parent and its spawned child. To use SysV IPC, msg queues and shared memory add these headers:
#include <sys/ipc.h> #include <sys/msg.h> #include <sys/shm.h>The third service in the SysV IPC suite is semaphores. If multiple processes reference the same memory location the coder you must control access by synchronization. Synchronization is implemented with semaphores. Semaphores will be covered on in our course. This lab will use shared memory for synchronization.
Read these man pages before starting:
$ man shmget # shmget is get a shared memory segment $ man shmat # shmat is attach to a shared memory segment $ man shmctl # shmctl is shared memory control operations $ man ftok # ftok is generate a SysV IPC keyIn Lab-4 you will write a program on odin 3600/4/mylab4.c using SysV IPC shared memory and SysV IPC message queues. You will also include POSIX signal handling using signal sets in your program. Copy these files into your account:
to copy from your Odin account: cd cd 3600/4 cp /home/fac/gordon/public_html/3600/examples/4/* .Carefully read the documentation in each file. Execute and run each file. When you are comfortable with the code, proceed. You will need to manually remove your IPC objects if things go wrong.
$ ./cleanipc.sh {username} # this script will cleanup your IPC objects $ ipcs -c username # shared objects created by you should be goneUse the commands above to avoid showing up on the "wall of shame". :)
If things go well your objects should be removed within your mylab4.c program.
While testing ALWAYS REMOVE YOUR IPC OBJECTS before executing your
code again.
LAB INSTRUCTIONS.
Please do your work on Odin in folder 3600/4/
Name your program: 3600/4/mylab4.c
STEP 1. Generate an IPC key and open a log file.
To generate an IPC key, create a file named 'foo' in the directory in which you compile and execute your programs.
$ cd $ cd 3600/4 $ touch foo
You may also do vi foo and put stuff in the file.
For consistency throughout the rest of the course, we will use 'foo' to generate the IPC key.
Open a file for writing named log. Only the child will write to this file but you should open it before the fork.
STEP 2. Create a shared memory segment to hold at least one integer.
You may create a shared memory segment larger than one integer.
You may also create a shared memory segment to hold a struct, and store your value there.
That is your choice.
You will use the IPC key you just created. The source shared_mem.c communicates between a parent and a forked child using a shared memory segment large enough to hold an integer. Source shared_mem.c has all the code you need to implement shared memory - you just need to take what you need and leave what you don't behind. You can either copy shared_mem.c to mylab4.c and delete/modify the existing code or start mylab4.c from scratch. In either case, understand each and every line of code for shared memory that you copy. Do not use any code you do not understand! The system call to create the shared memory segment returns a shared memory id.
Create the segment. Attach to the shared memory segment. Initialize its value to 0. After a fork(2) the child inherits the attached shared memory segment so you will not need to attach again in the child.
STEP 3. Get a message queue & fork(2) a child
Use the same IPC key you have already created to get a IPC message queue. Create the structure needed to send and receive messages (the child and the parent will use the same message structure and type of the message). You will be sending a message from parent to child after the fork. Look in msg_send.c for the code needed to get a message queue using the call msqget(2).
Message queues are designed to allow communication between unrelated processes. The only thing the child and the parent need in order to use the same message queue is the same IPC key. The only way for this to happen is to generate the IPC key before the fork since after the fork the child inherits the value of the IPC key.
Call fork(2).
STEP 1. Wait for shared memory to change, then write integer value to log.
The parent will modify the shared memory segment to something other than zero but the child does not know when this might happen. The child must loop continuously, checking the value until it changes from zero. This behavior is called a busy-wait. Not always the best way to code, but good for this lab exercise. After the value changes, the child writes the shared memory value to its log file.
busy-wait:
Stay in an infinite loop, constantly checking for something to happen.
When it does happen, immediately break out of the loop.
A short usleep() call should be placed inside the busy-wait, for this lab.
For example:
usleep(1000); /* sleep for 1-thousandth of a second */
With so many student programs running at once on Odin, the usleep can help the OS run a little more efficiently.
STEP 2. Write mesg from message queue to log.
The child blocks on the queue until the parent sends a message. The code to do this is in msg_rcv.c. The child grabs the message and writes its contents to log.
STEP 3. Exits
The child closes log, detaches from shared memory and exits with status code 0. Note that the child does not clean up IPC objects. It is safer for the parent to do this after the wait.
STEP 1. Write user input to shared memory
The parent prompts the user to enter a 2-digit integer using the write() call; e.g.,
Enter a 2-digit number:The prompt is a write call:
write(1, prompt, strlen(prompt));The parent reads the integer using read():
read(0, buf, 4); // 0=stdin; 4 is how many characters you want the user to typeThe read of user input can be tricky, so test your code. These calls are in readwrite.c in the examples from last week. You should always clear out the buffer before you do a read:
memset(buf, 0, BUFSIZE);
Since the integer will come in as a string it must be converted to an integer using atoi. The parent then writes the integer to its shared memory segment.
STEP 2. Send user input as a message to the queue
The parent prompts the user to enter a word using write(). The parent reads the word using read(2). The parent constructs a message that holds this word and sends the message to the queue. The code to do this is in msg_send.c.
STEP 3. After child terminates remove IPC objects
The parent calls wait(2), grabs the child's exit code and writes the code to stdout. After that the parent cleans up all IPC objects.
To save time when testing your code create an input file that holds user input:
Name your file: myinput The contents of your myinput file could look like this for example: 83 System-VSample runs...Note for the myinput file: When reading your 2-digit number from the command-line, the read statement will essentially discard blank characters to the right of the digits. When reading from your input file, the read statement has more data to work with, such as the characters on the second line of your file. Your first read statement might grab some of the characters from your second line. Adjust the "count" argument of the read function calls to control this.
$ ./lab4 Enter a two-digit number: 75 Enter a word: Linuxize Child exited with status code 0 $ cat log 75 Linuxize
$ ./lab4 < myinput Enter a two-digit number: Enter a word: Child exited with status code 0 $ cat log 83 System-V
$ strace -f -e trace=ipc ./lab4 < myinput shmget(0x1102af98, 4, IPC_CREAT|0666) = 911605760 shmat(911605760, 0, 0) = ? msgget(0x1102af98, IPC_CREAT|0666) = 297172992 Process 9356 attached [pid 9355] msgsnd(297172992, {1, " \nSystem-V\n\0\0\0\0\0\0\0\0\0"...}, 112, 0) = 0 [pid 9356] msgrcv(297172992, Process 9355 suspended {1, " \nSystem-V\n\0\0\0\0\0\0\0\0\0"...}, 112, 0, 0) = 112 [pid 9356] shmdt(0x7fac33f01000) = 0 Process 9355 resumed Process 9356 detached --- SIGCHLD (Child exited) @ 0 (0) --- shmdt(0x7fac33f01000) = 0 msgctl(297172992, IPC_RMID, 0) = 0 shmctl(911605760, IPC_RMID, 0) = 0 $ cat log 83 System-V $ ipcs -c | grep {username} # should display nothing
These files will be collected from your Odin 3600/4 folder
at the end of lab, 9:50am.
3600/4/mylab4.c 3600/4/Makefile 3600/4/foo 3600/4/myinputPlease don't change permissions or create new directories in your 3600/