Out: March 20, 2019 Due: Apr 3, 2019 (Start of lecture)

CENG 251 Lab 5: Signals, Forking and Exec

Part I: Signals (8 marks)

Write handlers for each of the following. Since your program is reacting to different signals you can combine these in a single program. Provide a listing and proof that each of these works.

You should follow the procedure used in class: Run the program in one terminal window while sending it signals in another.

1. Write a signal handler for SIGUSR1 that uses popen to run a shell command that determines the number of processes on the system. Print that value out to the terminal.

In the signal hander open a log file in append mode, ie: myLog.log . Write out the current time and the # of current processes to the file and close the file immediately after the write.

Verify that when you send multiple SIGUSR1s to your program you get multiple entries in your log file. (2 marks)

2. Open a couple files at the beginning of the program.

When you send the program SIGINT (c) have it display the real names of all the open files in the directory /proc/pid/fd using readdir. Note: The entries in /proc/pid/fd are symbolic links: 1, 2 3 …. You have to use readlink to follow the symbolic link to the real file name.

The algorithm is straightforward. Use getpid() to return the id of the current process, use sprintf or asprintf to construct the directory path as a string, chdir to that directory and then write a readdir loop to display not the names of the files - instead use readlink to determine what the files link to. (3 marks)

3. A common use of SIGHUP is to reinitialize a program. For example, to modify Apache’s parameters while it is still running, one would modify the file apache.conf and then send it a SIGHUP interrupt.

Add a SIGHUP interrupt handler to the previous question.

Create a file files.list consisting of several file names along with a file mode for opening the file. When your program is sent a SIGHUP interupt, read in the list of files and modes and open up each file in the appropriate mode. Be careful not destroy any of your source code files by opening them in write mode.

Verify that the files have been opened by checking the directory /proc/processID/fd which lists all the open files. What happens if you send a 2nd SIGHUP message? (3 marks)

Part II: Fork (12 marks)

1. In class we demonstrated 3 different styles of forking a process were used. Use a different style for each experiment a-c.

a. Creating an : (2 marks)

A who’s parent has died is known as an orphan process. Write a short program that creates a single child. Have the main process die right away but leave the child still executing in an infinite loop.

When the main program has completed:

Run the shell command: ps –O ppid What is the process id of this child’s parent? What is the State of the child? the child when you are done.

b. Creating a : (2 marks)

When a child process completes a record is kept in the A zombie process is a child process that has died without it’s code being picked up by the parent. Write a short program that creates a single child. Have the child process die right away but leave the parent running either in a loop or an extended sleep. Do not use a statement to wait for the child.

Run the command: ps –O ppid (type in the letters ppid literally, not a parent process id) and examine the column headings:

What is the process id of the child’s parent? What is the State of the child.

c. Reaping a process: (2 marks)

Write a short program that creates a single child. i. The child should output its process id and exit with a non-zero exit code. ie: exit(17) ii. The parent should wait for the child to complete and report the pid of the child and the reason (status code) that it exited by recovering it from a wait function call. Use the macro WEXITSTATUS to obtain the status. The wait function itself returns the pid of the child.

2. Managing Multiple Child Processes (6 marks)

a. Write a main process that creates a 5 children one after another passing each a random number between 1 million and 4 million. As you create the children store their process ids in an array. Do this carefully – make sure the children go off to a function that never returns or you’ll wind up with a situation like forkDemo5. All children will use the same function. (2 marks)

b. Each child should do the following: (2 marks) i. Announce its process id and parent process id and the random number passed as an argument which will be used as a delay time. ii. Set up an interrupt handler for one signal that is ignored. This signal handler should print out an identifying message. (However the proof that this works is that the message will never be printed out.) iii. Set up a 2nd interrupt handler that is not ignored and prints a message which includes the pid. iv. Use usleep to sleep for the random time in usecs. v. Call exit to end the child process.

c. After spawning the 5 chidren the parent process should: i. Use kill to send the non-ignored signal to each process. Verify that the message is printed out. Note the value(s) returned by kill. ii. Use kill to send the ignored signal to each process. Verify that the message is not printed out. Note the value(s) returned by kill iii. Wait for each child to finish and report the pid of each child as it is reaped. Note if the order is different than the order of creation. Use a counter so that you stop waiting after 5 children. iv. Based on the results of I and ii, use kill to verify that none of the child processes are still alive.

Part III: Child Processes and exec (10 marks)

Just as fork returns twice, members of the exec family never return. The two complement each other

The purpose of this exercise is to show that a child process inherits signal handlers, environment variables and open files from the parent. You may borrow code from previous steps and previous assignments.

1) In the initialization section of your program create 2-3 environment variables, open the file myDB (or the database you created in Lab 5) to obtain a file descriptor and use lseek to position the file at some random record n and then define 2 different signal handlers. (2 marks)

2) Fork a child process. Immediately call a subroutine (this will make your code more readable in terms of separating the child code from the parent code) passing the file pointer or file descriptor to it as an argument. Do do the following: (4 marks)

a. Print out the process id of the child.

b. Print out the environment variables to confirm that the child has inherited them.

c. Print out the next record in your database – this confirms that the open file and the file pointer have been inherited by the child.

d. Send the child process the signals you set up in the parent. Did the child receive the signals?

e. In the parent wait one second then print out the next record in your database. If location of the pointer is not the same but a copy of the file pointer the parent should print the same record as the child. Note if the records are the same or different.

f. Make a statement as to which of the above – environment variables, file location point and/or signals was inherited by the child. Most of the marks here depend on your stated conclusions.

3) Repeat the previous exercise but this time rewrite the subroutine as a separate program. Use execvp to launch this Verifying that the child has inherited the environment variables and the signal handlers is rather easy. Test these first. (2 marks). Passing the numeric file descriptor is a more difficult. Most techniques involve converting the number to a string and then converting it back to a number in the child. We will discuss this next week’s class, but see if you can think up a method of your own first. (2 marks)