dymm@b.cs.wvu.wvnet.edu (David Dymm) (03/09/89)
I POSTED THIS THE OTHER DAY --- FROM THE MAIL RECEIVED (THANK YOU VERY MUCH), I REALIZE THAT I DID A POOR JOB OF EXPLAINING MYSELF. SO I WILL POST THIS AGAIN WITH A DIFFERENT EXPLANATION: I would like to write an interrupt handling mechanism in 'C' (on BSD 4.2 Unix) to work in the following way: 1) Set up the signal facility: signal (SIGALRM, alarm_handler) 2) Set the alarm: ualarm (100000, 0) <== This will send a signal after 100,0000 microseconds. 3) The interrupt handler "alarm_handler" (a separate function) is called with the signal mechanism when the alarm timer times out. Let's call "location A" the place where we were in the code when we were interrupted by the timer. When "alarm_handler" has finished its local processing, it resets the alarm. At this point, I do NOT want to return control back to where the interrupt occurred!!!! Instead, I want to "longjmp" to a separate "function B" When "function B" has completed its work, I want to return to "location A". 4) However while function "B" is doing its thing, the alarm may again signal an interrupt, causing the above actions to happen again. The longjmp mechanism prevents continually pushing the call to function "B" on the system stack. The question is: How do I return to "location A" ??? I have looked at the "sigstack" mechanism, and also at the definitions for "sigcontext" and "sigstack" in "signal.h". But I do not see how to put this all together to accomplish my task. The system saves the state of the process on the signal stack when "signal" causes control to jump to "alarm_handler". How do I get at that information, AND more importantly, how do I use that information to accomplish my task. --------------------------------------------------------------- The following questions were raised by people who sent me mail: A) Why do a longjump to function "B" --- just call the function ??? If I "call" function "B", the function call gets pushed onto the system stack. The problem is that the above actions ( alarm timeout --> "alarm_handler" --> longjmp to "B" ) can occur a number of times. If I continually call function "B", then the stack will continue to grow. However whether I call "B" or longjmp, this does not help me in returning to location "A" !!! David Dymm Software Engineer USMAIL: Bell Atlantic Knowledge Systems, 145 Fayette Street, Morgantown, WV 26505 PHONE: 304 291-9898 (8:30-4:30 EST) USENET: {allegra,bellcore, cadre,idis,psuvax1}!pitt!wvucsb!dymm INTERNET: dymm@b.cs.wvu.wvnet.edu
djones@megatest.UUCP (Dave Jones) (03/09/89)
The correspondant poses questions such as, "How can I longjmp to B?"
etc.. He was a bit long on describing possible "how"'s, and a bit short on
the "what".
But I think I understand what he wants. I think the real question is,
How do you set up a SIGALRM handler which calls B() in such a way
that B() will be aborted and restarted by a subsequent SIGALRM.
If B() ever finishes, it should resume normal execution, of course.
It's a little tricky. We'll use a volatile flag called "handler_active".
SIGALRM must be blocked when it is either set or inspected.
The idea is that when there is a signal handler active on the stack,
a subsequent signal handler will simply longjmp back to the earlier
one. If there is an activation of B() on the stack when that happens,
the activation of B() will get popped off along with the second
signal-handler activation.
(I've neglected comments and white-space for the sake of net.brevity.)
sigalrm_handler(){
static int handler_active = 0;
static jmp_buf first_handler;
int old_mask;
if(handler_active) longjmp(first_handler, 1);
handler_active = 1;
setjmp(first_handler);
old_mask = sigsetmask(~0);
sigsetmask(old_mask & ~(sigmask(SIGALRM)));
B();
sigsetmask(old_mask);
handler_active = 0;
}
djones@megatest.UUCP (Dave Jones) (03/09/89)
I just realized that I don't have to call
sigsetmask to get the old signal-mask. It's
available in the struct sigcontext:
sigalrm_handler(sig,code,context)
struct sigcontext *scp;
{
static int handler_active = 0;
static jmp_buf first_handler;
int handler_mask;
if(handler_active) longjmp(first_handler, 1);
handler_active = 1;
setjmp(first_handler);
handler_mask = sigsetmask(scp->sc_mask);
B();
sigsetmask(handler_mask);
handler_active = 0;
}