Signals: Based On Chapter 12.5 of Text What If Something Unexpected or Unpredictable Happens?
This document discusses signals in Linux. It covers what signals are, common signal types, how processes can send and handle signals, and examples of using signals. Some key points:
- Signals interrupt normal program flow and allow processes to respond to events like errors or user input. The kernel sends signals to notify processes.
- Common signals include SIGINT (Control-C), SIGALRM (for alarm clocks), and SIGCHLD (when a child process exits).
- Processes can install custom signal handlers using signal() or ignore signals. The pause() system call waits for a signal.
- The kill() system call sends signals between processes. A child process notifies its parent of termination using
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0 ratings0% found this document useful (0 votes)
46 views17 pages
Signals: Based On Chapter 12.5 of Text What If Something Unexpected or Unpredictable Happens?
This document discusses signals in Linux. It covers what signals are, common signal types, how processes can send and handle signals, and examples of using signals. Some key points:
- Signals interrupt normal program flow and allow processes to respond to events like errors or user input. The kernel sends signals to notify processes.
- Common signals include SIGINT (Control-C), SIGALRM (for alarm clocks), and SIGCHLD (when a child process exits).
- Processes can install custom signal handlers using signal() or ignore signals. The pause() system call waits for a signal.
- The kill() system call sends signals between processes. A child process notifies its parent of termination using
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17
Signals
Based on chapter 12.5 of text
What if something unexpected or unpredictable happens? a floating-point error a power failure an alarm clock "ring" (discussed soon) the death of a child process a termination request from a user (i.e., a Control-C) a suspend request from a user (i.e., a Control-Z) 1 Signals These kind of events are often called interrupts i.e., they interrupt the normal flow of the program to service an interrupt handler When Linux recognizes such event it sends corresponding signal, e.g., floating point error: kernel sends offending process signal number 8 2 Signals Who can send signals? the kernel any process can send any other process a signal as long as it has permission receiving process suspends its current flow of control executes signal handler resumes original flow when signal handler finishes 3 Signals Why do we care about signals? we can use them to protect our program from Control-C arrange for alarm clock to terminate a long running program let our calendar pop up a window etc... 4 Signal Types Two signal types standard signal (traditional unix signals) delivered to a process by setting a bit in a bitmap one for each signal thus there cannot be multiple instances of the same signal; bit can be one (signal) or zero (no-signal) real-time signals (or queued signals) defined by POSIX 1003.1b where successive instances of the same signal are significant and need to be properly delivered. In order to use queued signals, you must use the sigaction () system call, rather than signal () 5 Defined Signals Where are signals defined? Signals are defined in /usr/include/signal.h other platform-specific header files e.g., /usr/include/asm/signal.h Programmer may chose that particular signal triggers a user-defined signal handler triggers the default kernel-supplied handler signal is ignored 6 Defined Signals Default handler usually does the following terminates the process and generates a dump of memory in a core file (core) terminates the process without generating a core image file (quit) ignores and discards the signal (ignore) suspends the process (stop) resumes the process 7 8 Terminal Signals Easiest way to send signal to foreground process press Control-C or Control-Z when terminal driver recognizes a Control-C it sends SIGINT signal to all of the processes in the current foreground job Control-Z causes SIGSTP to be sent by default SIGINT terminates a process SIGTSTP suspends a process 9 Requesting Alarm Signal System Call: unsigned int alarm (unsigned int count) alarm () instructs the kernel to send the SIGALRM signal to the calling process after count seconds. If an alarm had already been scheduled, it is overwritten. If count is 0, any pending alarm requests are cancelled. alarm () returns the number of seconds that remain until the alarm signal is sent. The default handler for this signal displays the message "Alarm clock" and terminates the process 10 Alarm Signal example $ cat alarm.c ...list the program. #include <stdio.h> main () { alarm (3); /* Schedule an alarm signal in three seconds */ printf ("Looping forever...\n"); while (1); printf ("This line should never be executed\n"); } $ ./alarm ...run the program. Looping forever... Alarm clock ...occurs three seconds later. $ _ 11 Handling Signals How do you override the default action in the previous example? the signal() system call may be used System Call: void (*signal (int sigCode, void (*func) (int))) (int) signal () allows a process to specify the action that it will take when a particular signal is received. The parameter sigCode specifies the number of the signal that is to be reprogrammed 12 Handling Signals func may be one of several values: SIG_IGN indicates that the specified signal should be ignored and discarded. SIG_DFL indicates that the kernel's default handler should be used. an address of a user-defined function, which indicates that the function should be executed when the specified signal arrives. 13 Handling Signals valid signal numbers are from "/usr/include/signal.h" (and the other header files that includes, the actual signal definitions are in "/usr/include/asm/signal.h" on his Linux machine). signals SIGKILL and SIGSTP may not be reprogrammed. a child process inherits signal settings from its parent during fork (). When process performs exec (), previously ignored signals remain ignored but installed handlers are set back to the default handler. with the exception of SIGCHLD, signals are not stacked, e.g., if a process is sleeping and three identical signals are sent to it, only one of the signals is actually processed. signal () returns the previous func value associated with sigCode if successful; otherwise it returns -1. 14 Handling Signals What is the problem with the example below? $ cat alarm.c ...list the program. #include <stdio.h> main () { alarm (3); /* Schedule an alarm signal in three seconds */ printf ("Looping forever...\n"); while (1); printf ("This line should never be executed\n"); } 15 Handling Signals System Call: int pause (void) pause () suspends the calling process and returns when the calling process receives a signal. It is most often used to wait efficiently for an alarm signal. pause () doesn't return anything useful. to enhance efficiency the previous program is modified to wait for a signal. also a custom signal handler is installed 16 Modified example $ cat handler.c ...list the program. #include <stdio.h> #include <signal.h> int alarmFlag = 0; /* Global alarm flag */ void alarmHandler (); /* Forward declaration of alarm handler */ /***************************************************************/ main () { signal (SIGALRM, alarmHandler); /* Install signal handler */ alarm (3); /* Schedule an alarm signal in three seconds */ printf ("Looping...\n"); while (!alarmFlag) /* Loop until flag set */ { pause (); /* Wait for a signal */ } printf ("Loop ends due to alarm signal\n"); } /***************************************************************/ void alarmHandler () { printf ("An alarm clock signal was received\n"); alarmFlag = 1; } $ ./handler ...run the program. Looping... An alarm clock signal was received ...occurs three seconds later. Loop ends due to alarm signal $ _ 17 Handling Signals Sometimes we want to protect critical pieces of code against Control-C attacks and other such signals save previous value of the handler so that it can be restored after the critical code has executed in the following example SIGINT is disabled 18 19 $ cat critical.c ...list the program. #include <stdio.h> #include <signal.h> main () { void (*oldHandler) (); /* To hold old handler value */ printf ("I can be Control-C'ed\n"); sleep (3); oldHandler = signal (SIGINT, SIG_IGN); /* Ignore Control-C */ printf ("I'm protected from Control-C now\n"); sleep (3); signal (SIGINT, oldHandler); /* Restore old handler */ printf ("I can be Control-C'ed again\n"); sleep (3); printf ("Bye!\n"); } $ ./critical ...run the program. I can be Control-C'ed ^C ...Control-C works here. $ ./critical ...run the program again. I can be Control-C'ed I'm protected from Control-C now ^C ...Control-C is ignored. I can be Control-C'ed again Bye! $ _ Handling Signals Process may send signal to other process by using kill() often misunderstood as killing another process, but not all kill signals do that System Call: int kill (pid_t pid, int sigCode) sends the signal with value sigCode to the process with PID pid. kill () succeeds and the signal is sent as long as at least one of the following conditions is satisfied: The sending process and the receiving process have the same owner. The sending process is owned by a super-user. 20 Handling Signals There are a few variations on the way that kill () works: If pid is 0, the signal is sent to all of the processes in the sender's process group. If pid is -1 and the sender is owned by a super-user, the signal is sent to all processes, including the sender. If pid is -1 and the sender is not a super-user, the signal is sent to all of the processes owned by the same owner as the sender, excluding the sending process. If the pid is negative and not -1, the signal is sent to all of the processes in the process group. If kill () manages to send at least one signal successfully, it returns 0; otherwise, it returns -1. 21 Handling Signals When child terminates child process sends SIGCHLD to parent parent often installs a handler to deal with this signal parent typically executes a wait() to accept the childs termination code (such child is not zombie anymore) Alternatively, the parent can choose to ignore SIGCHLD signals, in which case the child de-zombifies automatically. 22 example The example below does the following The parent process installs a SIGCHLD handler that is executed when its child process terminates. The parent process forks a child process to execute the command. The parent process sleeps for the specified number of seconds. When it wakes up, it sends its child process a SIGINT signal to kill it. If the child terminates before its parent finishes sleeping, the parent's SIGCHLD handler is executed, causing the parent to terminate immediately. 23 $ cat limit.c ...list the program. #include <stdio.h> #include <signal.h> int delay; void childHandler (); /********************************************************************/ main (argc, argv) int argc; char* argv[]; { int pid; signal (SIGCHLD, childHandler); /* Install death-of-child handler */ pid = fork (); /* Duplicate */ if (pid == 0) /* Child */ { execvp (argv[2], &argv[2]); /* Execute command */ perror ("limit"); /* Should never execute */ } else /* Parent */ { sscanf (argv[1], "%d", &delay); /* Read delay from command line */ sleep (delay); /* Sleep for the specified number of seconds */ printf ("Child %d exceeded limit and is being killed\n", pid); kill (pid, SIGINT); /* Kill the child */ } } /********************************************************************/ void childHandler () /* Executed if the child dies before the parent */ { int childPid, childStatus; childPid = wait (&childStatus); /* Accept child's termination code */ printf ("Child %d terminated within %d seconds\n", childPid, delay); exit (/* EXITSUCCESS */ 0); } 24 Handling Signals Run example $ ./limit 5 ls ...run the program; command finishes OK. a.out alarm critical handler limit alarm.c critical.c handler.c limit.c Child 4030 terminated within 5 seconds $ ./limit 4 sleep 100 ...run it again; command takes too long. Child 4032 exceeded limit and is being killed $ _ 25 Handling Signals Suspending and resuming processes The SIGSTOP and SIGCONT signals suspend and resume a process, respectively. They are used by the Linux shells to support job control to implement built-in commands like stop, fg, and bg. following example: create two children suspend and resume one child terminate both children 26 $ cat pulse.c ...list the program. #include <signal.h> #include <stdio.h> main () { int pid1; int pid2; pid1 = fork(); if (pid1 == 0) /* First child */ { while (1) /* Infinite loop */ { printf ("pid1 is alive\n"); sleep (1); } } pid2 = fork (); /* Second child */ if (pid2 == 0) { while (1) /* Infinite loop */ { printf ("pid2 is alive\n"); sleep (1); } } sleep (3); kill (pid1, SIGSTOP); /* Suspend first child */ sleep (3); kill (pid1, SIGCONT); /* Resume first child */ sleep (3); kill (pid1, SIGINT); /* Kill first child */ kill (pid2, SIGINT); /* Kill second child */ } 27 Process Groups What happens when you Control-C a program that created several children? typically the program and its children terminate why the children? 28 Process Groups In addition to having unique ID, process also belongs to a process group Several processes can be members of the same process group. When a process forks, the child inherits its process group from its parent. A process may change its process group to a new value by using setpgid (). When a process execs, its process group remains the same. 29 Process control terminal Every process can have an associated control terminal. This is typically the terminal where the process was started. When a process forks, the child inherits its control terminal from its parent. When a process execs, its control terminal stays the same. Every terminal can be associated with a single control process. When a metacharacter such as a Control-C is detected, the terminal sends the appropriate signal to all of the processes in the process group of its control process. 30 How the shell uses this When an interactive shell begins, it is the control process of a terminal and has that terminal as its control terminal. When a shell executes a foreground process, the child shell places itself in a different process group before exec'ing the command, and takes control of the terminal. Any signals generated from the terminal thus go to the foreground command rather than the original parent shell. When the foreground command terminates, the original parent shell takes back control of the terminal. When a shell executes a background process, the child shell places itself in a different process group before exec'ing, but does not take control of the terminal. Any signals generated from the terminal continue to go to the shell. If the background process tries to read from its control terminal, it is suspended by a SIGTTIN signal. 31 Fig 12-49 Control terminals and process groups 32 Process Groups System Call: pid_t setpgid (pid_t pid, pid_t pgrpId) setpgid () sets the process group ID of the process with PID pid to pgrpId. System Call: pid_t getpgid (pid_t pid) getpgid () returns the process group ID of the process with PID pid. 33