Instructor Dr Turgay Korkmaz Department Computer Science The University of Texas at San Antonio Office NPB 3330 Phone 210 4587346 Fax 210 4584437 email korkmazcsutsaedu ID: 673713
Download Presentation The PPT/PDF document "1 CS 3733 Operating Systems" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
1
CS 3733 Operating Systems
Instructor: Dr. Turgay KorkmazDepartment Computer ScienceThe University of Texas at San AntonioOffice: NPB 3.330Phone: (210) 458-7346 Fax: (210) 458-4437 e-mail: korkmaz@cs.utsa.eduweb: www.cs.utsa.edu/~korkmaz
Topics: Signals(USP Chapter 8.1-8.6)
These slides are prepared based on the materials provided by Drs. Robbins, Zhu, and Liu. Thanks to all.Slide2
2Outline
Overview of signalsConcepts and general terminologyPOSIX required signals
Signal generations: kill vs. raiseBlock signals and process signal masksSignal handles: catch vs. ignore SignalsWait signals: pause, sigsuspend and sigwaitErrors and async-signal safetyDepartment of Computer Science @ UTSASlide3
MotivationHow would you stop this program?Did you ever pres Ctrl-C when running a program?Did you ever use > kill -9 PIDIf yes, can you explain what is happening?We send a SIGNAL to a process…A signal is a software notification of an event to a process.Accordingly, the process takes an action (e.g., quit).Is this a SYNCHRONOUS or an ASYNCHRONOUS event?3
while(n=5){
printf(“n is %d\n”, n--); ...}
// vs. n==5Slide4
Signal Concept and TerminologyA 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 delivery.A signal that has been generated but not yet delivered is pending.A process catches a signal if it executes a signal handler when the signal is delivered.Alternatively, a process can ignore a signal when it is delivered, that is to take no action.4
Signal handler - functionSlide5
Signal Concept and Terminology - ExerciseA signal is __________when the event that causes the signal occurs.A signal is _________ when the process takes action based on the signal.The ________of a signal is the interval between its generation and delivery.A signal that has been generated but not yet delivered is_________.A process ________ a signal if it executes a signal handler when the signal is delivered.Alternatively, a process can ______ a signal when it is delivered, that is to take no action.5
Signal handler - function
generated
delivered
lifetime
pending
catches
ignore
Slide6
Signal Concept and Terminology (cont’d)The function sigaction is used to specify what is to happen to a signal when it is delivered.Each signal has a default action which is usually to terminate the process.The function sigprocmask is used to modify the signal mask.The signal mask determines the action to be taken when the signal is generated. It contains a list of signals to be
blocked.A blocked signal is not delivered to a process until it is unblocked.
6SignalMaskAction1
23
4Slide7
POSIX Required Signals: Table 8.17
REFSlide8
Generate Signals: Command LineThe kill commandSend a signal to a process from consoleThe usage of kill kill –l : list the signals the system understandskill [–signal] pid: send a signal to a process (pid)The default is SIGTERMExample: to unconditionally kill a process kill -9 pidkill –KILL pid
8Slide9
Generate Signals: Running ProgramThe kill system call#include <sys/types.h>#include <signal.h> int kill(pid_t pid, int sig);Example: send SIGUSR1 to process 3423if (kill(3423, SIGUSR1) == -1) perror
("Failed to send SIGUSR1 signal");Normally, do NOT specify pid as a numberUse
getpid() or getppid()9Slide10
Generate Signals: Running Program (cont.)Example: a child process kills its parentif (kill(getppid(), SIGTERM) == -1) perror ("Failed to kill parent");The raise system call: send a signal to itselfif (raise(SIGUSR1) != 0) perror("Failed to raise SIGUSR1");What do you think the following program does?int main(void) { alarm(10);
for ( ; ; ) ; }
10After 10 seconds, it gets SIGALRM, which (by default) kills the process…Slide11
Signal Mask and Signal SetsHow do you deal with a set of signals?How can we prevent a signal from being delivered?11SignalMask
Action1
234Slide12
Signal Mask and Signal SetsEach process has a signal maskDefines the set of signals to be BLOCKED!The set of signals: type sigset_t (originally was int, one bit per signal) Routines to handle signal sets (compare to select(…) which handles FDs)#include <signal.h> int sigemptyset( sigset_t *set);
int sigfillset( sigset_t *set);
int sigaddset( sigset_t *set, int signo); int sigdelset( sigset_t *set, int signo); int
sigismember(const sigset_t *set, int signo
);
12
initializes the set to contain no signals
puts all signals in the set
adds one signal to the set
removes one signal from the set
tests to see if a signal is in the set
if((
sigemptyset
(&
twosigs
) == -1) ||
(
sigaddset
(&
twosigs
, SIGINT) == -1) ||
(
sigaddset
(&
twosigs
, SIGQUIT) == -1))
perror
("Failed to set up signal mask");Slide13
Sys. Call to Modify Signal Mask: sigprocmask The system call: sigprocmask int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);how:
an integer specifying how the signal mask is to be modified: SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASKset: a pointer to a signal set to be used in the modification. If set is NULL, no modification is made.
oset: If oset is not NULL, the sigprocmask returns in *oset the signal set before the modification.Example: initialize a signal set and set masksigset_t newsigset; if ((sigemptyset(&newsigset) == -1) || (sigaddset(&newsigset
, SIGINT) == -1)) perror("Failed to initialize signal set"); else if (sigprocmask(
SIG_BLOCK
, &
newsigset,NULL
) == -1)
perror
("Failed to block SIGINT”);
13
Some signals
(
e.g., SIGSTOP and SIGKILL
)
cannot be blocked. Slide14
Example: Block/Unblock SIGINT14Alternating block/unblock SIGINT
Ctrl+C
: will not return immediately if in block section!
Ctrl+C: will return immediately if in unblock section!Slide15
Example: block all signals while creating two pipes, then restore old ones15int makepair(char *pipe1, char *pipe2) { sigset_t blockmask;
sigset_t oldmask;
int returncode = 0; if(sigfillset(&blockmask) == -1) return -1; if(sigprocmask(SIG_SETMASK, &blockmask, &oldmask) == -1)return -1;
if(((mkfifo(pipe1, RW_MODE) == -1) && (errno != EEXIST)) || ((mkfifo
(pipe2, RW_MODE) == -1) && (
errno
!= EEXIST))) {
returncode
=
errno
;
unlink(pipe1); unlink(pipe2);
}
if((
sigprocmask
(SIG_SETMASK, &
oldmask
, NULL)
== -1) && !
returncode
)
returncode
=
errno
;
if(
returncode
) {
errno
=
returncode
;
return -1;
}
return 0;
}
#include <
errno.h
>
#include <
signal.h
>
#include <
unistd.h
>
#include <sys/
stat.h
>
#define R_MODE (S_IRUSR | S_IRGRP | S_IROTH)
#define W_MODE (S_IWUSR | S_IWGRP | S_IWOTH)
#define RW_MODE (R_MODE | W_MODE)Slide16
Example: Block Signals & fork: child inherit mask16No interruption during child’s execution!
mask contains ALL signals!Slide17
Catching and Ignoring Signals: sigactionLet caller to examine or specify the action associated with a specific signal.17SignalMask
Action1
234Slide18
Set up signal handler: sigaction int sigaction(int signo, struct sigaction *act, struct sigaction *oact);
signo: specifies the signal number for the action. act: a pointer to a struct
sigaction structure that specifies the action to be taken. oact: a pointer to a struct sigaction structure that receives the previous action associated with the signal. If act is NULL, do not change the action associated with the signal. Either act or oact may be NULL.18Slide19
struct sigaction structurestruct sigaction { void (*sa_handler)(int); /* SIG_DFL, SIG_IGN or pointer to function (no return value) */
sigset_t sa_mask
; /* additional signals to be blocked */ int sa_flags; /* special flags and options */ void (*sa_sigaction) (int
, siginfo_t *, void *); /*
realtime
handler */
};
SIG_DFL: restore the default action for the signal.
SIG_IGN: handle the signal by ignoring it
(throwing it away).
Pointer to a user defined function (signal handler)
The storage for
sa_handler
and
sa_sigaction
may overlap, and an application should use only one of these members to specify the action.
If the
SA_SIGINFO
flag of the
sa_flags
field is
cleared
,
sa_handler
specifies the action to be taken.
If the
SA_SIGINFO
flag of the
sa_flags
field is
set
,
sa_sigaction
field specifies a signal-catching function.
19Slide20
Example: new handler for SIGINTSet up a signal handler that catches the SIGINT signal generated by Ctrl-C.20act.sa_handler=SIG_DFL;act.sa_handler=SIG_IGN;// and use the same procedure
How about ignoring SIGINT if the default action is in effect for this signal? (next slide)
How can we reset SIGINT to the default handler or ignore it?Slide21
Example: ignore SIGINT if the default action is in effect for this signal. struct sigaction act;if(sigaction(SIGINT,NULL, &act)==-1)/* Find current SIGINT handler */ perror("Failed to get old handler for SIGINT");else if(act.sa_handler == SIG_DFL){
/* if SIGINT handler is default */ act.sa_handler = SIG_IGN;
/* set new SIGINT handler to ignore */ if(sigaction(SIGINT, &act, NULL) == -1) perror("Failed to ignore SIGINT");}21Slide22
Exercise: A program that terminates gracefully on ctrl-C Ex1: Terminate program after receiving ctrl-C three timesEx1: Write a program that terminates gracefully on ctrl-C! (i.e., finish doSomething() then quit!)while(1) { // doSomething() }Print a msg that Program ends gracefully…22Slide23
Ex1: and Ex2: need modifications here… 23Slide24
Wait for SignalsSignals provide a method for waitingfor an event without busy waiting.int pause(void); int sigsuspend(const sigset_t *sigmask);int sigwait(
sigset_t *restrict sigmask,
int *restrict signo);24Si
gnalMaskAction
1
2
3
4Slide25
Wait for Signal: pause()The usage of pause() #include <unistd.h> int pause(void);Blocks/suspends the process until it receives a signal!Always return -1; if interrupted, set errno as EINTRHowever, no information about which signal causes it return!Can we use pause() to wait for a particular signal?How to know which signal?The signal handler of the wanted signal sets a flagAfter return from pause(), check the flag25
…pause();….Slide26
Wait for Signal: pause() – cont.static volatile sig_atomic_t sigreceived = 0; void catch_signal(int signo){ sigreceived = 1; //handler}…
while(sigreceived == 0) pause();
26What if the desired signal occurs between condition check and pause()? -- Wait for another occurrence again or other signals! -- What if there is no other signal! – Deadlock So, we need to block the signal when checking the condition!
struct
sigaction
act;
act.sa_handler
=
catch_signal
;
act.sa_flags
= 0;
sigemptyset
(&
act.sa_mask
);
sigaction
(SIGUSR1, &act, NULL);Slide27
Wait for Signal: pause() – cont.What about this solution?static volatile sig_atomic_t sigreceived = 0; int signum = SIGUSR1; //desired signal sigset_t sigset;sigemptyset(&
sigset); sigaddset(&
sigset, signum); //desired signal sigprocmask(SIG_BLOCK, &sigset, NULL); while(sigreceived == 0) pause(); 27
It executes pause while the signal is blocked, so theprogram never receives the signal and pause never returns!We need to atomically unblock the signal and suspend
the process
after checking the condition!Slide28
The sigsuspend() FunctionSuspends the process until a signal is receivedWe will use it to unblock the signal and pause the process in an atomic manner#include <signal.h> int sigsuspend(const sigset_t *
sigmask);Sets the signal mask to the one pointed to by sigmask and suspends the process until a signal is caught (in
atomic manner).It returns when the signal handler of the caught signal returns. This function always returns -1. Also the signal mask is restored to what it was before this function was called. 28Slide29
A wrong way to wait for a signal: wait for SIGUSR1sigfillset(&sigmost);sigdelset(&sigmost, SIGUSR1);while(sigreceived == 0) sigsuspend(&sigmost);The sigmost signal set contains all signals except the one to wait for. When the process suspends, only the signal SIGUSR1 is unblocked and so it seems that only this signal can cause sigsuspend
to return. But, it has the same problem as pause. If the signal is delivered before the sigsuspend call, the process still suspends itself and deadlocks if another SIGUSR1 signal is not generated.
29Slide30
How to use sigsuspend() to wait for a signalHave an handler to set a flag for the signal (e.g. signo)Block the signal with signoCreate a sigmask without signowhile(flag == 0) sigsuspend(sigmask);Signal signo
is blocked until sigsuspend is calledSigsuspend unblocks the signal signo and suspends When the signal is caught, the handler will be executed. Then sigsuspend returns and restores the previous mask (i.e., block the signal with
signo again) 30Slide31
A correct way to wait for a signal: wait for SIGUSR1sigset_t blockmask, sigmask; sigemptyset(&blockmask); sigemptyset(&sigmask); sigaddset(&blockmask, SIGUSR1); sigprocmask
(SIG_BLOCK, &blockmask, NULL); while(sigreceived
== 0) sigsuspend(&sigmask);31static volatile sig_atomic_t
sigreceived = 0;
void
catch_signal
(
int
signo
){
sigreceived
= 1;
}
Sets the signal mask to the one in
sigmask
(i.e.,
unblocks SIGUSR1 and suspends the process until a signal happens)
.
When it returns, the signal mask is restored to what it was before it was called.
Do tk-quiz-16Slide32
A correct way to wait for a signal while allowing other signals to be handled: 3. sigset_t maskblocked, maskold, maskunblocked;4. int signum = SIGUSR1;5.6. sigprocmask(SIG_SETMASK, NULL, &maskblocked
);7. sigprocmask(SIG_SETMASK, NULL, &maskunblocked
);8. sigaddset(&maskblocked, signum);9. sigdelset(&maskunblocked, signum);10. sigprocmask(SIG_BLOCK, &maskblocked, &
maskold);11. while(sigreceived == 0) 12. sigsuspend(&maskunblocked
);
13.
sigprocmask
(SIG_SETMASK, &
maskold
, NULL);
32
OPT
Robust
version Slide33
The sigwait() Function:An alternative way to wait for signalsint sigwait(const sigset_t *restrict sigmask, int *restrict signo); Block all signals that we want to wait forPut the signals you want to wait for in a sigset_tcall sigwait, which blocks the process until at least one of these signals is pending.
It removes one of the pending signals and gives you the corresponding signal number in the second parameter.Do what you want: no signal handler needed.It returns 0 on success and -1 on error with errno set
33How is this different than sigsuspend?Slide34
Differences between sigwait() and sigsuspend()Both functions have a first parameter that is a pointer to a signal set (sigset_t *). For sigsuspend, this 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 parameter 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, sigwait does not change the process signal mask. The signals in sigmask should be blocked before sigwait is called.
34Slide35
Count Signals35
First, block the signal
Wait only for the signal!Slide36
Issues in Handling Signals…Errors and async-signal safetyThree issues in handling signals:Certain blocking system calls (e.g., read) return -1 and set errno to EINTR if a signal is caught while the function is blocked.Error handling in signal handlersAsync-signal safety36Slide37
Signals and blocking system calls Certain blocking system calls will return -1 with errno set to EINTR if a signal is caught while the function is blocked.Check the man page to see if a system call can set errno to EINTR.If this happens, you should usually restart the function since a real error has not occurred. The restart library handles this for many of the most important system calls. Look at the functions in the restart library. 37Slide38
Handling errors in signal handlersIf you use a function that can modify errno in a signal handler, you must make sure that it does not interfere with error handling in the main part of the program.There is only one errno and it is used by both the main program and by the signal handler.Solution: in the signal handler, save and restore errno. void myhandler(int signo) { int
esaved; esaved
= errno; write(STDOUT_FILENO, "Got a signal\n", 13); errno = esaved; } 38Slide39
Async-signal safety.Only certain system calls and library functions may be used safely in a signal handler.The strtok function is an example of a function that might have a problem.In fact, the POSIX standard only guarantees that a small number of functions are async-signal safe, that is safe to use in a signal handler and the main program.Other functions may be async-signal safe in some implementations.Almost none of the functions in the standard C library are on the list.39Slide40
Functions that POSIX guarantees to be async-signal safe.40_Exit execve lseek sendto
stat
_exit fchown lstat setgid symlink accept fcntl mkdir setpgid
sysconf access fdatasync
mkfifo
setsid
tcdrain
aio_error
fork
open
setsockopt
tcflow
aio_return
fpathconf
pathconf
setuid
tcflush
aio_suspend
fstat
pause
shutdown
tcgetattr
alarm
fsync
pipe
sigaction
tcgetpgrp
bind
ftruncate
poll
sigaddset
tcsendbreak
cfgetispeed
getegid
posix_trace_event
sigdelset
tcsetattr
cfgetospeed
geteuid
pselect
sigemptyset
tcsetpgrp
cfsetispeed
getgid
raise
sigfillset
time
cfsetospeed
getgroups
read
sigismember
timer_getoverrun
chdir
getpeername
readlink
signal
timer_gettime
chmod
getpgrp
recv
sigpause
timer_settime
chown
getpid
recvfrom
sigpending
times
clock_gettime
getppid
recvmsg
sigprocmask
umask
close
getsockname
rename
sigqueue
uname
connect
getsockopt
rmdir
sigset
unlink
creat
getuid
select
sigsuspend
utime
dup
kill
sem_post
sleep
wait
dup2
link
send
socket
waitpid
execle
listen
sendmsg
socketpair
write Slide41
Signals and Threads How do you handle signals in a threaded environment? 41Slide42
Handling signals in a multithreaded environmentIf a signal is sent to a threaded program, any of the threads can handle the signal. Each thread inherits the process signal mask, but each thread has its own signal mask that can be modified with pthread_sigmask. sigprocmask should not be used in a threaded environment, but it can be used before the threads are created. The simplest way to handle signals in a multithreaded environment is to have a thread dedicated to signal handling.42Slide43
Handling signals in a multithreaded environment - contIssues involving signal safety can be handled by using sigwait: The main process blocks all signals before creating any threads. No signal handlers are set up. A thread is created to handle the signals. That thread sets up a sigset_t containing the signals of interest. It loops, calling sigwait and handles the pending signals.43Slide44
EXTRAS….44Slide45
Real Time Signals (USP 9.4)sigactionvoid(*sa_sigaction) (int, siginfo_t *, void *); /* realtime handler */When SA_SIGINFO flag is setsa_sigaction specifies the action to be takenA new type of signal handler: take 3 parametersSignals for this type of signal handlers are queuedUse sigqueue instead of kill to send one of these signalsint sigqueue(pid_t
pid, int
signo, const union sigval value);45Slide46
Set Up a Real Time Signal Handler46Slide47
An Example: Send a queue signal47