Signals are a simple yet powerful way for Linux processes to communicate in pre-defined ways. They are ideally suited for inter-process event handling during system operation. Signals can be sent to any process in the system, and can be recieved by defining special functions called signal handlers, which are executed upon receipt of the signal.
In this studio, you will:
Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete.
As you work through these exercises, please record your answers, and when finished email your results to email@example.com with the phrase Linux Signals in the subject line.
Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.
dense_mmprogram that we used earlier. Build this program and run it. While this program is executing, send it the keyboard interrupt signal (
SIGINT) by highlighting its terminal and pressing CTRL+C (hold down the CTRL button and press C). As the answer to this exercise, copy and paste the result from successfully interrupting your program.
man 7 signal. Some commonly used signals are
SIGQUIT(quit from keyboard), and
SIGTERM(terminate process). Every signal in the system is associated with a default action (which typically terminates the recieving process), but this can be overridden simply by defining your own signal handling function, which is what we will now do.
The modern, portable way to define a signal handler is to use the function
sigaction() which is documented at
man sigaction. Use
this function to define a new handler for
SIGINT. You will need to:
void function_name (int arg)
struct sigactionin your
sa_handlerfield of your
struct sigactionto your signal handling function
sa_flagsfield of your
SIGINTas the signum argument and a pointer to your
struct sigactionfor the act argument.
Declare a global counter and increment it when the handler function is
called. At the end of your
main() function print the value of
this counter. Copy and paste a sample program output as the answer to this
NOTE: Overriding the
SIGINT handler may make it
difficult to terminate your program. You can alternately use CTRL+\ to send
SIGQUIT signal or the
kill program to terminate
Even library functions are not immune to problems with asynchronicity.
Download the program
and run it. This is a very simple program that defines a signal handler for
SIGINT, and then prints the numbers from 1 to 5000 in order.
Try running this program and interrupting it with
the program output where it was possibly interrupted by a signal handler.
What happens? Copy and paste evidence.
printf()are not guaranteed to execute correctly when called from within a handler, since they may be called concurrently from different contexts. Fortunately, there is a list of functions that is guaranteed to be safe when called from a handler. These functions are given in the signal documentation at
man 7 signalunder "Async-signal-safe functions".
Going back to your original program, use the
man 2 write to produce output from within a signal
handler. In particular, you must:
char* message = "error message\n")
write()function with argument fd equal to zero to write to standard output (e.g.
write(0, message, num_chars);)