applications programming. By default, on receiving the "bus error" or the "segmentation fault" signal,
a process will dump core and terminate; but you can impose some different action by setting up a
signal handler for these signals.
Signals were modeled on hardware interrupts. Interrupt programming is hard because things happen
asynchronously (at unpredictable times); therefore, signal programming and debugging is hard. You
can glean more information by reading the manpage for signal, and looking at the include file
/usr/include/sys/signal.h.
Programming Challenge
Catching Signals on the PC
Signal handling functions are a part of ANSI C now, and they apply equally to PCs as well
as UNIX. For example, a PC programmer can use the signal() function to catch Ctrl-Break
and prevent a user breaking out of the program.
Write a signal handler to catch the INT 1B (Ctrl-Break) signal on a PC. Have it print a user-
friendly message, but not exit.
If you use UNIX, write a signal handler, so that on receiving a control-C (control-C is
passed to a UNIX process as a SIGINT signal) the program restarts, rather than quits. The
typedefs that will help you define a signal handler are shown in Chapter 3 on declarations.
The header file <signal.h> needs to be included in any source file that uses signals.
The "core dump" part of the message is just a throwback to the days when all memory was made of
ferrite rings, or "cores". Semiconductor memory has been the rule for 15 years or more, but "core"
persists as a synonym for "main memory".
Bus Error
In practice, a bus error is almost always caused by a misaligned read or write. It's called a bus error,
because the address bus is the component that chokes if a misaligned load or store is requested.
Alignment means that data items can only be stored at an address that is a multiple of their size. On
modern architectures, especially RISC architectures, data alignment is required because the extra logic
associated with arbitrary alignment makes the whole memory system much larger and slower. By
forcing each individual memory access to remain in one cache line or on a single page, we greatly
simplify (and therefore speed up) hardware like cache controllers and memory management units.
The way we express the "no data item may span a page or cache boundary" rule is somewhat indirect,
in that we state it in terms of address alignment rather than a prohibition on crossing page boundaries,
but it comes down to the same thing. For example, accesses to an 8-byte double are only permitted at
addresses that are an exact multiple of 8 bytes. So a double can be stored at address 24, address 8008,