setjmp/longjmp and some table tennis

N

no_click_there

Hi,

I'm learning to use the setjmp/longjmp functions and still can't
really grasp what's going on here. I'd basically like to be able to
jump back and forth from (or to) two given functions.

Let's consider the following toy-example (yes, the example is stupid
but never mind...)

BEGIN CODE =====================
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>

void wrapper();
void ping(jmp_buf, jmp_buf);
void pong(jmp_buf, jmp_buf);

int main() {
wrapper();
return 0;
}
void ping(jmp_buf ping_env, jmp_buf pong_env) {
printf("calling ping\n");
switch (setjmp(ping_env)) {
case 0:
printf("ping: case 0\n");
pong(ping_env, pong_env);
break;
case 1:
printf("ping: case 1\n");
longjmp(pong_env, 1);
break;
case 2:
printf("ping: case 2\n");
longjmp(pong_env, 2);
break;
default:
printf("ping: case default\n");
break;
}
printf("ping is done\n");
}
void pong(jmp_buf ping_env, jmp_buf pong_env) {
printf("\tcalling pong\n");
switch (setjmp(pong_env)) {
case 0:
printf("\tpong: case 0\n");
longjmp(ping_env, 1);
break;
case 1:
printf("\tpong: case 1\n");
longjmp(ping_env, 2);
break;
case 2:
printf("\tpong: case 2\n");
longjmp(ping_env, 3);
break;
default:
printf("\tpong: case default\n");
break;
}
printf("pong is done\n");
}
void wrapper() {
jmp_buf pong_env;
jmp_buf ping_env;
ping(ping_env, pong_env);
}
END CODE ========================

This code works OK if I make ping_env and pong_env static global
variables. However, when I try to pass them as parameters the code
crash with a "Bus error".

Any explanation as to why it crashes? (Well, I guess that's because
the jmp_buf variables passed as parameters are somehow not properly
restored, but I'm new to this so...)

And, even better, any advise on how to correct this while keeping the
intent of the program? (Yeah, I know any real-life application of this
pattern would yield pretty awful code but that's not the matter
here...)

Thanks,

nch
 
D

Dave Vandervies

Hi,

I'm learning to use the setjmp/longjmp functions and still can't
really grasp what's going on here. I'd basically like to be able to
jump back and forth from (or to) two given functions.

Then setjmp/longjmp is the wrong tool for the job. You're only allowed
to longjmp back to a setjmp in a stack frame that's still live.

And, even better, any advise on how to correct this while keeping the
intent of the program? (Yeah, I know any real-life application of this
pattern would yield pretty awful code but that's not the matter
here...)

You want coroutines. They're not directly supported by C (or, for
that matter, by a lot of other languages); there are ways to do it
using correct and portable C code, but they're all Rather Ugly and/or
quite limited.

If you don't mind giving up portability, using threads to fake it might
be the cleanest solution, even though they're kind of heavyweight for
something like this (and they'll take a bit of care to get right).


dave
 
H

Hallvard B Furuseth

Dave said:
You want coroutines. They're not directly supported by C (or, for
that matter, by a lot of other languages); there are ways to do it
using correct and portable C code, but they're all Rather Ugly and/or
quite limited.

In this case it's simple enough. Let ping() and pong return the value
to be passed to each other, and write a controlling function which calls
them.

For more complicated examples it gets uglier, yes. E.g. let ping() and
pong() fill a struct with a pointer to the next function to be called
and its arguments, and the controlling function would call via that
struct. Or set an integer representing what to do next, and write
the controlling function as a state machine.
 
F

Fred Kleinschmidt

Hi,

I'm learning to use the setjmp/longjmp functions and still can't
really grasp what's going on here. I'd basically like to be able to
jump back and forth from (or to) two given functions.
And, even better, any advise on how to correct this while keeping the
intent of the program? (Yeah, I know any real-life application of this
pattern would yield pretty awful code but that's not the matter
here...)

Don't use a screwdriver when a pair of pliers is called for.
Use something patterned like this:

typedef void (*Bouncer)( /*whatever needs passing*/ );

void ping( /*whatever needs passing*/ );
void pong( /*whatever needs passing*/ );
....
Bouncer next = NULL;
while (1) {
next = (next==ping) ? pong : ping;
(*next) (/*whatever needs passing*/ );
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top