Practical Session 2

advertisement
Operating Systems, 142
Practical Session 2,
Signals and Assignment 1
1
Signals
• Signals are a way of sending simple messages
to processes/ threads.
• Used to notify a process of important events.
• Signals can be sent by other processes/
threads, or by the kernel.
• Signals are defined in POSIX.
• Signals can be found in Linux but not in XV6,
you can add them yourself!
2
Reacting to Signals
• Signals are processed (by the kernel) after a
process finished running in kernel mode, just
before returning to user mode:
– Upon returning from a system call.
– Upon returning from a timer interrupt (interrupt
sent by the hardware clock).
3
Signals: Synchronous VS. Asynchronous
• Programs are synchronous: executed line by line
• Signals can be synchronous or asynchronous
– Synchronous: occur as a direct result of the executing
instruction stream. Examples: dividing by zero,
segmentation fault, etc.
– Asynchronous: external to (and in some cases
unrelated to) the current execution context. A
mechanism for an inter-process communication.
Example: receiving a termination signal from a
different process.
4
Signals-Examples
•
•
•
•
SIGSEGV – Segmentation Faults
SIGFPE – Floating Point Error
SIGSTOP – Causes process to suspend itself
SIGCONT – Causes a suspended process to
resume execution
Which are synchronous?
 A list of signals in Linux: http://www.ucs.cam.ac.uk/docs/course-notes/unixcourses/Building/files/signals.pdf
5
Signal Table
• Each process has a signal table
• Each signal has an entry in the table
• Each signal has an indicator whether to ignore
the signal or not (SIG_IGN)
• Each signal has a column of what to do upon
receiving the signal (if not ignoring it)
Sig_Num
1
2
6
SIG_IGN
Handler
Blocking and Ignoring
• Blocking: The signal is not delivered to the
process. It remains pending until the block is
removed.
• Ignoring: The signal is discarded by the kernel
without any action being taken. The execution
of the process continues even if nonmeaningful (i.e. ignoring SIGFPE or SIGSEGV).
 According to POSIX, the behavior of a process is undefined after it ignores
a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill or raise.
7
Signal Handlers
• Each signal has a default action. For example:
– SIGTERM – Terminate process.
– SIGFPE (floating point exception) – dump core and
exit.
• The default action can be changed by the process
using the signal*/ sigaction system call.
 It is highly recommended to refrain from using the signal call in your code, as we
will see later. Nonetheless it is important to be familiar with it since it appears in
many legacy programs.
8
Signal Handlers
• Five default actions:
– Ignore: ignores the signal; no action taken.
– Exit: forces the process to exit.
– Core: forces the process to exit and create a core file.
– Stop: stops the process.
– Continue: resume execution of a stopped process.
 Some functions are not safe to call from within a signal handler, such as printf,
malloc, etc. A useful technique to overcome this is to use a signal handler to set a
flag and then check that flag from the main program and print a message if
required. Further reading: http://www.ibm.com/developerworks/linux/library/lreent/index.html
9
Signal Handlers
• Two signals cannot be ignored or have their
associated action changed:
– SIGKILL
– SIGSTOP
(Don’t confuse with SIGTSTP, which is sent when a user ^z in
the shell. The default actions of both signals are similar, but
the latter can be modified).
• When calling execvp() all signals are set to their
default action. The bit that specifies whether to
ignore the signal or not is preserved. Why?
10
Scheme of signal processing
User Mode
Normal
program
flow
Kernel Mode
An event which traps to kernel
do_signal()
handle_signal()
setup_frame()
Signal
handler
Return
code on
the stack
11
system_call()
sys_sigreturn()
restore_sigcontext()
Sending Signals
• Signals can be sent:
– From the keyboard
– From the command line via the shell
– Using system calls
12
Keyboard Signals
• Ctrl–C – Sends a SIGINT signal . By default this
causes the process to terminate.
• Ctrl-\ - Sends a SIGQUIT signal. Causes the
process to terminate.
• Ctrl-Z – Sends a SIGTSTP signal. By default this
causes the process to suspend execution.
 Note: not all keyboard signals are supported in all shells.
13
Command line Signals
• kill <signal> <PID> – Sends the specified signal to
the specified PID. A Negative PID specifies a whole
process group.
– Kill -9 <PID> sends a SIGKILL which terminates the
process.
• killall <args> <commands> – can be used to send
multiple signals to all processes running specific
commands.
– Example: killall -9 java
• fg – Resumes the execution of a suspended process
(sends a SIGCONT).
14
System call Signals
Kill(pid_t pid,int sig)
Usage example:
#include <unistd.h>
/* standard unix functions, like getpid() */
#include <sys/types.h> /* various type definitions, like pid_t */
#include <signal.h>
/* signal name macros, and the kill() prototype */
/* first, find my own process ID */
pid_t my_pid = getpid();
/* now that I got my PID, send myself the STOP signal. */
kill(my_pid, SIGSTOP);
15
Signal Priority
• Each pending signal is marked by a bit in a 32 bit word.
• Therefore there can only be one signal pending of each
type.
• A process can’t know which signal came first.
• The process executes the signals starting at the lowest
numbered signal.
• POSIX 2001 also defines a set of Real-Time Signals which
behave differently:
–
–
–
–
16
Multiple instances may be queued
Provide richer information (may be accompanied by an integer)
Delivered in guaranteed order
Use SIGRTMIN+n up to SIGRTMAX to refer to these signals (32 in
Linux)
Manipulation of Signals
sighandler_t signal(int signum, sighandler_t handler)
• Registers a new signal handler for the signal with number
signum.
• The signal handler is set to sighandler which may be a user
specified function, or either SIG_IGN or SIG_DFL.
• If the corresponding handler is set to SIG_IGN or SIG_DFL,
then the signal is ignored or set do default action accordingly.
• Return Value: previous value of the signal handler,
or SIG_ERR on error.
• Deprecated, do not use!
17
Manipulation of Signals
• On some systems (e.g. System V Unix), if the handler is set to a function
sighandler and a signal is received, then first the handler is reset to
SIG_DFL, and next sighandler is called.
• This may result in portability issues, or unwanted signal handling.
• One solution to this problem is demonstrated in the “ouch” signal handler
function:
void ouch(int sig)
{
printf(“OUCH! - I got signal %d\n”, sig);
signal(SIGINT, ouch);
}
• What is the problem with this solution?
18
Manipulation of Signals- sigaction
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
• A more sophisticated (and safe) way of manipulating signals.
• Doesn’t restore (by default) the signal handler to default
when delivering a signal.
• signum is the number of the signal.
• act is a pointer to a struct containing much information
including the new signal handler.
• oldact if not null will receive the old signal handler.
For more details and another example see:
http://www.opengroup.org/onlinepubs/009695399/functions/sigaction.html
Example
19
Manipulation of Signals- sigaction
The sigaction structure is defined as something like:
struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
• sa_handler specifies the action to be associated with signum and
may be SIG_DFL, SIG_IGN, or a pointer to a signal handling
function.
• sa_mask specifies a mask of signals which should be blocked during
execution of the signal handler. In addition, the signal which
triggered the handler will be blocked, unless the SA_NODEFER flag
is used.
• sa_flags specifies a set of flags which modify the behavior of the
signal.
20
Manipulation of Signals- sigprocmask
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
The sigprocmask call is used to change the list of
currently blocked signals. The behaviour of the call is
dependent on the value of how, as follows:
– SIG_BLOCK The set of blocked signals is the union of the
current set and the set argument.
– SIG_UNBLOCK The signals in set are removed from the
current set of blocked signals. It is legal to attempt to
unblock a signal which is not blocked.
– SIG_SETMASK The set of blocked signals is set to the
argument set.
21
Manipulation of Signals- sigprocmask
• sigset_t is a basic data structure used to
represent a signal set.
• Initialization of sigset_t should be done using:
sigemptyset, sigfillset, sigaddset, …
• A variable of type sigset_t should not be
manipulated manually (for portability)!
• An example of usage can be found at:
http://www.linuxprogrammingblog.com/code-examples/blocking-signals-withsigprocmask
Example
22
Manipulation of Signals- sigpending
int sigpending(sigset_t *set);
Returns the set of signals that are pending for
delivery to the calling thread (i.e., the signals
which have been raised while blocked). The
mask of pending signals is returned in set.
23
Waiting for signals
int pause(void);
Causes the calling process (or thread) to sleep until a (any) signal is
delivered that either terminates the process or causes the invocation
of a signal-catching function.
int sigsuspend(const sigset_t *mask);
Temporarily replaces the signal mask of the process, and suspends the
process until a signal not belonging to the waiting mask arrives.
Allows waiting for a particular signal.
24
The system call alarm
unsigned alarm(unsigned seconds);
Requests the system to generate a SIGALRM for the process
after seconds time have elapsed. Processor scheduling delays
may prevent the process from handling the signal as soon as it
is generated.
• If seconds is 0, a pending alarm request, if any, is canceled.
• Alarm requests are not stacked; only one SIGALRM
generation can be scheduled in this manner. If the
SIGALRM signal has not yet been generated, the call shall
result in rescheduling the time at which the SIGALRM signal
is generated.
25
Example 1
#include <stdio.h>
/* standard I/O functions */
#include <unistd.h>
/* standard unix functions, like getpid() */
#include <sys/types.h> /* various type definitions, like pid_t*/
#include <signal.h>
/* signal name macros, and the signal() prototype */
/* first, here is the signal handler */
void catch_int(int sig_num){
/* reassign the signal handler again to catch_int, for next time */
signal(SIGINT, catch_int);
/* and print the message */
printf("Don't do that\n");
}
int main(){
/* set the INT (Ctrl-C) signal handler to 'catch_int' */
signal(SIGINT, catch_int);
/* now, lets get into an infinite loop of doing nothing */
Causes the process to halt
while (true) {
execution until it receives
pause();
any signal.
}
}
26
Example 2
int cpid[5];
int j;
// holds the pids of the children
// index to cpid
// function to activate when a signal is caught
int sigCatcher() {
signal(SIGINT, sigCatcher); // re-assign the signal catcher
printf("PID %d caught one\n", getpid());
if(j > -1)
kill(cpid[j], SIGINT); // send signal to next child in cpid
}
27
Example 2-Continued
int main() {
int i;
int zombie;
int status;
int pid;
signal(SIGINT, sigCatcher); // sets a handler for INT signal
…
28
Example 2-Continued
for(i=0; i<5; i++){
if((pid=fork()) == 0){
printf("PID %d ready\n", getpid());
j = i-1;
pause();
exit(0);
}
else
cpid[i] = pid;
}
sleep(2);
kill(cpid[4], SIGINT);
sleep(2);
for(i=0; i<5; i++){
zombie = wait(&status);
printf("%d is dead\n", zombie);
}
exit(0);
}
29
// create new child
// wait for signal
// end process (become a zombie)
// Only father updates the cpid array.
// allow children time to enter pause
// send signal to first child
// wait for children to become zombies
// collect zombies
Output
PID 22899 ready
PID 22900 ready
PID 22901 ready
PID 22902 ready
PID 22903 ready
PID 22903 caught one
PID 22902 caught one
PID 22901 caught one
PID 22900 caught one
PID 22899 caught one
22903 is dead
22901 is dead
22902 is dead
22899 is dead
22900 is dead
30
Security Issues
• Not all processes can send signals to all
processes.
• Only the kernel and super user can send
signals to all processes.
• Normal processes can only send signals to
processes owned by the same user.
31
Process ID and Group ID
• Each process has an ID (pid).
• A process group is a collection of related
processes.
• Each process has a process-group identifier (pgid).
• One process in the group is the group leader and
all member’s group ID is equal to the leaders pid.
The group leader is the process group's initial
member.
• A signal can be sent to a single process or to a
process group.
• Used by the shell to control different tasks
executed by it.
32
Process Group ID
int getpid() – return the process’s PID.
int getpgrp() – return the process’s PGID.
setpgrp() – set this process’s PGID to be equal to
his PID.
setpgrp(int pid1, int pid2) – set process’s pid1
PGID to be equal to pid2’s PID.
33
MIDTERM QUESTION (APPENDIX)
34
‫‪Question from midterm 2004‬‬
‫תלמיד קיבל משימה לכתוב תכנית שמטרתה להריץ תכנית נתונה‬
‫(ברשותו רק הקובץ הבינארי) ‪ prompt‬ע"י שימוש ב‪ fork -‬ו‪.execvp-‬‬
‫בנוסף נדרש התלמיד למנוע מן המשתמש "להרוג" את התכנית ע"י‬
‫הקשת ‪( ctrl-c‬שים לב כי התכנית ‪ prompt‬אינה מסתיימת לעולם)‪.‬‬
‫מצורף פתרון שהוצע ע"י התלמיד )‪ (my_prog.c‬וכן התכנית ‪. prompt‬‬
‫א‪ -‬תאר במדויק את פלט התכנית כאשר הקלט הנו‪:‬‬
‫‪Good luck in the ^c midterm exam.‬‬
‫ב‪ -‬האם הפתרון המוצע עונה על הגדרת התרגיל?‬
‫ג‪ -‬אם תשובתך ל‪-‬ב' היא לא‪ ,‬כיצד היית משנה את התכנית‬
‫‪( my_prog.c‬ניתן להוסיף‪ /‬לשנות שורה או שתיים בקוד לכל‬
‫היותר)?‬
‫‪35‬‬
Question from midterm 2004
#include…
void cntl_c_handler(int dummy){
signal(SIGINT, cntl_c_handler);
}
main (int argc, char **argv){
int waited;
int stat;
argv[0] = “prompt”;
signal (SIGINT, cntl_c_handler);
if (fork() == 0) { // son
execvp(“prompt”,argv[0]);
}
else { // father
waited = wait(&stat);
printf(“My son (%d) has terminated \n”,waited);
}
}
36
my_prog.c
Question from midterm 2004
main(int argc, char** argv){
char buf[20];
while(1) {
printf(“Type something: “);
gets(buf);
printf(“\nYou typed: %s\n”,buf);
}
}
37
prompt.c
‫(זכרו כי קוד זה אינו ניתן‬
)‫לשינוי ע"י התלמיד‬
Sample execution of code
:‫ תאר במדויק את פלט התכנית כאשר הקלט הנו‬-‫א‬
Good luck in the ^c midterm exam.
Type something: Good luck
You typed: Good luck
Type something: in the ^c
My son 139 has terminated
38
Code is incorrect
?‫האם הפתרון המוצע עונה על הגדרת התרגיל‬
• Execvp doesn’t preserve signal handlers.
• Therefore prompt.c doesn’t ignore ^c.
• This means that the process can be
terminated.
39
Code correction
‫ כיצד היית משנה את התכנית‬,‫ב' היא לא‬-‫אם תשובתך ל‬
‫ לשנות שורה או שתיים בקוד לכל‬/‫ (ניתן להוסיף‬my_prog.c
?)‫היותר‬
1. Change
signal (SIGINT, cntl_c_handler); in my_prog.c
With
signal (SIGINT, SIG_IGN);
2. Add
if (fork()==0){
signal (SIGINT, SIG_IGN);
execvp(“prompt”,argv[0]);
40
Question from midterm 2012
:‫נתון קטע הקוד הבא‬
void sigchld_handler(int s) {
printf(“S”);
}
int main(){
signal(SIGCHLD, sigchld_handler);
signal_block(SIGCHLD);
if (fork() != 0) {
printf(“A”);
signal_unblock(SIGCHLD);
printf(“B”);
wait ();
printf(“C”);
}
else {
printf(“D”);
}
}
41
‫‪Question from midterm 2012‬‬
‫• ידוע כי הפקודות ‪ signal_block‬וכן ‪signal_unblock‬‬
‫חוסמות ומשחררות חסימה לסיגנלים‪.‬‬
‫• שרטטו גרף מכוון המתאר את הפלטים האפשריים‬
‫לקוד זה‪ .‬כל צומת בגרף תסמל הדפסה וכל קשת‬
‫מכוונת תייצג יחס סדר מתחייב בין הדפסות‪.‬‬
‫• לדוגמא‪ ,‬אם עפ"י קוד מסוים ידוע כי יודפסו ‪ Y ,X‬ו – ‪Z‬‬
‫וכי ההדפסה של ‪ X‬תופיע בהכרח לפני ההדפסה של ‪Y‬‬
‫(אך ‪ Z‬יכול להופיע לפני או אחרי כל אחת מן ההדפסות‬
‫האחרות)‪ ,‬יתקבל הגרף הבא‪:‬‬
‫‪Z‬‬
‫‪Y‬‬
‫‪X‬‬
‫‪42‬‬
Question from midterm 2012
:‫הגרף שיתקבל מהקוד‬
void sigchld_handler(int s) {
printf(“S”);
}
int main(){
signal(SIGCHLD, sigchld_handler);
signal_block(SIGCHLD);
if (fork() != 0) {
printf(“A”);
signal_unblock(SIGCHLD);
printf(“B”);
wait ();
printf(“C”);
}
else {
printf(“D”);
}
}
43
A
D
B
S
C
More Information
•
•
•
•
•
•
•
44
http://www.linuxjournal.com/article/3985
http://www.linux-security.cn/ebooks/ulk3-html/0596005652/understandlk-CHP-11.html
http://cs-pub.bu.edu/fac/richwest/cs591_w1/notes/wk3_pt2.PDF
http://books.google.com/books?id=9yIEji1UheIC&pg=PA156&lpg=PA156&dq=linux+ret_from
_intr()&source=bl&ots=JCjEvqiVM&sig=z8CtaNgkFpa1MPQaCWjJuU5tq4g&hl=en&ei=zf3zSZsvjJOwBsUxYkB&sa=X&oi=book_result&ct=result&resnum=22#PPA159,M1
man signal, sigaction…
man kill…
Process groups:
http://www.win.tue.nl/~aeb/linux/lk/lk-10.html
http://www.informit.com/articles/article.aspx?p=366888&seqNum=8
CODE EXAMPLES
45
sigaction code example
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
sig_atomic_t sigusr1_count = 0;
void handler (int signal_number){
++sigusr1_count;
}
int main (int argc, char ** argv){
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &handler;
sigaction (SIGUSR1, &sa, NULL);
/* Do some lengthy stuff here. */
/* ... */
printf (“SIGUSR1 was raised %d times\n”, sigusr1_count);
return 0;
}
46
Back
sigprocmask code example
/** This program blocks SIGTERM signal for 10 seconds using sigprocmask(2) * After that
the signal is unblocked and the queued signal is handled. */
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static int got_signal = 0;
static void hdl (int sig) {
got_signal = 1;
}
int main (int argc, char *argv[]) {
sigset_t mask;
sigset_t orig_mask;
struct sigaction act;
memset (&act, 0, sizeof(act));
act.sa_handler = hdl;
47
sigprocmask code example
if (sigaction(SIGTERM, &act, 0)) {
perror ("sigaction");
return 1;
}
sigemptyset (&mask);
sigaddset (&mask, SIGTERM);
if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) {
perror ("sigprocmask");
return 1;
}
sleep (10);
if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) {
perror ("sigprocmask");
return 1;
}
sleep (1);
if (got_signal) puts ("Got signal");
return 0; }
48
Back
Download