Behaviour of setjmp/longjmp and registers

94 more school days cquenel at polyslo.CalPoly.EDU
Thu Jan 26 15:11:39 AEST 1989


Sorry for the length guys, but I think this will clear a lot up.
Present are responses follow to the following people:

henry at utzoo.uucp writes :
ark at alice.UUCP (Andrew Koenig) writes:
chris at mimsy.UUCP (Chris Torek) writes:
geoff at warwick.UUCP (Geoff Rimmer) writes:
haahr at phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes :
tim at crackle.amd.com (Tim Olson) writes:

In the last few articles I'm afraid I've been misunderstood a 
little bit.  I'd like to try again.

I think some people have there has been some confusion over
two behaviours associated with variables at longjmp time.

I will use the word CONSERVED when a variable is unaffected by
a long jump.  I will use the word RESTORED when a variable
is given the value that it had at setjmp-time (either "for free"
or by copying it's old value back into it).

Under older systems, automatic variables were CONSERVED, and
register variables were RESTORED.

To illustrate the difference consider the following pseudo-code:

	routine()
	{
		/* register */ int i;
		i = BEFORE_VALUE;
		call to set_jmp();
		i = AFTER_VALUE;
		call to routine_which_calls_long_jmp();
	}

If i is declared REGISTER, then "normally" it would be RESTORED.
It's value would be BEFORE_VALUE.
If i is NOT declared register, then normally it would be CONSERVED.
It's value would be AFTER_VALUE.

ANSI guarantees that variables declared volatile will be CONSERVED.  
It does not say that ANY variables have to be restored.

On stack-based machines with conventional registers and calling
sequences you get automatic variable CONSERVATION for free.
(You have to write out all your automatic variables
 that are alive in registers.)

On those conventional systems, you also get RESTORED automatics
under the following circumstances:  If you declare it to be
of register storage class, AND the compiler ACTUALLY puts it in
a register.  While I don't know of any compiler that GUARANTEES
that ALL "register" declarations result in actual registers being
used, I'm sure some people would assume that it is a safe bet that
ONE or TWO register declarations will be honored. Although this
is non-portable strictly speaking, it probably works most of the time.

I see no problem with a compiler going beyond the ANSI spec and
guaranteeing that ALL automatic variables will be CONSERVED.
I think this is a very reasonable thing.  And it can be achieved
without added setjmp-time baggage, on a fairly conventional machine.
No general registers need to stored for this to happen !

My argument is that no code would rely on registers being RESTORED.

Returning from a longjmp and having all your local registers trashed
would be a hassle to deal with, I admit.  But the alternative is
to have them be the values at the time the setjmping procedure
called the longjmping procedure.

>From the Pyramid man page on setjmp/longjmp:

                                    ...	 All memory-bound data
     have values as of the time	longjmp	was called.  The machine
     registers are restored to the values they had at the time
     that setjmp was called.  But, because the register	storage
     class is only a hint to the C compiler, variables declared
     as	register variables may not necessarily be assigned to
     machine registers,	so their values	are unpredictable after	a
     longjmp.  This is especially a problem for	programmers try-
     ing to write machine-independent C	routines.  ...

     [There follows an example with a careful note
      NOT to modify register variables after calling
      setjmp.  This is because their values will be
      indeterminate on a Pyramid.  It would not be too
      much trouble to conserve them, just ignore the
      register declaration in a routine that calls
      setjmp.]


henry at utzoo.uucp writes :
>However, an implementation that simply trashes the registers (rather,
>allows them to be trash) or, still worse, does likewise for automatic
>variables not declared "register" (i.e. by promoting them to registers
>and then not preserving them), is probably not going to sell well when
>word gets around.

You are correct, perhaps ANSI could have guaranteed that
automatics would be CONSERVED.  My point was that none should be
RESTORED.


ark at alice.UUCP (Andrew Koenig) writes:
>...John Reiser figured out a way around it -- a nifty version of
>longjmp that unwound the stack, restoring the correct registers
>at each iteration -- and that went into at least some VAX C
>implementations.

This allows register variables to be truly RESTORED without
the space and time overhead of saving all the registers in
the jmp_buf.  However, the calling convention that supported it
was rather luxurious (read : expensive) in its own right.

chris at mimsy.UUCP (Chris Torek) writes:
>But the contents of *all* automatic variables (register or not) *can* be
>guaranteed without too much trouble, and without requiring `volatile'
>qualifiers.

Granted, they can be guaranteed CONSERVED.
They are not RESTORED.

I wrote previously:
>I think this newer definition of setjmp/longjmp is much cleaner
>and provides only what is necessary and most useful.

chris at mimsy.UUCP (Chris Torek) writes:
>This is a separate (and much more sensible) line of argument with
>which I happen not to agree: opinion as to elegance.

I think that CONSERVING all automatic variables but RESTORING
none of them is more elegant than CONSERVING all non-register
automatic variables and sort-of-restoring or maybe-restoring
register variables.

I say that CONSERVING them all and RESTORING non of them is best.

geoff at warwick.UUCP (Geoff Rimmer) writes:
>I don't know what the ANSI standard says, but our manual page for
>setjmp() mentions in passing that
>
>	register variables have unpredictable values code after the
>	return from longjmp 
>
>So, it's probably just luck that the Sequent, Ultrix and Vax C
>compiler give what you'd expect from a non-register variable: 

It seems like restoring register variables to an unknown
state is a pretty common thing to do.  My argument is that
all these venders instead of saying "register variables
are in an unknown state" should NOT RESTORE THEM, and should write
them to the stack, and should say that they are CONSERVED.

It ocurrs to me that this would require the following extra work
on the part of their compilers: reserving space for register
variables on the stack and dumping even [registers that could
be guaranteed across procedure calls] to the stack.

haahr at phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes :
>a setjmp/longjmp implementation that restores all variables (including
>those in registers) falls out of a caller saves function call protocol.
>no muss, no fuss, just restore the stack pointer and pc.  this will
>work in the presence of inter-procedural optimization, if setjmp() is
>marked as a function that trashes all registers.

Using a full caller-saves convention by itself will not even
allow you to CONSERVE register variables, much less RESTORE them.
(Although when Paul said "restore" he may have meant CONSERVE).
When the first return from setjmp takes place, all those nicely
saved register values are popped off the stack. NEVER TO BE PUSHED
AGAIN. :-)  If you want your registers to be RESTORED, you have
to save them in the jmp_buf.

haahr at phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes :
>this is one of the several reasons i consider caller-saves a better
>approach to function call protocol.

Both pure-caller-save and pure-callee-save have their benefits, but
I personally believe that a combined caller-callee saves 
protocal works best.

tim at crackle.amd.com (Tim Olson) writes:

[In response to my saying that register windows made setjmp a big deal]

>Register-windowed machines are usually very easy to write
>setjmp()/longjmp() for, because the registers are treated as a
>"stack-cache".  Thus, all you have to save is the current stack-cache
>pointer in the jmpbuf, and restore it upon a longjmp().  This makes
>automatic variables act just as statics do: their value is that as of
>the time of the longjmp().  This is much cleaner than the botch of
>saving the register contents in the jmpbuf and restoring them.
>
>Of course, you still have to worry about optimizations such as register
>coalescing, etc.

You are correct. I was in error.

Sliding register window machines SHOULD be easy to write 
setjmp/longjmp for.  The simple solution of restoring the
Control Stack (or Register Stack) Pointer to its old value 
have the effect of CONSERVING register variables, but not
of RESTORING to their values at setjmp time.

I think this is a very sane way to do it.


--chris

-------------------------------------------------------------------------------
| Nothing the God of Bio-Mechanics wouldn't let you in heaven for ?           |
-------------------------------------------------------------------------------
| Chris Quenelle            | Smart Mailers -> cquenel at polyslo.CalPoly.EDU    |
| Computer Systems Lab      | Dumb Mailers  -> !ucbvax!voder!polyslo!cquenel  |
| Cal Poly State Univ.      |-------------------------------------------------|
| San Luis Obispo, CA 93407 | On a clear disk you can seek forever.           |
-------------------------------------------------------------------------------



More information about the Comp.lang.c mailing list