source robbins and robbins unix systems programming prentice hall 2003 l.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Chapter 8 Signals PowerPoint Presentation
Download Presentation
Chapter 8 Signals

Loading in 2 Seconds...

play fullscreen
1 / 54

Chapter 8 Signals - PowerPoint PPT Presentation


  • 250 Views
  • Uploaded on

Source: Robbins and Robbins, UNIX Systems Programming, Prentice Hall, 2003. Chapter 8 Signals. 8.1 Basic Signal Concepts. Basic Signal Concepts. A signal is a software notification to a process of an event A signal is generated when the event that causes the signal occurs

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Chapter 8 Signals' - wyome


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
basic signal concepts
Basic Signal Concepts
  • A signal is a software notification to a process of an event
  • A signal is generated when the event that causes the signal occurs
  • A signal is delivered when the process takes action based on the signal
  • The lifetime of a signal is the interval between its generation and its delivery
  • A signal that has been generated but not yet delivered is said to be pending
    • There may be considerable time between signal generation and signal delivery
    • The process must be running on a computer at the time of signal delivery
  • A program installs a signal handler by calling the sigaction() function with the name of a user-written function
  • A process handles a signal if it executes a signal handler when the signal is delivered
  • If the process is set to ignore a signal, that signal is thrown away when delivered and has no effect on the process
basic signal concepts continued
Basic Signal Concepts(continued)‏
  • The action taken when a signal is generated depends on the current signal handler for that signal and on the process signal mask
  • The signal mask contains a list of currently blocked signals
  • Blocked signals are not thrown away as ignored signals are
  • If a signal is blocked, it is delivered when the process unblocks that signal
  • A program blocks a signal by changing its process signal mask using sigprocmask()‏
  • A program ignores a signal by setting the signal handler to SIG_IGN using sigaction()
signal names
Signal Names
  • Every signal has a symbolic name starting with SIG
  • The signal names are defined in the signal.h file, which should be included by any C program that uses signals
  • The table on the following slide lists some of the POSIX signals and their default actions
  • Two signals, SIGUSR1 and SIGUSR2, are available for users and do not have a preassigned use
  • Some signals such as SIGFPE and SIGSEGV are generated when certain errors occur; other signals are generated by specific function calls such as SIGALRM by the alarm() function
certain posix signals

SIGNAL

NBR

DESCRIPTION

DEFAULT ACTION

SIGABRT

6

Process abort (sent by assert)‏

Implementation dependent

SIGALRM

14

alarm clock

Abnormal termination

SIGCONT

25

Execution continued if stopped

Continue

SIGFPE

8

Arithmetic error (i.e., divide by zero)‏

Implementation dependent

SIGINT

2

Interactive attention signal (Ctrl-C)‏

Abnormal termination

SIGKILL

9

Termination (cannot be caught or ignored)‏

Abnormal termination

SIGQUIT

3

Interactive termination; core dump

Implementation dependent

SIGSEGV

11

Segmentation fault

Abnormal termination

SIGSTOP

23

Execution stop (cannot be caught or ignored)‏

Stop

SIGTERM

15

Termination

Abnormal termination

SIGUSR1

16

User-defined signal 1

Abnormal termination

SIGUSR2

17

User-defined signal 2

Abnormal termination

Certain POSIX Signals
kill command
kill Command
  • A user can send signals to a process from a command shell using the kill command
  • The name of the command is a slight misnomer in that it can be used to send any of the POSIX signals, not just the ones that cause abnormal process termination
  • The kill command sends a signal to the process or processes that are specified by each pid operandkill [-signal_name] pid ...kill [-signal_number] pid ...
  • The first form of the kill command take a signal name as defined in signal.h without the SIG prefix (i.e., INT instead of SIGINT)‏
  • The second form takes a signal number
  • If no signal name or number is specified, SIGTERM is sent by default
  • Example usagekill 3425kill –9 896kill –KILL 3425kill –INT 9328kill –USR1 567
kill function
kill() Function
  • In a program, a user can send a signal to a process using the kill() function#include <signal.h>int kill(pid_t pid, int signalNbr);
  • The function takes a process ID and a signal number (i.e., a symbolic name) as parameters
  • If successful, the function returns zero; otherwise, it returns –1 and sets errno
  • A user may only send a signal to a process that he or she owns
    • For most signals, the kill() function determines permissions by comparing the user IDs of caller process and target process
  • Example use of the kill() functionint status;pid_t childPid;. . .status = kill(childPid, SIGUSR1);if (status == -1) perror("Failed to send the SIGUSR1 signal to child");
raise function
raise() Function
  • A process can send a signal to itself with the raise() function#include <signal.h>int raise(int sig);
  • The function takes just one parameter, a signal number
  • If successful, the function returns zero; otherwise, it returns a nonzero error value and sets errno
    • The function sets errno to EINVAL if the signal number is invalid
  • Example use of raise() functionint status;status = raise(SIGUSR1);if (status != 0) perror("Failed to raise SIGUSR1");
alarm function
alarm() Function
  • The alarm() function causes a SIGALRM signal to be sent to the calling process after a specified number of real seconds has elapsed#include <unistd.h>unsigned int alarm(unsigned int seconds);
  • The function returns the number of seconds remaining on the alarm before the call resets the value, or zero if no previous alarm was set
  • The function never reports an error
  • Requests to alarm() are not stacked, so a call to alarm() before the previous timer expires causes the alarm to be reset to the new value
  • If alarm() is called with a zero value argument, it cancels a previous alarm request
  • The default action for SIGALRM is to terminate the process
  • The following program runs for five seconds of wall-clock time and then terminates#include <unistd.h>int main(void){alarm(5);for ( ; ; );return 0;} // End main
assert function
assert() Function
  • The assert() function is used to put diagnostic checks into a program by means of an assertion expression that evaluates to true or false (i.e., a nonzero or a zero result)#include <assert.h>void assert(int expression);
  • When the value of the expression passed to the assert() function is false, the function first prints a diagnostic message to stderr containing the assertion expression, the file name and the line number in the file where the assertion is located. It than calls the abort() function. An example output is shown belowassertion “nbrOfValues <= 7" failed: file “sample-program.c", line 52 10 [sig] a 3640 open_stackdumpfile: Dumping stack trace to a.exe.stackdump
  • The abort() function sends the SIGABRT signal to the process (using raise() ) and never returns. At that point, the process either executes the default signal handler for SIGABRT or calls the signal handler registered by the process. In either case, the process terminates
  • The default action for SIGABRT is to request a stack trace dump and then terminate
  • If NDEBUG is defined in a program before the #include for assert.h, then any assert statements in the program are ignored by the compiler
use of assert
Use of assert()

#include <stdio.h>

#include <limits.h>

// #define NDEBUG

#include <assert.h>

#define MIN_SCORES 2

#define MAX_SCORES 5

// ******************************************

int main(void)‏

{

float average;

int i;

int score;

float sum = 0;

int nbrOfScores;

int scoreTable[MAX_SCORES];

printf("Enter the number of scores (%d - %d: “, MIN_SCORES,

MAX_SCORES);

scanf("%d", &nbrOfScores);

printf(“\n");

assert( (nbrOfScores >= MIN_SCORES) && (nbrOfScores <= MAX_SCORES) );

(More on next slide)‏

use of assert continued
Use of assert()(continued)

for (i = 0; i < nbrOfScores; i++)‏

{

printf("Enter score #%d (x >= 0): ", i + 1);

scanf("%d", &score);

assert( (score >= 0) && (score < INT_MAX) );

assert( (i >= 0) && ( i < nbrOfScores) );

scoreTable[i] = score;

sum = sum + score;

} // End for

printf("\nList of Scores: ");

for (i = 0; i < nbrOfScores; i++)‏

printf(" %d ", scoreTable[i]);

assert(sum >= 0);

average = sum / nbrOfScores;

assert(average >= 0);

printf("\n\nAverage score: %.2f\n", average);

return 0;

} // End main

sample outputs with assert
Sample Outputs ( with assert )‏

uxb3% a.out

Enter the number of scores (2 - 5): 3

Enter score #1 (x >= 0): 89

Enter score #2 (x >= 0): 72

Enter score #3 (x >= 0): 84

List of Scores: 89 72 84

Average score: 81.67

uxb3%

uxb3% a.out

Enter the number of scores (2 - 5): 1

assert-demo.c:25: failed assertion `(nbrOfScores >= MIN_SCORES) && (nbrOfScores <= MAX_SCORES)'

Abort

uxb3%

uxb3% a.out

Enter the number of scores (2 - 5): 4

Enter score #1 (x >= 0): -1

assert-demo.c:32: failed assertion `(score >= 0) && (score < INT_MAX)'

Abort

uxb3%

sample output with no assert
Sample Output ( with no assert )‏

uxb2% a.out

Enter the number of scores (2 - 5): 10

Enter score #1 (x >= 0): -5

Enter score #2 (x >= 0): -10

Enter score #3 (x >= 0): -15

Enter score #4 (x >= 0): -20

Enter score #5 (x >= 0): -25

Enter score #6 (x >= 0): 5

Enter score #7 (x >= 0): 10

Enter score #8 (x >= 0): 15

Enter score #9 (x >= 0): 20

Enter score #10 (x >= 0): 25

Enter score #11 (x >= 0): 34

List of Scores: -5 -10 -15 -20 -25 5 10 15 1117650944 34 10 0 0 0 -4195632

Average score: 5.27

uxb2%

Notice the amount of incorrect input and output that is not flagged nor pointed out as wrong

the signal set
The Signal Set
  • A process can temporarily prevent a signal from being delivered by blocking it
  • Blocked signals do not affect the behavior of the process until they are delivered
  • The process signal mask identifies the set of signals that are currently blocked
  • A program specifies operations (such as blocking or unblocking) on groups of signals by using signal sets of type sigset_t
  • Blocking a signal is different from ignoring a signal
  • When a process blocks a signal, the operating system does not deliver the signal until the process unblocks the signal
    • A process blocks a signal by modifying its signal mask with sigprocmask()‏
  • When a process ignores a signal, the signal is delivered and the process handles it by throwing it away
    • A process sets a signal to be ignored by calling sigaction() with a handler of SIG_IGN (described later in these slides)‏
signal set functions
Signal Set Functions
  • Signal sets are manipulated by the five functions listed below#include <signal.h>int sigaddset(sigset_t *set, int signalNbr);int sigdelset(sigset_t *set, int signalNbr);int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);int sigismember(const sigset_t *set, int signalNbr);
  • The first parameter for each function is a pointer to a variable of type sigset_t
  • The sigaddset() function adds signalNbr to the signal set
  • The sigdelset() function removes signalNbr from the signal set
  • The sigemptyset() function initializes a sigset_t variable to contain no signals
  • The sigfillset() function initializes a sigset_t variable to contain all signals
    • A program initializes a signal set by calling either sigemptyset() or sigfillset() before using it
  • Each of these functions return zero if the operation is successful; otherwise, the function returns –1 and sets errno
  • The sigismember() function reports whether signalNbr is in a sigset_t variable
    • It returns 1 if sigNbr is in the signal set and zero if it is not
example use of signal set functions
Example use of Signal Set Functions

#include <stdio.h>

#include <signal.h>

// *******************************

int main(void)‏

{

int status;

sigset_t mySet;

status = sigemptyset(&mySet);

if (status == -1)‏

perror("Failed to empty signal set");

status = sigaddset(&mySet, SIGINT);

if (status == -1)‏

perror("Failed to add SIGINT signal to signal set");

status = sigaddset(&mySet, SIGQUIT);

if (status == -1)‏

perror("Failed to add SIGQUIT signal to signal set");

if (sigismember(&mySet, SIGINT))‏

fprintf(stderr, "The set contains the SIGINT signal\n");

else

fprintf(stderr, "The set does not contain the SIGINT signal\n");

return 0;

} // End main

sigprocmask function
sigprocmask() Function
  • A process can examine or modify its process signal mask with the sigprocmask() function#include <signal.h>int sigprocmask(int how, const sigset_t *set, sigset_t *oldSet);
    • The how parameter is an integer specifying the manner in which the signal mask is to be modified
    • The set parameter is a pointer to a signal set to be used in the modification
      • If set is NULL, no modification is made
    • If oldSet is not NULL, the function sets oldSet to a pointer pointing to the signal set used before the modification
  • If successful, the function returns zero; otherwise, it returns –1 and sets errno
  • The sigprocmask() function should only be used by a process with a single thread
    • When multiple threads exist, the pthread_sigmask() function should be used
using the sigprocmask function
Using the sigprocmask() Function
  • The how parameter can take on one of the following three values
    • SIG_BLOCK Add a collection of signals to those currently blocked
    • SIG_UNBLOCK Delete a collection of signals from those currently blocked
    • SIG_SETMASK Set the collection of signals being blocked to the specified set
  • Some signals, such as SIGSTOP and SIGKILL cannot be blocked
    • If an attempt is made to block these signals, the system ignores the request without reporting an error
  • The program on the next slide enters an infinite loop in which it displays a message, blocks the SIGINT signal, does some calculations, unblocks the signal, and does some more calculations
    • If a user enters Ctrl-C while SIGINT is blocked, the programs finishes the calculations and prints the message "Calculation ran safe from interruption" before terminating
    • If a user enters Ctrl-C while SIGINT is unblocked, the program terminates immediately (probably in the midst of the unblocked calculation loop)‏
example 1 use of sigprocmask
Example #1: use of sigprocmask()‏

#include <math.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main(void)

{

int i;

sigset_t intMask;

int repeatFactor = 10000;

double y = 0.0;

int status;

status = sigemptyset(&intMask);

if (status == -1)‏

{

perror("Failed to initialize the signal set");

return 1;

} // End if

status = sigaddset(&intMask, SIGINT);

if (status == -1)‏

{

perror("Failed to add SIGINT to the signal set");

return 1;

} // End if

(More on next slide)‏

example 1 use of sigprocmask continued
Example #1: use of sigprocmask() (continued)‏

for ( ; ; ) // Infinite loop

{

status = sigprocmask(SIG_BLOCK, &intMask, NULL);

if (status == -1)‏

break;

fprintf(stderr, "Blocked the SIGINT signal\n");

for (i = 0; i < repeatFactor; i++)

y = y + sin((double)i);

fprintf(stderr, "[SIGINT Blocked] Calculation ran safe from interruption\n");

status = sigprocmask(SIG_UNBLOCK, &intMask, NULL);

if (status == -1)‏

break;

fprintf(stderr, "Unblocked the SIGINT signal\n");

for (i = 0; i < repeatFactor; i++)

y = y + sin((double)i);

fprintf(stderr,

"[SIGINT Unblocked] Calculation ran, but vulnerable to interruption\n");

} // End for

perror("Failed to block or unblock signal mask");

return 1;

} // End main

example 2 use of sigprocmask
Example #2: use of sigprocmask()‏

#include <errno.h>

#include <stdio.h>

#include <signal.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/wait.h>

int main(void)

{

pid_t pid;

sigset_t mask, oldMask;

int status;

status = sigfillset(&mask);

if (status == -1)‏

{

perror("Failed to fill the signal set");

return 1;

} // End if

(More on next slide)‏

example 2 use of sigprocmask continued
Example #2: use of sigprocmask()(continued)‏

status = sigprocmask(SIG_SETMASK, &mask, &oldMask);

if (status == -1)

{

perror("Failed to block signals using the signal mask");

return 1;

} // End if

else

fprintf(stderr,

"\nParent set mask to block all signals before creating child\n\n");

pid = fork();

if (pid == -1)

{

perror("Failed to create child process");

return 1;

} // End if

if (pid == 0) // Child process

{

fprintf(stderr,

"Child process is running with inherited signal mask from parent\n\n");

execl("/bin/ls", "ls", "-l", NULL);

perror("exec function failed in child process");

return 1;

} // End if

(More on next slide)‏

example 2 use of sigprocmask continued27
Example #2: use of sigprocmask()(continued)‏

else // Parent process

{

fprintf(stderr, "Parent created child process\n\n");

status = sigprocmask(SIG_SETMASK, &oldMask, NULL);

if (status == -1)

{

perror("Parent failed to restore signal mask");

return 1;

} // End if

else

fprintf(stderr,

"Parent reset signal mask to original values after creating child\n\n");

fprintf(stderr, "Parent waiting for child process to terminate...\n\n");

status = wait(NULL);

if (status == -1)

{

perror("Parent failed to wait for child");

return 1;

} // End if

fprintf(stderr, "\nParent has detected termination of child process\n");

} // End else

return 0;

} // End main

example 2 sample output
Example #2: Sample Output

uxb2% a.out

Parent set mask to block all signals before creating child

Parent created child process

Parent reset signal mask to original values after creating child

Parent waiting for child process to terminate...

Child process is running with inherited signal mask from parent

total 6

drwx------ 12 jjt107 faculty 1024 Jun 21 10:35 Files

drwx------ 2 jjt107 faculty 1024 Jul 24 08:43 Mail

drwx--x--x 19 jjt107 faculty 1024 Jul 3 12:32 http

Parent has detected termination of child process

uxb2%

sigaction function
sigaction() Function
  • The sigaction() function allows the calling program to set and examine the action associated with a specific signal#include <signal.h>int sigaction(int signalNbr, const struct sigaction *action, struct sigaction *oldAction);
    • The signalNbr parameter specifies the signal number for the action
    • The action parameter is a pointer to a struct sigaction structure that specifies the action to be taken
    • If action is NULL, the call to the function does not change the action associated with the signal
    • The oldAction parameter is a pointer to a struct sigaction structure that is assigned the previous action associated with the signal
  • If successful, the function returns zero; otherwise, it returns –1 and sets errno
struct sigaction
struct sigaction
  • The struct sigaction structure has the following contents:struct sigaction{void (*sa_handler)(int);sigset_t sa_mask;int sa_flags;void (*sa_sigaction)(int, siginfo_t *, void *);};
    • The sa_handler member is assigned SIG_DFL, SIG_IGN or a pointer to a signal handler function
    • The sa_mask member is assigned additional signals to be blocked during execution of the handler
    • The sa_flags member is assigned special flags and options
    • The sa_sigaction member is assigned a pointer to a real-time signal handler
  • The storage for sa_handler and sa_sigaction may overlap; consequently, a program should use only one of these members to specify the action
    • If the SA_SIGINFO flag of the sa_flags field is cleared, the sa_handler field specifies the action to be taken for the specified signal
    • If the SA_SIGINFO flag of the sa_flags field is set, the sa_sigaction field specifies a signal-catching function
struct sigaction continued
struct sigaction(continued)‏
  • This code segment sets the signal handler for SIGINT to mySignalHandler()struct sigaction newAction;int status;newAction.sa_handler = mySignalHandler; // Set the signal handlernewAction.sa_flags = 0; // No special actionsstatus = sigemptyset(&newAction.sa_mask);if (status == -1) perror("Failed to initialize signal set");else { status = sigaction(SIGINT, &newAction, NULL); if (status == -1) perror("Failed to install signal handler for SIGINT"); } // End else
signal handler
Signal Handler
  • A signal handler is an ordinary function that returns void and has one integer parameter
  • When the operating system delivers the signal, it sets the parameter to the number of the signal that was delivered
    • Most signal handlers ignore this value, but it is possible to use the same signal handler for many signals
  • The usefulness of signal handlers is limited by the inability to pass values to them (this has been corrected for the sa_sigaction handler)‏
  • Two special values of the sa_handler member of the struct sigaction structure are SIG_DFL and SIG_IGN
    • SIG_DFL specifies that the sigaction() function should restore the default action for the signal
    • SIG_IGN specifies that the process should handle the signal by ignoring it (throwing it away)
example use of sig ign
Example use of SIG_IGN
  • The following code segment causes the process to change its new action to ignore the SIGINT signal if the default action is currently in effect for this signalstruct sigaction action;int status;status = sigaction(SIGINT, NULL, &action);if (status == -1) perror("Failed to get old handler information for SIGINT");else if (action.sa_handler == SIG_DFL) { action.sa_handler = SIG_IGN; status = sigaction(SIGINT, &action, NULL); if (status == -1) perror( "Failed to set SIGINT signal handler to ignore signal"); } // End else
example sigint signal handler
Example SIGINT Signal Handler

#include <signal.h>

#include <stdio.h>

#include <unistd.h>

#define MAX_PRESSES 5

static int pressCount = 0;

void catchCtrlC(int signalNbr);

int main(void)‏

{

// See next slide

}

// This function is the signal handler

void catchCtrlC(int signalNbr)‏

{

char message[] = "Ctrl-C was pressed\n";

write(STDERR_FILENO, message, strlen(message) );

pressCount++; // Global variable

} // End catchCtrlC

The catchCtrlC() function is defined here as

a signal handler for the SIGINT signal generated

by Ctrl-C.

The write() function is used instead offprintf() because POSIX guarantees thatit is async-signal safe, meaning that thefunction can be called safely from within

a signal handler.

(More on next slide)‏

example sigint signal handler continued
Example SIGINT Signal Handler(continued)‏

Sample Output

// *****************************************

int main(void)

{

struct sigaction action;

int status;

action.sa_handler = catchCtrlC;

action.sa_flags = 0;

status = sigemptyset(&action.sa_mask);

if (status == -1)‏

{

perror("Failed to initialize signal set");

exit(1);

} // End if

status = sigaction(SIGINT, &action, NULL);

if (status == -1)‏

{

perror("Failed to set signal handler for SIGINT");

exit(1);

} // End if

while (pressCount < MAX_PRESSES); // Loop has no statements

return 0;

} // End main

uxb3% a.out

Ctrl-C was pressed

Ctrl-C was pressed

Ctrl-C was pressed

Ctrl-C was pressed

Ctrl-C was pressed

uxb3%

waiting for signals
Waiting for Signals
  • Signals provide a method for waiting for an event without busy waiting
  • Busy waiting means continually using CPU cycles to test for the occurrence of an event (Typically through the use of a loop)‏
  • A more efficient approach is to suspend the process until the waited-for event occurs
    • That way, other processes can use the CPU productively
  • The pause(), sigsuspend(), and sigwait() functions provide three mechanisms for suspending a process until a signal occurs
pause function
pause() Function
  • The pause() function suspends the calling thread until the delivery of a signal whose action is either to execute a user-defined signal handler or to terminate the process#include <unistd.h>int pause(void);
  • If the action is to terminate, pause() does not return
  • If a signal is caught by the process, pause() returns after the signal handler returns
  • The pause() function always returns –1
    • If interrupted by a signal, pause() sets errno to EINTR
  • To wait for a particular signal by using pause(), a program must determine which signal caused pause() to return
    • This information is not directly available, so the signal handler must set a global flag for the program to check after pause() returns
example of pause and sigint signal handler
Example of pause() and SIGINT Signal Handler

Sample Output

int main(void)

{

struct sigaction action;

int status;

action.sa_handler = catchCtrlC;

action.sa_flags = 0;

status = sigemptyset(&action.sa_mask);

if (status == -1)‏

{

perror("Failed to initialize signal set");

exit(1);

} // End if

status = sigaction(SIGINT, &action, NULL);

if (status == -1)‏

{

perror("Failed to set signal handler for SIGINT");

exit(1);

} // End if

fprintf(stderr, "Program paused . . .\n");

pause();

return 0;

} // End main

uxb3% a.out

Program paused . . .

Ctrl-C was pressed

uxb3%

sequence problems with the pause function
Sequence Problems with the pause() Function
  • The following code segment uses pause() to cause a process to wait for a particular signal by having the signal handler set the sigreceived variable to 1static sig_atomic_t sigreceived = 0;. . .while (sigreceived == 0) pause();
  • What happens if a signal occurs after the test of sigreceived but before pause()?
    • The pause() function would not return at that time, but would wait until some other signal or the occurrence of the same signal was delivered again to the process
  • The delivery of a signal before the pause() function was called in a program was one of the major problems with the original UNIX signals
    • There was no simple, reliable way to get around the problem
  • The program must do two operations at once: unblock the signal and call the pause() function
    • In other words, the two operations need to be atomic (i.e., logically viewed as one instruction)‏
  • The sigsuspend() function provides a method of achieving this
sigsuspend function
sigsuspend() Function
  • The sigsuspend() function replaces the process signal mask with the set of signals pointed to by the signalMask argument and suspends the process until delivery of a signal whose action is either to execute a signal handler function or to terminate the process.#include <signal.h>int sigsuspend(const sigset_t *signalMask);
  • The sigsuspend() function returns when the signal handler of the caught signal returns
  • The signalMask parameter can be used to unblock the signal that the program is looking for
  • When sigsuspend() returns, the signal mask is reset to the value it had before the sigsuspend() function was called
  • The sigsuspend() function always returns –1 and sets errno
example use of sigsuspend
Example use of sigsuspend()‏
  • The program on the next slide shows a way for a process to wait for a single signal
  • Assume that a signal handler has been set up for the sigNbr signal and that the signal handler sets sigReceived to 1
  • Error checking has been omitted from the code for clarity purposes
  • The maskAll structure contains all signals
  • The maskMost structure contains all signals except sigNbr
  • No signals can be caught between the testing of sigReceived and the suspension of the process, since the signal is blocked at this point
  • The process signal mask had the value contained in maskMost while the process is suspended, so only sigNbr is not blocked
  • When sigsuspend() returns, the signal must have been received
example use of sigsuspend continued
Example use of sigsuspend()(continued)‏

Command Shell A

#include <stdio.h>

#include <signal.h>

static sig_atomic_t sigReceived = 0;

int main(void)‏

{

int status;

sigset_t maskAll;

sigset_t maskMost;

sigset_t maskOld;

int sigNbr = SIGUSR1;

fprintf(stderr, "PID: %d\n", getpid());

sigfillset(&maskAll);

sigfillset(&maskMost);

sigdelset(&maskMost, sigNbr);

sigprocmask(SIG_SETMASK, &maskAll, &maskOld);

if (sigReceived == 0)‏

sigsuspend(&maskMost);

sigprocmask(SIG_SETMASK, &maskOld, NULL);

return 0;

} // End main

uxb3% a.out

PID 2624

uxb3% a.out

PID 3548

uxb3%

Command Shell B

uxb3% kill –INT 2624

uxb3%

uxb3% kill –USR1 2624

uxb3% kill –9 3548

uxb3%

sigwait function
sigwait() Function
  • The sigwait() function blocks until any of the signals in the structure pointed to by signalMask becomes pending
    • It then removes that signal from the set of pending signals and unblocks itself#include <signal.h>int sigwait(const sigset_t *signalMask, int *signalNbr);
  • When sigwait() returns, the number of the signal that was removed from the pending signals is stored in the location pointed to by signalNbr
  • If successful, sigwait() returns zero; otherwise, it returns –1 and sets errno
  • Note the difference between sigwait() and sigsuspend()‏
    • Both functions have a first parameter that is a pointer to a signal set
    • For sigsuspend(), this signal set holds the new signal mask and so the signals that are not in the set are the ones that can cause sigsuspend() to return
    • For sigwait(), this signal set holds the set of signals to be waited for, so the signals in the set are the ones that can cause the sigwait() to return
    • Unlike sigsuspend(), the sigwait() function does not change the process signal mask
    • The signals in signalMask should be blocked before sigwait() is called
example use of sigwait
Example use of sigwait()‏

#include <signal.h>

#include <stdio.h>

int main(void)‏

{

int signalCount = 0;

int signalNbr;

sigset_t signalSet;

int status;

status = sigfillset(&signalSet);

if (status == -1)‏

perror("Failed to fill the signal set");

status = sigprocmask(SIG_BLOCK, &signalSet, NULL);

if (status == -1)‏

perror("Failed to block signals");

fprintf(stderr, "This process has ID %ld\n", (long)getpid());

(More on next slide)‏

example use of sigwait continued
Example use of sigwait()(continued)‏

for ( ; ; ) // Infinite loop

{

signalNbr = sigwait(&signalSet); // Default version

if (signalNbr == -1)‏

{

perror("Failed to wait using sigwait");

return 1;

} // End if

else

fprintf(stderr, "Unblocked signal #%d\n", signalNbr);

/*

status = sigwait(&signalSet, &signalNbr); // POSIX version

if (status == -1)‏

{

perror("Failed to wait using sigwait");

return 1;

} // End if

*/

signalCount++;

fprintf(stderr, "Number of signals so far: %d\n", signalCount);

} // End for

} // End main

example use of sigwait sample output
Example use of sigwait(): Sample Output

Command Shell A

Command Shell B

uxb3% a.out

This process has ID 15469

Unblocked signal #16

Number of signals so far: 1

Unblocked signal #17

Number of signals so far: 2

Unblocked signal #2

Number of signals so far: 3

Unblocked signal #14

Number of signals so far: 4

Unblocked signal #16

Number of signals so far: 5

Unblocked signal #2

Number of signals so far: 6

Killed

uxb3%

uxb3% kill -USR1 15469

uxb3% kill -USR2 15469

uxb3% kill -INT 15469

uxb3% kill -ALRM 15469

uxb3% kill -USR1 15469

uxb3% kill -INT 15469

uxb3% kill -KILL 15469

uxb3%

signals and function calls
Signals and Function Calls
  • Three difficulties can occur when signals interact with function calls
    • The first problem concerns whether POSIX functions that are interrupted by signals should be restarted
    • The second problem occurs when signal handlers call non-reentrant functions
    • The third problem involves the handling of errors that use errno
  • What happens when a process catches a signal while it is executing a library function?
    • The answer depends on the type of call
  • Terminal I/O can block the process for an undetermined length of time
    • There is no limit on how long it takes to get a key value from a keyboard or to read from a pipe
    • Function calls that perform such operations are sometimes characterized as slow
  • Other operations, such as disk I/O, can block for short periods of time; still others, such as getpid(), do not block at all
    • Neither of these operations is considered to be slow
slow posix calls
Slow POSIX Calls
  • The slow POSIX calls are the ones that are interrupted by signals
  • They return when a signal is caught and the signal handler returns
  • The interrupted function returns –1 with errno set to EINTR
    • If a function sets errno and one of the possible values is EINTR, then the function can be interrupted
  • The program must handle this error explicitly and restart the system call if desired
  • It was originally thought that the operating system needs to interrupt slow calls to allow the user the option of canceling a blocked call
  • This traditional treatment of handling blocked functions has been found to add unneeded complexity to many programs, and it is not used in newly-created POSIX functions
async signal safe
Async-signal Safe
  • A function is async-signal safe if it can be safely called from within a signal handler
  • Many POSIX library functions are not async-signal safe because they use static data structures, call malloc() or free(), or use global data structures in a non-reentrant way
  • Consequently, a single process might not correctly execute concurrent calls to these functions
  • Normally this is not a problem in a program with no signal handlers, but signals add concurrency to a program
  • Since signals occur asynchronously, a process may catch a signal while it is executing a library function
    • Therefore, programmers must be careful when calling library functions from inside signal handlers
  • The next slide lists many of the POSIX functions that are safe to call from within a signal handler
    • Notice that functions such as scanf(), fscanf(), printf(), and fprintf() from the C standard I/O library are not on the list
some async signal safe functions

alarm

getppid

read

stat

chdir

kill

rmdir

time

chmod

link

sigaction

unlink

chown

lstat

sigaddset

wait

close

mkdir

sigdelset

waitpid

execle

mkfifo

sigfillset

write

execve

open

sigismember

fork

pause

sigprocmask

fstat

pipe

sigsuspend

getpid

raise

sleep

Some Async-signal Safe Functions
useful rules for signal handling
Useful Rules for Signal Handling
  • When in doubt that a function is async-signal safe or not, explicitly restart library function calls within a program
  • Check each library function used in a signal handler to make sure that it is on the list of async-signal safe functions
  • Carefully analyze the potential interactions between a signal handler that changes an external variable and other program code that accesses the variable
    • Block signals to prevent unwanted interactions
  • As a general rule, signal handlers should save and restore errno if they call functions that might change the value of errno