170 likes | 296 Views
4061 Session 15 (3/6). Today. More about signals A (relevant) aside Quiz review. Today’s Objectives. Give an example of how signals might be used in a real-world application Identify reentrant and non-reentrant code
E N D
Today • More about signals • A (relevant) aside • Quiz review
Today’s Objectives • Give an example of how signals might be used in a real-world application • Identify reentrant and non-reentrant code • Give examples of functions that are safe and not safe to use in a signal handler • State what happens when system calls are interrupted by signals
Admin • Homework 2 • Homework 3 • Quiz 3
Signals Case Study: Apache • Apache httpd is web server software • It is designed to maximize such things as uptime and efficiency • It has a parent thread which coordinates activity, and several (or many) children which handle web requests
Signals Case Study: Apache • Httpd comes with a shell script that makes it easy to start, stop, and restart the server • Uses signals to deliver messages to the parent • TERM: stop now • USR1: graceful restart • HUP: restart • What happens with kill -9 <httpdpid>? • http://httpd.apache.org/docs/2.0/stopping.html
Another Signals Use Case • Implement a “quality feedback agent” for a piece of software • After the software crashes, or is forced shut, the next time it’s run, it asks to send an email to its developers
Interrupted Operations • What happens when a signal interrupts a system call? • It depends! • “Fast” system calls are not • “Slow” system calls are interrupted, and so are I/O ops (read/write)
Slow Calls • Slow system calls can block for a long time, or forever. These include: • Reads and writes that can block indefinitely (e.g. pipe) • Opens that can block indefinitely (e.g. fifo) • pause() and wait()
Interrupted Slow Calls • Operations that can be interrupted include EINTR among their error returns. • For most I/O operations, only "slow" devices will ever be interrupted. • If an operation returns , it is guaranteed not to be partially completed. • On Linux, but not on Solaris, the default behavior is to automatically retry interrupted operations. • If you use sigaction(), you can set the SA_RESTART flag to enforce this behavior.
Revisiting Read/Write • Recall: these functions are not guaranteed to read or write the amount specified • One reason (among several) is that they may be preempted by a system call • If these functions return -1, you should check errno for EINTR • This indicates a signal interrupted the call before it read or wrote any data
Revisiting Read/Write • Some systems automatically restart system calls (BSD >=4.2, linux, mac os) • Some do not (solaris) • What’s the difference? • Can be overridden (either way) using a flag in sigaction
int g_var = 1; int f() { g_var = g_var + 2; return g_var; } int g() { return f() + 2; } int f(int i) { int priv = i; priv = priv + 2; return priv; } int g(int i) { int priv = i; return f(priv) + 2; } Reentrant Code Example from: http://en.wikipedia.org/wiki/Reentrant
Make me reentrant • Why is this code non-reentrant? • Make me reentrant. char *strToUpper(char *str) { static char buffer[STRING_SIZE_LIMIT]; int index; for (index = 0; str[index]; index++) buffer[index] = toupper(str[index]); buffer[index] = '\0'; return buffer; }
Signal Handler Safety • What can you "safely" do inside a signal handler? • Remember that any function you use in a signal handler could also be in use in your program when the signal arrives
Malloc and free • Malloc and free are non-reentrant • Why? • As part of allocating and freeing memory, the process must track the parts of its address space that are free and occupied • One common way to do so is to use a linked list to track allocated regions of the heap • Doom: • We’re in the middle of a malloc • We’re interrupted by a signal • The signal handler calls malloc
Safe Calls in Signal Handlers • Reentrant functions and “atomic” signal handlers • The UNIX spec lists 118 functions that are reentrant, and thus safe to use in signal handers • read/write • stat • open • wait • ...