作業系統導論(一) - ncue.edu.tw

Download Report

Transcript 作業系統導論(一) - ncue.edu.tw

Signals

What is a Signal?


A signal is an event generated by the UNIX and Linux systems in
response to some condition, upon receipt of which a process
may in turn take some action.
Signals are software generated interrupts that are sent to
a process when a event happens.
1
The Role of Signals

Signals serve two main purposes:


To make a process aware that a specific event has occurred.
To force a process to execute a signal handler function
included in its code.
2

Each signal defined by the system falls into one of five
classes:





Hardware conditions
Software conditions
Input/output notification
Process control
Resource control
3
Signal Handling


func() can have three values:
SIG_DFL


SIG_IGN


a pointer to a system default function SID_DFL(), which will
terminate the process upon receipt of sig.
a pointer to system ignore function SIG_IGN() which will
disregard the sig action (UNLESS it is SIGKILL).
A function address

a user specified function.
4

Each signal has a default action which is one of the
following:




The signal is discarded after being received
The process is terminated after the signal is received
A core file is written, then the process is terminated
Stop the process after the signal is received
5
Signals Function

Programs can handle signals using the signal
library function.
Header file:
#include <signal.h>
Function declaration:
void signal(int sig, void (*func) (int) );
Parameters:
sig :The signal to be caught or ignored.
func :The function to be called when the specified
signal is received.
6
Macros are defined in <signal.h>

Signals can be numbered from 0 to 31.









SIGHUP 1 /* hangup */
SIGINT 2 /* interrupt */
SIGQUIT 3 /* quit */
SIGILL 4 /* illegal instruction */
SIGABRT 6 /* used by abort */
SIGKILL 9 /* hard kill */
SIGALRM 14 /* alarm clock */
SIGCONT 19 /* continue a stopped process */
SIGCHLD 20 /* to parent on child stop or exit */
7
Signals Function
Table of Signal
Name
Description

SIGINT
SIGABORT
SIGKILL
SIGUSR1
Linux sends a process this signal when the user tries to
end it by pressing Ctrl+C.
The abort function causes the process to receive this
signal.
This signal ends a process immediately and cannot be
handled.
This signal is reserved for application use.
8

The most common way of sending signals to processes
is using the keyboard. There are certain key presses that
are interpreted by the system as requests to send signals
to the process with which we are interacting:

Ctrl-C


Ctrl-Z


Pressing this key causes the system to send an INT signal (SIGINT)
to the running process. By default, this signal causes the process to
immediately terminate.
Pressing this key causes the system to send a TSTP signal
(SIGTSTP) to the running process. By default, this signal causes the
process to suspend execution.
Ctrl-\

Pressing this key causes the system to send a ABRT signal
(SIGABRT) to the running process. By default, this signal causes the
process to immediately terminate. Note that this redundancy (i.e.
Ctrl-\ doing the same as Ctrl-C) gives us some better flexibility. We'll
explain that later on.
9
example 1
/* We'll start by writing the function which reacts to the signal which is passed in the parameter sig.
This is the function we will arrange to be called when a signal occurs.
We print a message, then reset the signal handling for SIGINT
(by default generated by pressing CTRL-C) back to the default behavior.
Let's call this function ouch. */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! - I got signal %d\n", sig);
(void) signal(SIGINT, SIG_DFL);
}
/* The main function has to intercept the SIGINT signal generated when we type Ctrl-C .
For the rest of the time, it just sits in an infinite loop, printing a message once a second. */
int main()
{
(void) signal(SIGINT, ouch);
while(1) {
printf("Hello World!\n");
sleep(1);
}
10
}
#include <signal.h>
int n;main(int argc, char **argv)
{
void InterruptHandler(), InitHandler(); n = 0;
signal(SIGINT, InterruptHandler); /* signal 2 */
signal(SIGHUP, InitHandler); /* signal 1 */
while (1)
{
n++;
sleep(1);
} }
void InterruptHandler()
{ printf("The current value of n is %d\n", n);
exit(0);
}
void InitHandler()
{ printf("Resetting the value of n to zero\n");
n = 0;
}
11
% cc -o signal signal.c
% ./signal
./signal
^C
(interrupt character)
The current value of n is 3%
./signal &
[1] 20822
% kill -1 %1
Resetting the value of n to zero
% kill -2 %1
The current value of n is 19
[1] Done
./signal
12
Sending Signals

There are two common functions used to send signals.

int kill(int pid, int signal)


a system call that send a signal to a process, pid. If pid is
greater than zero, the signal is sent to the process whose
process ID is equal to pid. If pid is 0, the signal is sent to all
processes, except system processes.
int raise(int sig)

sends the signal sig to the executing program.
13
Sending Signals

raise() actually uses kill() to send the signal to the
executing program:
kill(getpid(), sig);

There is also a UNIX command called kill that can be
used to send signals from the command line to terminate
running process.
kill -<signal> <PID>
kill -INT 5342
kill -9 5342 (SIGKILL 9 /* hard kill */)
14
alarm()

The alarm function call can be used by a process
to schedule a SIGALRM signal at some time in
the future.
15
example 3
/* In alarm.c, the first function, ding, simulates an alarm clock. */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static int alarm_fired = 0;
void ding(int sig)
{
alarm_fired = 1;
}
/* In main, we tell the child process to wait for five seconds
before sending a SIGALRM signal to its parent. */
int main()
{
int pid;
printf("alarm application starting\n");
if((pid = fork()) == 0) {
sleep(5);
kill(getppid(), SIGALRM);
exit(0);
}
16
/* The parent process arranges to catch SIGALRM with a call to signal
and then waits for the inevitable. */
printf("waiting for alarm to go off\n");
(void) signal(SIGALRM, ding);
pause();
if (alarm_fired)
printf("Ding!\n");
printf("done\n");
exit(0);
}
17
Example 5
/* sig_talk.c --- Example of how 2 processes can talk to each other using kill() and signal().
We will fork() 2 process and let the parent send a few signals to it`s child. */
/* cc sig_talk.c -o sig_talk */
#include <stdio.h>
#include <signal.h>
void sighup(); /* routines child will call upon sigtrap */
void sigint();
void sigquit();
main()
{ int pid;
/* get child process */
if ((pid = fork()) < 0)
{
perror("fork");
exit(1); }
if (pid == 0)
{ /* child */
signal(SIGHUP,sighup); /* set function calls */
signal(SIGINT,sigint);
signal(SIGQUIT, sigquit);
for(;;); /* loop for ever */
} else /* parent */
18
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid,SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid,SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid,SIGQUIT);
sleep(3);
}}
void sighup()
{
signal(SIGHUP,sighup); /* reset signal */
printf("CHILD: I have received a SIGHUP\n");
}
void sigint()
{
signal(SIGINT,sigint); /* reset signal */
printf("CHILD: I have received a SIGINT\n");
}
void sigquit()
{
printf("My DADDY has Killed me!!!\n");
exit(0);
}
19
sigaction.

X/Open specification recommends a newer
programming interface for signals that is more
robust
20
sigaction structure



If the argument act is not a null pointer, it points to a structure
specifying the action to be associated with the specified signal
The sigaction structure, used to define the actions to be taken on
receipt of the signal specified by sig, is defined in signal.h and has
at least the following members:
If the argument act is a null pointer, signal handling is
unchanged
21
sigaction structure




The sa_handler field of the sigaction structure identifies
the action to be associated with the specified signal.
If the sa_handler field specifies a signal-catching
function, the sa_mask field identifies a set of signals that
will be added to the process' signal mask before the
signal-catching function is invoked.
The SIGKILL and SIGSTOP signals will not be added to
the signal mask using this mechanism; this restriction will
be enforced by the system without causing an error to be
indicated.
The sa_flags field can be used to modify the behaviour of
the specified signal.
22
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! - I got signal %d\n", sig);
}
int main()
{
struct sigaction act;
act.sa_handler = ouch;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
while(1) {
printf("Hello World!\n");
sleep(1);
}
}
23
Signal Sets

The header file signal.h defines the type
sigset_t and functions used to manipulate
sets of signals.
24
Signal Sets
#include <signal.h>
int sigaddset(sigset_t *set, int signo);
DESCRIPTION
The sigaddset() function adds the individual signal
specified by the signo to the signal set pointed to
by set
25
Signal Sets
#include <signal.h>
int sigemptyset(sigset_t *set);
DESCRIPTION
The sigemptyset() function initialises the signal set
pointed to by set, such that all signals defined in
this document are excluded.
26
Signal Sets
#include <signal.h>
int sigfillset(sigset_t *set);
DESCRIPTION
The sigfillset() function initialises the signal set
pointed to by set, such that all signals defined in
this document are included
27
Signal Sets
include <signal.h>
int sigdelset(sigset_t *set, int signo);
DESCRIPTION
The sigdelset() function deletes the individual signal
specified by signo from the signal set pointed to
by set.
28
sigismember

The function sigismember determines whether
the given signal is amember of a signal set.
29
example 6
/* signaldef.c This program binds the signal SIGCLD to a handler sig_cld, then it loops ten times. In each
iteration it creates a child and pauses. The handler is called when the child terminates. It collects and prints out
information about the defunct chil`d. Notice that it is implemented as a loop because multiple SIGCLD
signals may result in a single signal event. */
#include <signal.h>
#include <wait.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
typedef void Sigfunc(int);
/* Sigfunc is type of function with one int arg, and void return */
Sigfunc * signal(int signo, Sigfunc *func)
{ struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_RESTART
if (signo != SIGALRM)
act.sa_flags |= SA_RESTART;
#endif
if (sigaction(signo, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
30
static void sig_cld();
int main()
{
pid_t
pid;
int i;
if (signal(SIGCLD, sig_cld) == SIG_ERR) {
printf("signal error\n");
exit(1);}
for (i=0; i < 10; i++){
if ( (pid = fork()) < 0) {
printf("fork error\n");
exit(1);
}
else if (pid == 0) {
/* child */
sleep(2);
exit(0);
}
pause(); /* parent */
}
exit(0);
}
static void sig_cld()
{
pid_t
pid;
int
status;
printf("SIGCLD received, ");
while ( (pid = waitpid(-1, &status, WNOHANG)) > 0){
printf("child pid = %d terminated\n", pid);
}
printf ("Returning from handler\n");
return;
31