Wednesday, November 26, 2008

Jumping Around

For one of the defects I was working on I came across with longjmp and setjmp.It was a cool method. Setjmp() and longjmp() are usually used so that if an error is detected within a long string of procedure calls, the error may be dealt with gracefully by a high-level call.

#define _JBLEN  9
typedef struct { int _jb[_JBLEN + 1]; } jmp_buf[1];
This is an irritating way of saying that jmp_buf is an array of _JBLEN+1 integers.

So, when you call setjmp(), you pass it the address of an array of integers, and it stores the value of the registers in that array. Setjmp() returns 0 when you call it in this way.

longjmp(jmp_buf env, int val);
Longjmp() resets the registers to the values saved in env. This includes the sp, fp and pc. What this means is that longjmp() doesn't return. Instead, when you call it, you return as if you have just called the setjmp() call that saved env. This is because the pc is restored along with the other registers. Setjmp() returns the val argument of longjmp(), which is not allowed to be zero (read the man page). Thus, you know when setjmp() returns a non-zero value that longjmp() was called, and is returning to setjmp().

My eg...


#include < stdio.h >
#include < setjmp.h >
#include < signal.h >
#include < unistd.h >

jmp_buf env;

static void signal_handler(int sig)
{
switch (sig) {
case SIGALRM: // process for alarm
longjmp(env,sig);
// BREAK NEVER REACHED
default: exit(sig);
}
}

class Process
{
unsigned int time_interval;

public :
Process()
{
time_interval = 3;
}

void get()
{
int returned_from_longjump;

printf(" inside get \n");
if ((returned_from_longjump = setjmp(env)) != 0)
{
switch (returned_from_longjump)
{
case SIGALRM:
printf("longjumped from alarm to get%d\n",SIGALRM);
return;
}
}

(void) signal(SIGALRM, signal_handler);
alarm(time_interval);
sleep(3);
alarm(0) ;
}


void put()
{
int returned_from_longjump;

printf(" inside put \n");
if ((returned_from_longjump = setjmp(env)) != 0)
{
switch (returned_from_longjump)
{
case SIGALRM:
printf("longjumped from alarm to put%d\n",SIGALRM);
return;
}
}

(void) signal(SIGALRM, signal_handler);
alarm(time_interval);
sleep(3);
alarm(0);
}


void process()
{
int count = 1;
while (count++)
{
if(count %2 )
{
get();
}
else
{
put();
}
printf(" waiting for you to INTERRUPT (cntrl-C) ...\n");
sleep(1);
} //end while forever loop
}

};

void main( )
{
Process p;
p.process();
}

No comments: