Lab 3 - Signals and select()

Due: Friday April 17, 2009 at 1:00pm

In this lab, we will explore two concepts central to many network programs: signal masks and select(). These concepts form the basis of allowing a program to use full-duplex communication.

Part 1: Signals

Signals are notifications sent by the operating system or the user to processes. The signals can affect the behavior of the process. For example, if you are running a program in the foreground of your shell and you type CTRL-C, this sends the SIGINT signal to the process. By default, the process will terminate when it receives this signal. The coder can also set up signal handlers to change the default behavior of the process when it receives certain specific signals.

Read the manual page on signals using the following command:

man 7 signal
To investigate signal processing and signal handlers, change to your directory containing the lab code from Lab 2 (or copy the lab code to a new directory) and type:
make process
This will compile the file process.c into a program called process. To run the program, use the command:
./process 01000
This will output information about the process's current signal mask. The signal mask defines the signals for which the program has signal handlers. Look at the code for process.c and see how it is setting up these signal handlers in main() using sigaddset.

Part 2: select()

The purpose of select() is to give the program a way of waiting for I/O events or errors from specified file descriptors or sockets. For example, if the user types something on the keyboard, this will be an event for the stdin file descriptor. If data is waiting on the network socket, i.e. something can be read with recv(), then this would also be an I/O event.

The files terminal.c and specio.h in the lab code directory use the select() function. Compile the code using the command:

make terminal
Run the program using the command:
./terminal
This program steps through three basic terminal modes: raw, cbreak and cooked. Raw mode inputs data character by character with no interpretation (e.g. no signal handling). Cbreak mode responds to SIGINT (CTRL-C) and also uses character by character mode. Cooked mode, also called line mode, gets a full line of input from the user and does interpretation.

Run terminal giving it a variety of input such as printable characters, tabs, control sequences (CTRL-G for bell, CTRL-C for SIGINT, CTRL-Z for SIGSTOP, etc) and escape.

Look at the code for terminal.c and go to the label selectloop in main(). This sets up select() to watch stdin (the keyboard) for reads (what you've typed) and exceptions. One could expand select() to watch for other I/O events by using FD_SET on other file descriptors.

Part 3: Lab Write-Up

Answer the following questions and email your responses to me in plain text, Open Office or PDF format.
  1. What is the purpose of each of the signals listed on the line "Current Signal Mask" in the output of process according to the man page?
  2. What is the full list of signals marked in process.c as important signals? Just give the signals, not their purpose
  3. Pick three signals from Question 2 that you did not describe in Question 1 and describe their purpose.
  4. Look at the man page for sigemptyset and describe its purpose in process.c.
  5. Look at the man page for sigprocmask and describe how it is used in process.c.
  6. Describe what happened when you ran terminal with a variety of input.
  7. Look at the source code for terminal.c. How is the SIGINT (CTRL-C) signal handler set up?
  8. One of the issues with Lab 2 is there was no way to check both the socket and the keyboard for data at the same time, so we could only recode the programs to use half-duplex communication. How would you use concepts explored in this lab to allow full duplex communication between vcrec and vcsend? Describe the general code changes you would need to make, but do not actually code the changes.