Chapter08-Exceptional_Control_Flow(2)Signals
Chapter08-Exceptional_Control_Flow(2)Signals
SYSTEMS PROGRAMMING
[0]
init [1]
Daemon …
e.g. httpd Login shell Login shell
oShell
oSignals
oNonlogical Jumps (skipped)
/* evaluate */
eval(cmdline);
}
}
Computer Systems: A Programmer’s Perspective 3rd Edition 5
SIMPLE SHELL EVAL FUNCTION
o Our example shell correctly waits for and reaps foreground jobs
void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = fork()) == 0) { /* Child runs user job */
if (execve(argv[0], argv, environ) < 0) {
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
}
}
} not terminate
/* Parent waits for foreground job to terminate */
if (!bg) {
Will create a memory leak
int status;
if (waitpid(pid, &status, 0) < 0)
that could run the kernel out
unix_error("waitfg: waitpid error");
} of memory
else
printf("%d %s", pid, cmdline);
}
return;
}
Computer Systems: A Programmer’s Perspective 3rd Edition 7
SOLUTION?
Background Background
process group 32 process group 40
Child Child
• getpgrp()
pid=21 pid=22
pgid=20 pgid=20 Return process group of current process
Foreground • setpgid()
process group 20 Change process group of a process (see
text for details)
Computer Systems: A Programmer’s Perspective 3rd Edition 15
SENDING SIGNALS WITH /BIN/KILL PROGRAM
pid=21 pid=22
pgid=20 pgid=20
Foreground
process group 20
Computer Systems: A Programmer’s Perspective 3rd Edition 18
EXAMPLE: CTRL-C AND CTRL-Z
linux> ./forks 17 STAT (process state) Legend:
Child: pid=28108 pgrp=28107
Parent: pid=28107 pgrp=28107 First letter:
<types ctrl-z>
S: sleeping
Suspended
linux> ps w T: stopped
PID TTY STAT TIME COMMAND R: running
27699 pts/8 Ss 0:00 -tcsh
28107 pts/8 T 0:01 ./forks 17 Second letter:
28108 pts/8 T 0:01 ./forks 17 s: session leader
28109 pts/8 R+ 0:00 ps w +: foreground proc group
linux> fg
./forks 17
See “man ps” for more
<types ctrl-c>
linux> ps w details
PID TTY STAT TIME COMMAND
27699 pts/8 Ss 0:00 -tcsh
28110 pts/8 R+ 0:00 ps w
Process A Process B
user code
kernel code context switch
Time
user code
kernel code context switch
user code
int main()
{
/* Install the SIGINT handler */
if (signal(SIGINT, sigint_handler) == SIG_ERR)
unix_error("signal error");
return 0;
}
Computer Systems: A Programmer’s Perspective 3rd Edition 25
SIGNALS HANDLERS AS CONCURRENT FLOWS
Process A Process B
Sigemptyset(&mask);
Sigaddset(&mask, SIGINT);
oUse the reentrant SIO (Safe I/O library) from csapp.c in your
handlers.
• ssize_t sio_puts(char s[]) /* Put string */
• ssize_t sio_putl(long v) /* Put long */
• void sio_error(char s[]) /* Put msg & exit */
void sigint_handler(int sig) /* Safe SIGINT handler */
{
Sio_puts("So you think you can stop the bomb with ctrl-c, do you?\n");
sleep(2);
Sio_puts("Well...");
sleep(1);
Sio_puts("OK. :-)\n");
_exit(0);
}
action.sa_handler = handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
Sigfillset(&mask_all);
Signal(SIGCHLD, handler);
initjobs(); /* Initialize the job list */
while (1) {
if ((pid = Fork()) == 0) { /* Child */
Execve("/bin/date", argv, NULL);
}
Sigprocmask(SIG_BLOCK, &mask_all, &prev_all); /* Parent */
addjob(pid); /* Add the child to the job list */
Sigprocmask(SIG_SETMASK, &prev_all, NULL);
}
exit(0);
}
Sigfillset(&mask_all);
while ((pid = waitpid(-1, NULL, 0)) > 0) { /* Reap child */
Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
deletejob(pid); /* Delete the child from the job list */
Sigprocmask(SIG_SETMASK, &prev_all, NULL);
}
if (errno != ECHILD)
Sio_error("waitpid error");
errno = olderrno;
}
Sigfillset(&mask_all);
Sigemptyset(&mask_one);
Sigaddset(&mask_one, SIGCHLD);
Signal(SIGCHLD, handler);
initjobs(); /* Initialize the job list */
while (1) {
Sigprocmask(SIG_BLOCK, &mask_one, &prev_one); /* Block SIGCHLD */
if ((pid = Fork()) == 0) { /* Child process */
Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */
Execve("/bin/date", argv, NULL);
}
Sigprocmask(SIG_BLOCK, &mask_all, NULL); /* Parent process */
addjob(pid); /* Add the child to the job list */
Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */
}
exit(0);
}
Computer Systems: A Programmer’s Perspective 3rd Edition 40
EXPLICITLY WAITING FOR SIGNALS
void sigchld_handler(int s)
{
int olderrno = errno;
pid = Waitpid(-1, NULL, 0); /* Main is waiting for nonzero pid */
errno = olderrno;
}
void sigint_handler(int s)
{
}
while (1) {
Sigprocmask(SIG_BLOCK, &mask, &prev); /* Block SIGCHLD */
if (Fork() == 0) /* Child */
exit(0);
/* Parent */
pid = 0;
Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock SIGCHLD */
oSolution: sigsuspend
int sigsuspend(const sigset_t *mask)
• Equivalent to atomic (uninterruptable) version of:
sigprocmask(SIG_BLOCK, &mask, &prev);
pause();
sigprocmask(SIG_SETMASK, &prev, NULL);
while (1) {
Sigprocmask(SIG_BLOCK, &mask, &prev); /* Block SIGCHLD */
if (Fork() == 0) /* Child */
exit(0);
void bar(void)
{
if (error2)
longjmp(buf, 2);
}
int error1 = 0;
int error2 = 1;
int main()
{
switch(setjmp(buf)) {
case 0:
foo();
break;
case 1:
printf("Detected an error1 condition in foo\n");
break;
case 2:
printf("Detected an error2 condition in foo\n");
break;
default:
printf("Unknown error condition in foo\n");
}
exit(0);
}
Computer Systems: A Programmer’s Perspective 3rd Edition 49
LIMITATIONS OF NONLOGICAL JUMPS
sigjmp_buf buf;
int main()
{ linux> ./restart
if (!sigsetjmp(buf, 1)) { starting
Signal(SIGINT, handler); processing...
Sio_puts("starting\n"); processing...
} processing...
else restarting
Sio_puts("restarting\n"); Ctrl-c
processing...
while(1) { processing...
Sleep(1); restarting Ctrl-c
Sio_puts("processing...\n"); processing...
} processing...
exit(0); /* Control never reaches here */ processing...
}
Computer Systems: A Programmer’s Perspective 3rd Edition 52
SUMMARY