Index Home About Blog
From: Dennis Ritchie <dmr@bell-labs.com>
Newsgroups: comp.std.c
Subject: Re: Threads
Date: Tue, 15 Dec 1998 04:55:16 +0000

Nick Maclaren and many others understand the implementation
issues arising from setjmp/longjmp even aside from
asyncronicity, but some don't.  Suppose we have main(...) with

	int a;
	if (setjmp(...)) { /* what's the state here? */}
	else {
		/* lots of manipulation of values of
		   variables like a and even machine status */
		f(); /* where f() calls g() calls h() calls i()*/
	}

In the scenario, i() does a longjmp.  There are two very
general views of what might happen.  One is that setjmp
saves the state of the whole world at the time the call
to it is first executed (it's a sort of checkpoint), and this
all gets restored when the longjmp happens.  This is not
at all what the C setjmp/longjmp try to do.

The second general view is that the execution of the longjmp
restores control flow to the clause after the if (setjmp(...)),
but the visible state is the one contemporaneous with the instant
of the longjmp call within i().  In particular, any changes
to the variable a that occurred in main's else clause, before
the call to f(), are effective and visible.  Generally, this
is the way of C.

The practical implication is that the information saved at
the time of the setjmp is almost certainly quite small and
bounded, because anything about statics, random registers
etc. is likely obsolete and irrelevant when the longjmp
occurs.

The other practical implication and difficulty is that the
local variables visible in main (after the longjmp) may well
be strewn throughout the stack as main calls f calls g calls h
calls i, depending on details of the calling sequence.  For
example, main's 'a' may be spilled from a register to the
stack only somewhere in the middle of the sequence of calls.

The runtime implementation of longjmp thus must (in general)
be prepared to scrounge back through the stack and find where
the various bits were secreted.

The C89 use of "volatile" in this context was sort of a hint
to help this out, but isn't much use in the context of modern
optimizing compilers; it applied only to things explicitly
also declared as "register".  Today local (auto) things
tend to be put into registers automatically by the compiler.

	Dennis


From: Larry Jones <larry.jones@sdrc.com>
Newsgroups: comp.std.c
Subject: Re: Threads
Date: Tue, 15 Dec 1998 16:20:28 -0500

Dennis Ritchie wrote:
>
> The C89 use of "volatile" in this context was sort of a hint
> to help this out, but isn't much use in the context of modern
> optimizing compilers; it applied only to things explicitly
> also declared as "register".  Today local (auto) things
> tend to be put into registers automatically by the compiler.

I hate to argue with Dennis, of all people, but the use of "volatile"
in this context in C89 didn't have anything to do with "register", it
applied to all local variables.  The reason being that some traditional
implementations of setjmp/longjmp naturally reverted all registers to
the state they had when setjmp was called rather than the state they
had when they called (the function that called) longjmp.  Since modern
compilers do tend to put things in registers all by themselves, this
causes a serious problem in that such things no longer have the expected
semantics.  There was concern at the time that requiring compilers to
get the sematics right in all cases was an undue burden, so C89 took the
pragmatic approach of saying that local variables could end up with
either state.  This isn't so bad, since there are usually no more than
a few local variables whose state you care about -- C89 dictated that
programmers declare such variables "volatile" to give the compiler
notice that those are the important variables that it has to get right.

-Larry Jones

Apparently I was misinformed. -- Calvin


From: Dennis Ritchie <dmr@bell-labs.com>
Newsgroups: comp.std.c
Subject: Re: Threads
Date: Tue, 15 Dec 1998 20:09:43 +0000

Larry Jones wrote:

> I hate to argue with Dennis, of all people, but the use of "volatile"
> in this context in C89 didn't have anything to do with "register", it
> applied to all local variables....

Fair enough, though I know the effect was first noticed with
declared registers.

	Dennis

> Apparently I was misinformed. -- Calvin

Indeed.


From: Dennis Ritchie <dmr@bell-labs.com>
Newsgroups: comp.compilers
Subject: Re: Register allocation in special circumstancies
Date: 15 Feb 2001 00:34:45 -0500
Keywords: C, design, optimize

Torben AEgidius Mogensen wrote (first quoting Bokhanko):

> ..., and hence we must take into account this
> >nasty feature of "setjmp" points. But how to do it?
>
> The simplest thing would be to wrap every setjmp inside a function,
> which isn't inlined. This way, it won't affect the register allocation
> of the function that uses setjmp. And inside the new function you have
> a well-defined register state defined by the calling convention, which
> makes saving the state fairly simple....

No.  It doesn't help at all in a callee-saves situation.  The problem is
that in

int f()
	int var = 1;
	...
	if (setjmp(...)) {	// or a wrapper for it!
		...
		// what's var now? Any of g, h, i
		// might be the caller of longjmp
	}
	...
	var = 2;
	g();
	var = 3;
	h();
	var = 4;
	i();

any of g, h, or i (or their own descendants) may call longjmp.  There
is absolutely nothing setjmp or its wrapper can know about the dynamic
value of var at the time that longjmp is called later, and deeper
down.  When control finally returns to f(), unless f() itself has
stashed the dynamically current value of var before each call out, to
g, h, i, the value of a will be lost unless the wrapper is prepared to
do a highly compiler-dependent search through the stack for the place
where f's registers actually reside.

Saying (in C89 and C99)

	volatile int var = 1;

is entended to encourage f to save var within itself before each call
out to make this work, and correspondingly to restore it at each
callee return. Putting the setjmp in a wrapper could frustrate this
attempt, if the compiler somehow keys on the presence of a call to
setjmp, and in any event doesn't help it.

The point is that the register state at the time of the call to setjmp
is not necessarily relevant, so the most assiduous saving of it
doesn't help.

[The situation is much more pleasant in a general caller-saves scheme,
where the setjmp/longjmp situation can often fit in with little
effort.]

	Dennis

Index Home About Blog