State Machines and Coroutines

D

Deiter

State Machines and Coroutines

The other thread on goto: Lead me to want to ask... In the spirit of
state machines and coroutines, This n00b to C would like to know if
setjmp/longjmp are the only way to break out of a routine; leave the
function and re-enter the stack state.

I ask this because I've only briefly, as yet, reviewed these functions
and I believe longjmp will only return a designated int. Therefore I
would naively assume pointers would/could be used to return or alter
variables. I think I remember something mentioned about volatile
qualifiers being used as well.

Thank you,
Deiter
 
A

Alastair

Deiter said:
State Machines and Coroutines

The other thread on goto: Lead me to want to ask... In the spirit of
state machines and coroutines, This n00b to C would like to know if
setjmp/longjmp are the only way to break out of a routine; leave the
function and re-enter the stack state.

I ask this because I've only briefly, as yet, reviewed these functions
and I believe longjmp will only return a designated int. Therefore I
would naively assume pointers would/could be used to return or alter
variables. I think I remember something mentioned about volatile
qualifiers being used as well.

Hi Deiter,
I'm not entirely sure what you are trying to do here, but it sounds
like you want to exit a function before you have reached the end?

You can exit a function at any point with the return(var) statment. For
example if your fundtion returns an integer you can call return(0).

e.g.

int test_fnc(int input)
{
if (input >= 1)
return (1);
else
return(0);
}

After the return statment the function is removed from the stack.
Hope that helps,
Alastair
 
D

Deiter

Alastair said:
Hi Deiter,
I'm not entirely sure what you are trying to do here, but it sounds
like you want to exit a function before you have reached the end?

You can exit a function at any point with the return(var) statment. For
example if your fundtion returns an integer you can call return(0).

e.g.

int test_fnc(int input)
{
if (input >= 1)
return (1);
else
return(0);
}

After the return statment the function is removed from the stack.
Hope that helps,
Alastair

Hi, thanks Alastar but I'm a bit farther along than returns.

I believe setjmp allows you to "unwind" the stack to a prior position in
the routine when longjmp is then called.

But I'm generally interested in how the experienced in C consider
efficient state machines/coroutine structured programming.

Thanks
 
A

Alastair

Hi, thanks Alastar but I'm a bit farther along than returns.
I believe setjmp allows you to "unwind" the stack to a prior position in
the routine when longjmp is then called.

But I'm generally interested in how the experienced in C consider
efficient state machines/coroutine structured programming.

Thanks

Hi Dieter,

Hmm... nearly everything I do in C is as part of state mechines, but I
have not come across a need to use setjmp / longjmp, we need every bit
of efficiency that we can get (in some cases).

I'll be interested to hear what other poeple have to say...

Do you have a simple example of what you are trying to achieve?
 
T

tmp123

Deiter said:
I think I remember something mentioned about volatile
qualifiers being used as well.

Hi,

One usual use of "volatile" is to inform the compiler that the variable
can be changed by some code not created by it. In other words, the
value can change "alone". Setjmp/longjmp man pages refers to this flag.

That means, in a code like:
int x;
x=8;
.... /* x is not changed */
printf("%d",x);

the compiler could optimize to:
int x;
.... /* x is not changed */
printf("%d",8);

The volatile flag prevents the compiler to do not made this kind of
optimization.

Probably some other users of this group can provide more information.

Kind regards.

PS: Sorry if this is something well known by you. About the other part
of your query, I'm not sure of understand it.
 
S

Sjouke Burry

Alastair said:
Hi Dieter,

Hmm... nearly everything I do in C is as part of state mechines, but I
have not come across a need to use setjmp / longjmp, we need every bit
of efficiency that we can get (in some cases).

I'll be interested to hear what other poeple have to say...

Do you have a simple example of what you are trying to achieve?
I program in C for about 20 years, and I have yet to meet a case,
where I need to jump(or might want to).
And I hope I never have to learn how.
Before that time, I used fortran, and even there jump was mostly
to get the same result as continue and exit in C,so short,simple
forward jumps only ,to control loops,or to construct a case switch.
 
C

Chuck F.

Deiter said:
>
State Machines and Coroutines

The other thread on goto: Lead me to want to ask... In the
spirit of state machines and coroutines, This n00b to C would
like to know if setjmp/longjmp are the only way to break out of
a routine; leave the function and re-enter the stack state.

I ask this because I've only briefly, as yet, reviewed these
functions and I believe longjmp will only return a designated
int. Therefore I would naively assume pointers would/could be
used to return or alter variables. I think I remember something
mentioned about volatile qualifiers being used as well.

There is no such thing as a stack in C. There are only various
classes of storage (static, automatic, and allocated). A stack may
be used to implement automatic storage, but is not required.

After that the important thing to bear in mind is that after
executing a longjmp only volatile storage items are accessible.
From N869:

[#3] All accessible objects have values as of the time
longjmp was called, except that the values of objects of
automatic storage duration that are local to the function
containing the invocation of the corresponding setjmp macro
that do not have volatile-qualified type and have been
changed between the setjmp invocation and longjmp call are
indeterminate.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
A

Alastair

Deiter said:
State Machines and Coroutines

The other thread on goto: Lead me to want to ask... In the spirit of
state machines and coroutines, This n00b to C would like to know if
setjmp/longjmp are the only way to break out of a routine; leave the
function and re-enter the stack state.

I ask this because I've only briefly, as yet, reviewed these functions
and I believe longjmp will only return a designated int. Therefore I
would naively assume pointers would/could be used to return or alter
variables. I think I remember something mentioned about volatile
qualifiers being used as well.


Hi Deiter - read the topic (very recent) about using "Goto" - the
longjmp / setjmp are mentioned there with some comments later about
it's potencial use...

Alastair
 
S

sebasttj

Deiter said:
State Machines and Coroutines

The other thread on goto: Lead me to want to ask... In the spirit of
state machines and coroutines, This n00b to C would like to know if
setjmp/longjmp are the only way to break out of a routine; leave the
function and re-enter the stack state.

Coroutines in C, by Simon Tatham:
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

He uses a technique similar to the famous Duff's Device to implement
coroutines as described by Knuth.

There's also the Protothreads library, which uses the technique to
implement a form of cooperative multithreading.
http://www.sics.se/~adam/pt/pt-1.0-refman/main.html

Josh
 
C

Chris Torek

The other thread on goto: Lead me to want to ask... In the spirit of
state machines and coroutines, This n00b to C would like to know if
setjmp/longjmp are the only way to break out of a routine;

As others noted, the answer to this question as stated is "no",
because ordinary "return" breaks out of a routine, returning to
its caller. But the answer to the question I believe you intended
is "yes".
leave the function and re-enter the stack state.

Given this and the subject line ("coroutines"), it sounds as though
you wish to use longjmp() to resume execution in a function that
earlier used setjmp() to terminate its own execution, e.g.:

void f(void) {
... do some work ...
if (setjmp(label1))
goto resume;
... do some more work ...
longjmp(label2, 1); /* "suspend" function f() */
resume:
... do yet more work ...
... ordinary function-return here ...
}

void g(void) {
... do some work ...
if (setjmp(label2))
goto resume;
... do some more work ...
f(); /* f() will longjmp to label2 */
return;
label2:
/* we got here because f() executed a longjmp() */
... do more work ...
longjmp(label1, 1); /* go back into f() */
/* NOTREACHED */
}

This is not "legal" in Standard C, and some implementations --
including more than one that I wrote myself -- will abort your
program at the "longjmp(label1, 1)" in g(), when they discover
that you are attempting to "reactivate" a stack frame that you
abandoned earlier (by executing the longjmp() in f()).

The key insight here is that longjmp() does not mean "suspend"; it
means "quit, and destroy all local variables". To implement
coroutines, you must *not* destroy the local variables. How this
can be done (and indeed, whether it is even possible) is
machine-dependent, and sometimes compiler-dependent. The longjmp
function is not guaranteed to do this, and does not work on real
implementations.
I ask this because I've only briefly, as yet, reviewed these functions
and I believe longjmp will only return a designated int.

This is correct; but the situation is considerably worse: longjmp()
may also destroy variables that are local to the function that used
setjmp(). To prevent this, such variables must be declared using
the "volatile" qualifier. In addition, the return value from setjmp()
cannot be stored in a variable! That is, the Standard renders the
effect of:

int x; /* or even "volatile int x" */
...
x = setjmp(jmpbuf);

undefined:

Environmental restriction

[#4] An invocation of the setjmp macro shall appear only in
one of the following contexts:

- the entire controlling expression of a selection or
iteration statement;

- one operand of a relational or equality operator with
the other operand an integer constant expression, with
the resulting expression being the entire controlling
expression of a selection or iteration statement;

- the operand of a unary ! operator with the resulting
expression being the entire controlling expression of a
selection or iteration statement; or

- the entire expression of an expression statement
(possibly cast to void).

[#5] If the invocation appears in any other context, the
behavior is undefined.

What this means is that to use longjmp(), the programmer must in
general implement his own stack of activations, e.g.:

struct Goto {
struct Goto *next;
volatile int longjmp_value1; /* can use volatile here */
volatile char *longjmp_value2; /* to avoid needing it below */
... etc ...
jmp_buf buf;
};
struct Goto *Goto_tos; /* current top of Goto stack */
...
void f(void) {
struct Goto g; /* need "volatile" if not in the struct */
...
g.next = Goto_tos; /* push ourselves on the stack */
Goto_tos = g;
if (setjmp(g.buf))
goto got_jumped_to;

... normal flow of control ...
return;
got_jumped_to:
Goto_tos = g.next; /* pop ourselves off the stack */
... the value(s) from longjmp are in g.longjmp_valueN ...
... "gone-to" flow of control ...
}

void g(void) {
... normal flow of control ...
if (some exceptional condition) {
/* abort, ripping control away from all callers until top
of goto stack */
Goto_tos->longjmp_value1 = ...;
Goto_tos->longjmp_value2 = ...;
longjmp(Goto_tos->buf, 1);
}
... continue normal flow of control ...
}

Note that as soon as you start doing this, all functions involved
in the path between f() and g() that need to clean up (e.g., close
a file or free memory) start having to catch longjmp()s. In this
case, the "goto stack" structure provides the same thing Lisp
systems provide via "unwind-protect".
 
D

Dieter

Deiter said:
State Machines and Coroutines

The other thread on goto: Lead me to want to ask... In the spirit of
state machines and coroutines, This n00b to C would like to know if
setjmp/longjmp are the only way to break out of a routine; leave the
function and re-enter the stack state.

I ask this because I've only briefly, as yet, reviewed these functions
and I believe longjmp will only return a designated int. Therefore I
would naively assume pointers would/could be used to return or alter
variables. I think I remember something mentioned about volatile
qualifiers being used as well.

Thank you,
Deiter

To all the responders: Thank you.

Dieter
 
C

Chris Torek

Given this and the subject line ("coroutines"), it sounds as though
you wish to use longjmp() to resume execution in a function that
earlier used setjmp() to terminate its own execution ...

That last line should read "earlier used longjmp()" (not setjmp()).

The example was correctly-invalid, though.

As one last note, it sometimes *is* possible to use longjmp to
implement coroutines (this depends on the system), but it is always
machine-dependent, and often best done as C-callable assembly
routines (i.e., often you should not even *attempt* to write the
coroutine routines in non-portable C -- it will be easier, not to
mention safer, to write them in the machine's assembly language).
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top