alternate stacks for signal handlers
Henry Cejtin
henry@sourcelight.com
Fri, 21 Jul 2000 20:25:19 -0500
Ok, here is the story with signal stacks.
First, you must allocate a chunk of memory to be used as the signal stack.
It's size must be at least MINSIGSTKSZ, and really should be atleast SIGSTKSG
(these are defined by including signal.h, and the latter is 8K). (Actually,
I would make it 2 or 3 times that just to be safe against multiple signals
coming in really fast.) Note, for protection against overflowing the signal
stack (not really a problem for us, but we should be safe) you should use the
mmap trick to surround it with regions mapped with no permissions. Note, the
Intel stack grows by decreasing, so the most important boundary is on the low
side.
You now have to execute a system call to indicate that the alternate stack
should be used. Ths system call is sigaltstack() and it takes 2 arguments.
The second one is how it returns the current state, and NULL is fine. The
first is a pointer to a `stack_t', which is a typedef'd struct having the
following members:
ss_sp base address of signal stack
ss_size size of signal stack
ss_flags 0
Next, in every call to sigaction you should set the sa_flags member of the
struct sigaction to
SA_RESTART | SA_ONSTACK
The SA_RESTART makes sure that any system call going on when the signal is
delivered will be restarted (instead of returning failure with errno EINTR).
The SA_ONSTACK is the flag that says to use the signal stack.
With this in place, there should be no problem with interrupts. When an
interrupt happens, if the stack pointer does NOT point into the alternate
stack, it will be set to point there. Then all the registers (including the
original stack pointer) will be saved on that stack and the process will
start running the signal handler code.
Note, if a signal comes in after sigaction has been called with SA_ONSTACK in
the sa_flags member and before sigaltstack() has been called, the process
will get a SIGSEGV, so the moral is call sigaltstack() first.