signal: a notification of an event to the target process
ex1.c:
void main(){
for(;;);
}
^c
will kill this process. When the user presses ^c
, the system sends a signal (SIGINT: signal number 2) to the current running process. If the process didnβt prepare for this signal, it dies.
ex2.c:
#include <stdio.h>
#include <signal.h>
void foo(int signum){
printf("I am ok\n");
}
void main(){
signal(2, foo); // prepare for signal number 2. same as signal(SIGINT, foo)
for(;;);
}
signal(SIGINT, foo)
means βdonβt kill me when SIGINT
arrives, run foo()
insteadβ.
Refer β/usr/include/bits/signum.hβ for signal numbers and signal names. | signal number | signal name | when this signal is raised | whom this signal is sent to | default action | | ββββ- | ββββ | ββββββββββββββββββββββ | βββββββββββββββ | βββββββ- | | 1 | SIGHUP | a session leader with a controlling terminal(e.g. shell) is killed | all foreground child processes of this leader | kill | | 2 | SIGINT | ^c | foreground process | kill | | β¦.. | | | | | | 9 | SIGKILL | kill -9 1234 | pid 1234 | kill with no exception | | β¦β¦. | | | | | | 11 | SIGSEGV | illegal access of memory | the process who accessed illegal memory area | kill | | β¦.. | | | | | | 15 | SIGTERM | kill 1234 | pid 1234 | kill | | β¦ | | | | | | 17 | SIGCHLD | child process is killed | the parent process | ignore | | β¦β¦β¦ | | | | | | 20 | SIGTSTP | ^z | the currrent process | suspend | | 31 | SIGSYS | bad system call | the process who called the system call | kill |
kill
command, kill()
system callkill
is a command to send a signal (it is not a command to βkillβ a program!)
kill -12 1234
will send βsignal 12β to βprocess 1234β. If the signal number is not specified signal 15 is sent. Thus
kill 1234
is same as
kill -15 1234
And if process 1234 didnβt prepare for signal number 15, it will βkillβ the process. If process 1234 did prepare for signal 15, it cannot βkillβ the process.
A program can call kill()
to send a signal.
kill(1234, 15);
will send signal 15 to process 1234.
signal x
is raised ==>
signal x
is sent to the target process ==>
if the target process has prepared for this signal
the prepared function is executed
and go back to the location where the signal is happened
otherwise
do the default action
ex1 is running ==>
^c
is pressed ==>
signal 2 (SIGINT) is raised ==>
signal 2 is sent to ex1 ==>
ex1 is killed
ex2 is running ==>
^c
is pressed ==>
signal 2 (SIGINT) is raised ==>
signal 2 is sent to ex2 ==>
foo()
is executed ==>
go back to for(;;);
All program should call exit()
to terminate the program. (In fact, the compiler adds exit()
at the end of all programs in case the programmer forgets).
int main(){
..........
exit(0); // terminate this process and send exit status(0) to the parent
}
Algorithm for exit
:
1. remove the body
2. make the process status "zombie"
3. send SIGCHLD to the parent
4. adopt the children of this process to the init process (pid=1)
(* βinitβ process (pid=1) is one that runs an infinite loop calling wait()
. It removes a zombie process whoever becomes a child of it.)
The parent should call wait()
for each child it has created.
Algorithm for wait
:
if the child is already dead (a zombie)
remove the process descriptor
else
wait until the child is dead
int x, y;
x = wait(&y);
printf("child %d is removed. the exit status was %d\n", x, y);
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
int main(){
int x,y,z;
x=fork();
if (x != 0) exit(0); // kill the parent
setsid(); // become a session leader of a new session and
// lose the controlling terminal. "ps -ejf|grep pid" (pid is the process id of
// this process) will show the PID of this process is same as its SID,
// and it has no terminal. Since it no longer belongs to the original terminal
// it will not get SIGHUP when the original terminal is closed
if (fork() !=0) exit(0); // kill the parent again, so that the child becomes the only
// non-session-leader member in the new session
// prepare for various signals
signal(SIGCHLD,SIG_IGN); /* ignore child */
signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGHUP,signal_handler); /* catch hangup signal */
signal(SIGTERM,signal_handler); /* catch kill signal */
for(;;){
// daemon's code here
...........
}
}
(Do not use ^z
when experimenting with signals. ^z
will stop the process, and the process cannot receive further signals.)
$ ps -ef | grep 12345
where 12345 is your student ID. Suppose ex2βs pid is 334455. Send SIGINT (signal number 2) to ex2 with $ kill -2 334455
What happens? Explain the result.open another terminal
find the pid of ex2, e.g. 1234
kill 1234 (or βkill -15 1234β)
Why SIGINT (signal 2) cannot kill ex2 while SIGTERM (signal 15) can?
#include <stdio.h>
#include <signal.h>
void foo(int signum){
printf("I am ok\n");
}
void main(){
signal(2, foo); // prepare for signal number 2. same as signal(SIGINT, foo)
signal(15, foo);
for(;;);
}
Now compile and run ex2 and try to kill it with SIGINT and SIGTERM in another window. Assume ex2 has pid 334455.
$ kill -2 334455
$ kill -15 334455
Explain the result.
ps βef | grep 1234
(assuming your student id is 1234) in another terminal, close the terminal where ex2 is currently running, and find this pid again with ps βef | grep 1234
in the second window. Explain why ex2 dies in this case.kill -15 parent-pid
) and observe what happens to the children. ..................
x = fork();
if (x==0) for(;;); // first child
else{
y=fork();
if (y==0) for(;;); // second child
}
for(;;); // parent
...........
kill -9 114455
, where 114455 is the pid of the shell. What happens to the three processes (the parent and the two children)? Why the three children die and how can you prevent the three processes from being killed?wait()
since the parent should run its infinite loop too. The parent should prepare a handler for SIGCHLD
signal and call wait()
inside this handler.kill()
to send a signal to a process. enter pid and signal number
1234 15
enter pid and signal number
1122 2
............
Use above program to kill ex2.
&
symbol. In a normal shell, the &
symbol means βgive me prompt without waitingβ.ex) Suppose βinf.cβ is as follows:
int main(){
for(;;){
.............
}
}
If you run βinfβ without &
, the shell will wait until βinfβ finishes.
$ ./inf
- --- shell wait here
But if you run it with &
, the shell runs βinfβ but is ready for next command.
$ ./inf&
$ --- "inf" is running, but you can issue next command