Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

noalias comments to X3J11

748 views
Skip to first unread message

d...@alice.uucp

unread,
Mar 20, 1988, 3:37:58 AM3/20/88
to
Reproduced below is the long essay I sent as an official comment
to X3J11. It is in two parts; the first points out some problems
in the current definition of `const,' and the second is a diatribe
about `noalias.'

By way of introduction, the important thing about `const' is that the
current wording says, in section 3.3.4, that a pointer to a
const-qualified object may be cast to a pointer to the plain object,
but "If an attempt is made to modify the pointed-to object by means of
the converted pointer, the behavior is undefined." Because function
prototypes tend to convert your pointers to const-qualified pointers,
difficulties arise.

In discussion with various X3J11 members, I learned that this section
is now regarded as an inadvertant error, and no one thinks that
it will last in its current form. Nevertheless, it seemed wisest
to keep my comments in their original strong form. The intentions
of the committee are irrelevant; only their document matters.

The second part of the essay is about noalias as such. It seems likely
that even the intentions of the committee on this subject are confused.

Here's the jeremiad.

Dennis Ritchie
research!dmr
d...@research.att.com
----------

This is an essay on why I do not like X3J11 type qualifiers.
It is my own opinion; I am not speaking for AT&T.

Let me begin by saying that I'm not convinced that even
the pre-December qualifiers (`const' and `volatile') carry
their weight; I suspect that what they add to the cost of
learning and using the language is not repaid in greater
expressiveness. `Volatile,' in particular, is a frill for
esoteric applications, and much better expressed by other
means. Its chief virtue is that nearly everyone can forget
about it. `Const' is simultaneously more useful and more
obtrusive; you can't avoid learning about it, because of its
presence in the library interface. Nevertheless, I don't
argue for the extirpation of qualifiers, if only because it
is too late.

The fundamental problem is that it is not possible to
write real programs using the X3J11 definition of C. The
committee has created an unreal language that no one can or
will actually use. While the problems of `const' may owe to
careless drafting of the specification, `noalias' is an
altogether mistaken notion, and must not survive.

1. The qualifiers create an inconsistent language

A substantial fraction of the library cannot be
expressed in the proposed language.

One of the simplest routines,

char *strchr(const noalias char *s, int c);

can return its first parameter. This first parameter must
be declared with `const noalias;' otherwise, it would be
illegal (by the constraints on assignment, 3.3.16.1) to pass
the address of a const or noalias object. That is, the type
qualifiers in the prototype are not merely an optional
pleasantry of the interface; they are required, if one is to
pass some kinds of data to this or most other library routines.

Unfortunately, there is no way in X3J11's language for
strchr to return the value it promises to, because of the
semantics of return (3.6.6.4) and casts (3.3.4). Whether
the stripping of the const and noalias qualifiers is done by
cast inside strchr, or implicitly by its return statement,
strchr returns a pointer that (because of `const') cannot be
stored through, and (because of `noalias') cannot even be
dereferenced; by the rules, it is useless. (Incidentally, I
think this observation was made by Tom Plum several years
ago; it's disconcerting that the inconsistency remains.)

Although the plain words of the Standard deny it, plastering
the appropriate `non-const' cast on an expression to
silence a compiler is sometimes safe, because the most probable
implementation of `const' objects will allow them to be
read through any access path, and will diagnose attempts to
change them by generating an access violation fault at run
time. That is, in common implementations, adding or taking
away the `const' qualifier of a pointer can never create any
bugs not implicit in the rule `do not modify a genuine const
object through any access path.'

Nevertheless, I must emphasize that this is NOT the
rule that X3J11 has written, and that its library is inconsistent
with its language. Someone writing an interpreter
using X3J11/88-001 is perfectly at liberty to (indeed, is
advised to) carry with each pointer a `modifiable' bit, that
(following 3.3.4) remains off when a pointer to a const-
qualified object is cast into a plain pointer. This implementation
will prevent many of the real uses of strchr, for
example. I'm thinking of things like

if (p = strchr(q, '/'))
*p = ' ';

which are common and innocuous in C, but undefined by
X3J11's language.

A related observation is that string literals are not
of type `array of const char.' Indeed, the Rationale (88-004
version) says, `However, string literals do not have
[this type], in order to avoid the problems of pointer type
checking, particularly with library functions....' Should
this bald statement be considered anything other than an
admission that X3J11's rules are screwy? It is ludicrous
that the committee introduces the `const' qualifier, and
also makes strings unwritable, yet is unable to connect the
two conceptions.

2. Noalias is an abomination

`Noalias' is much more dangerous; the committee is
planting timebombs that are sure to explode in people's
faces. Assigning an ordinary pointer to a pointer to a
`noalias' object is a license for the compiler to undertake
aggressive optimizations that are completely legal by the
committee's rules, but make hash of apparently safe
programs. Again, the problem is most visible in the
library; parameters declared `noalias type *' are especially
problematical.

In order to write such a library routine using the new
parameter declarations, it is in practice necessary to
violate 3.3.4: `A pointer to a noalias-qualified type ...
may be converted to ... the non-noalias-qualified type. If
the pointed to object is referred to by means of the converted
pointer, the behavior is undefined.' Thus, the problem
that occurs with `const' is now much worse; there are no
interesting and legal uses of strchr.

How do you code a routine whose prototype specifies a
noalias pointer? If you fail to violate 3.3.4, but instead
try to rewrite the declarations of temporary variables to
make them agree in type with parameters, it becomes hard to
be sure that the routine works. Consider the specification
of strtok:

char *strtok(noalias char *s1, noalias const char *s2);

It retains a static pointer to its writable, `noalias' first
argument. Can you be sure that this routine can be made
safe under the rules? I have studied it, and the answer is
conditionally yes, provided one accepts certain parts of the
Standard as gospel (for example that `noalias' handles will
NOT be synchronized at certain times) while ignoring other
parts. It is a very dodgy thing. For other routines, it is
certain that complete rewriting is necessary: qsort, for
example, is full of pointers that rove the argument array
and change it here and there. If these local pointers are
qualified with `noalias,' they may all be pointing to different
virtual copies of parts of the array; in any event,
the argument itself may have a virtual object that might be
completely untouched by the attempt to sort it.

The `noalias' rules have the assignment and cast restrictions
backwards. Assigning a plain pointer to a const-
qualified pointer (pc = p) is well-defined by the rules and
is safe, in that it restricts what you can do with pc. The
other way around (p = pc) is forbidden, presumably because
it creates a writable access path to an unwritable object.
With `noalias,' the rules are the same (pna = p is OK,
p = pna is forbidden), but the realistic safety requirements are
completely different. Both of these assignments are equally
suspicious, in that both create two access paths to an
object, one manifestation of which might be virtual.

Here is another way of observing the asymmetry: the
presence of `const type *' in a parameter list is a useful
piece of interface information, but `noalias type *' most
assuredly is not. Given the declaration


memcpy(noalias void *s1, const noalias void *s2, size_t n);

what information can one glean from it? Some committee
members apparently believe that it conveys either to the
reader or to the compiler that the routine is safe, provided
that the strings do not overlap. They are mistaken.
Perhaps the committee's intent is not reflected in the
current words of the Standard, but I can find nothing there
that justifies their belief. The rules (page 65, lines 19-20)
specify `all objects accessible by these [noalias]
lvalues,' which is the entirety of both array arguments.

More generally, suppose I see a prototype

char *magicfunction(noalias char *, noalias char *);

Is there anything at all I can conclude about the requirements
of magicfunction? Is there anything at all I can conclude
about things it promises to do or not to do? All I
learn from the Rationale (page 52) is that such a routine
enjoins me from letting the arguments overlap, but this is
at variance with the Standard, which gives a stronger
injunction.

Within the function itself, things are equally bad. A
`const type *' parameter, though it presents problems for
strchr and other routines, does usefully constrain the function:
it's not allowed to store through the pointer. However,
within a function with a `noalias type *' parameter,
nothing is gained except bizarre restrictions: it can't cast
the parameter to a plain pointer, and it can't assign the
parameter to another noalias pointer without creating
unwanted handles and potential virtual objects. The interface
MUST say noalias, or at any rate DOES say noalias, so
the author of the routine has all the grotesque inventions
of 3.5.3 (handles, virtual objects) rubbed in his face, like
or not.

The utter wrongness of `noalias' is that the information
it seeks to convey is not a property of an object at
all. `Const,' for all its technical faults, is at least a
genuine property of objects; `noalias' is not, and the
committee's confused attempt to improve optimization by pinning
a new qualifier on objects spoils the language.
`Noalias' is a bogus invention that is not necessary, and
not in any case sufficient for its apparent purpose.

Earlier languages flirted with gizmos intended to help
optimization, and generally abandoned them. The original
Fortran, for example, had a FREQUENCY statement that didn't
help much, confused people, and was dropped. PL/1 had
`normal/abnormal' and `uses/sets' attributes that suffered a
similar fate. Today, these are generally looked on as
adolescent experiments.

On the other hand, the insufficiency of `noalias' is
suggested by Cray's Fortran compiler, which has 20 separate
keywords that control various details of optimization. They
are specified by an equivalent of #pragma, and thus, despite
their oddness, can be ignored when trying to understand the
meaning of a program.

Perhaps there is some reason to provide a mechanism for
asserting, in a particular patch of code, that the compiler
is free to make optimistic assumptions about the kinds of
aliasing that can occur. I don't know any acceptable way of
changing the language specification to express the possibility
of this kind of optimization, and I don't know how much
performance improvement is likely to result. I would
encourage compiler-writers to experiment with extensions, by
#pragma or otherwise, to see what ideas and improvements
they can come up with, but I am certain that nothing resembling
the noalias proposal should be in the Standard.

3. The cost of inconsistency

K&R C has one important internal contradiction
(variadic functions are forbidden, yet printf exists) and
one important divergence between rule and reality (common
vs. ref/def external data definitions). These contradictions
have been an embarrassment to me throughout the years,
and resolving them was high on X3J11's agenda. X3J11 did
manage to come up with an adequate, if awkward, solution to
the first problem. Their solution to the second was the
same as mine (make a rule, then issue a blanket license to
violate it).

I'm aware that there are distinctions to be made
between `conforming' and `strictly conforming' programs.
Although the X3J11 rules for qualifiers are inconsistent,
and therefore most nominally X3J11 compilers will ignore, or
only warn about, casts and assignments that X3J11 says are
undefined, people will somehow survive. C has, after all,
survived the vararg and the extern problems.

Nevertheless, I advise strongly against sanctifying a
language specification that no one can possibly embody in a
useful compiler. This advice is based on bitter experience.

4. What to do?

Noalias must go. This is non-negotiable.

It must not be reworded, reformulated or reinvented.
The draft's description is badly flawed, but that is not the
problem. The concept is wrong from start to finish. It
negates every brave promise X3J11 ever made about codifying
existing practices, preserving the existing body of code,
and keeping (dare I say it?) `the spirit of C.'

Const has two virtues: putting things in read-only
memory, and expressing interface restrictions. For example,
saying

char *strchr(const char *s, int c);

is a reasonable way of expressing that the routine cannot
change the object referred to by its first argument. I
think that minor changes in wording preserve the virtues,
yet eliminate the contradictions in the current scheme.

1) Reword page 47, lines 3-5 of 3.3.4 (Cast operators), to
remove the undefinedness of modifying pointed-to
objects, or remove these lines altogether (since casting
non-qualified to qualified isn't discussed explicitly
either.)

2) Rewrite the constraint on page 54, lines 14-15, to say
that pointers may be assigned without taking qualifiers
into account.

3) Preserve all current constraints against modifying
non-modifiable lvalues, that is things of manifestly
const-qualified type.

4) String literals have type `const char []'.

5) Add a constraint (or discussion or example) to assignment
that makes clear the illegality of assigning to an
object whose actual type is const-qualified, no matter
what access path is used. There is a manifest constraint
that is easy to check (left side is not const-
qualified), but also a non-checkable constraint (left
side is not secretly const-qualified). The effect
should be that converting between pointers to const-
qualified and plain objects is legal and well-defined;
avoiding assignment through pointers that derive ultimately
from `const' objects is the programmer's responsibility.


These rules give up a certain amount of checking, but
they save the consistency of the language.

Stephen J. Friedl

unread,
Mar 20, 1988, 11:47:39 PM3/20/88
to
In article <77...@alice.UUCP>, d...@alice.UUCP (Dennis Ritchie) writes:
> 4. What to do?
>
> Noalias must go. This is non-negotiable.
>
> It must not be reworded, reformulated or reinvented.
> The draft's description is badly flawed, but that is not the
> problem. The concept is wrong from start to finish. It
> negates every brave promise X3J11 ever made about codifying
> existing practices, preserving the existing body of code,
> and keeping (dare I say it?) `the spirit of C.'

Now >>this<< is a man who does not mince his words.

--
Steve Friedl V-Systems, Inc. *Hi Mom*
fri...@vsi.com {uunet,attmail,ihnp4!amdcad!uport}!vsi!friedl

Frank Swarbrick

unread,
Mar 21, 1988, 8:22:24 PM3/21/88
to
What does this const thing have to do with the function below getting the
suspicious pointer conversion warning?

int pos(const char *str,char c)
{
char *s;

s = strchr(str,c);
return s ? (int)(s - str) : -1;
}

This, of course, works if I take out the const thing. Is this one of the
things that you were complaining about, or should this just plain not work?
(This was done in Turbo C 1.5, by the way.)

Frank Swarbrick (and his cat)
swar...@tramp.UUCP swar...@tramp.Colorado.EDU
...!{ncar|nbires}!boulder!tramp!swarbric
"Welcome back my friends to the show that never ends..."

Bob Babcock

unread,
Mar 22, 1988, 11:07:14 PM3/22/88
to
>>`Volatile,' in particular, is a frill for
>>esoteric applications, and much better expressed by other
>>means. Its chief virtue is that nearly everyone can forget
>>about it.

What about an interrupt routine which receives control on a keyboard
interrupt and sets a globally known flag. That doesn't sound very
esoteric to me, and volatile seems exactly what is needed to describe
such a flag to the compiler. (I also do some of my coding in an
environment where some variables are hardware registers which may
change due to external events. That's less common, but I wouldn't
call it esoteric either.)

Henry Spencer

unread,
Mar 23, 1988, 2:33:30 PM3/23/88
to
>What does this const thing have to do with the function below getting the
>suspicious pointer conversion warning?
>
> return s ? (int)(s - str) : -1;

You're mixing two separate types of pointer: s is char *, str is
const char *. THOSE ARE NOT THE SAME TYPE. Evidently the compiler
is doing the conversion for you, but it's not entirely happy about it.
In this particular case, adding const to the declaration of s would
fix it, pretty much. (The exact rules for this sort of thing may yet
change again before ANSI C is final.)
--
"Noalias must go. This is | Henry Spencer @ U of Toronto Zoology
non-negotiable." --DMR | {allegra,ihnp4,decvax,utai}!utzoo!henry

Frank Swarbrick

unread,
Mar 24, 1988, 7:31:24 PM3/24/88
to
In article <1988Mar23....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
:>What does this const thing have to do with the function below getting the

:>suspicious pointer conversion warning?
:>
:> return s ? (int)(s - str) : -1;
:
:You're mixing two separate types of pointer: s is char *, str is
:const char *. THOSE ARE NOT THE SAME TYPE. Evidently the compiler
:is doing the conversion for you, but it's not entirely happy about it.
:In this particular case, adding const to the declaration of s would
:fix it, pretty much. (The exact rules for this sort of thing may yet
:change again before ANSI C is final.)

I just changed it to
return s ? s - (char *)str : -1;

and it worked fine. Thanks for the idea, although you gave it indirectly and
maybe without knowing it...

(Actually I didn't run it, but it compiled without giving the warning.)

Frank Swarbrick (and his cat)
swar...@tramp.UUCP swar...@tramp.Colorado.EDU
...!{ncar|nbires}!boulder!tramp!swarbric

"Remember when you were young. You shown like the sun..."

t...@hcx2.ssd.harris.com

unread,
Mar 25, 1988, 10:53:00 AM3/25/88
to

> Const has two virtues: putting things in read-only
>memory, and expressing interface restrictions. For example,
>saying
>
> char *strchr(const char *s, int c);
>
>is a reasonable way of expressing that the routine cannot
>change the object referred to by its first argument. I
>think that minor changes in wording preserve the virtues,
>yet eliminate the contradictions in the current scheme.

You bet!, That would be a very reasonable thing for const to do,
and that's what I thought it did until I talked to my friend on
the committee. It is obvious to the casual observer what something
being constant means, right? But no, the obvious meaning of const
is not acceptable to some committee members, so what happens, `noalias'
is invented just so `noalias const' can mean what just `const'
should obviously have meant all along.

I agree with dmr, noalias must go! But I have another even more
pressing reason for getting rid of it. Working for a compiler
vendor, this is the nightmare scenario I see:

1) User with non-optimizing compiler sees noalias and says
`This is neat! I can get my code really optimized with this!'
and proceeds to use it liberally throughout the 40,000,000
lines of code he develops with his nonoptimizing compiler
that is toatlly bored by `noalias'.

2) User switches to our highly optimizing compiler which immediately
deletes 30,000,000 lines of apparently dead code. And does
nastly transformations to the rest of it.

3) User screams, yells, and generally makes life totally
miserable complaining about how our compiler is broken.

Repeat this over and over for an endless series of users who won't
believe they can't write code. Not to mention that some of the
problems might be actual bugs in the optimizer, but it could
take weeks to track them down and sort them out.

For this reason alone, I can't believe that any vendor is likely to
actually take advantage of any optimizations that noalias might allow.
Similar situations already exist for FORTRAN. There are all sorts
of optimizations allowed according to the strict letter of the
FORTRAN standard, but very few compilers will do them by default because too
much user code will break. You generally have to specifically request
the highest level of optimization.

This is an important point. Real vendors have to develop compilers
for real users. Neither users or compilers are perfect, and `noalias'
will just emphasize those imperfections.

The correct way to aggressively optimize programs is via a global
program database that gathers the information for the whole
program and *knows* what is aliased and what is not, but thats
another story....
================================
taho...@ssd.harris.com

Henry Spencer

unread,
Mar 25, 1988, 12:23:55 PM3/25/88
to
>>`Volatile,' in particular, is a frill for esoteric applications...

>
> What about an interrupt routine which receives control on a keyboard
> interrupt and sets a globally known flag. That doesn't sound very
> esoteric to me...

Interrupt routines are almost by definition esoteric, not to mention highly
machine-specific. Only on PCs do users commonly write their own interrupt
routines; in more modern environments [MSDOS is a Neanderthal operating
system, its only saving grace being some of the nifty applications that run
on it] such things generally are confined to the bowels of the operating
system, where they belong.

Randell E. Jesup

unread,
Mar 26, 1988, 4:10:19 PM3/26/88
to
In article <1988Mar25....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>>>`Volatile,' in particular, is a frill for esoteric applications...
>
>Interrupt routines are almost by definition esoteric, not to mention highly
>machine-specific. Only on PCs do users commonly write their own interrupt
>routines; in more modern environments [MSDOS is a Neanderthal operating
>system, its only saving grace being some of the nifty applications that run
>on it] such things generally are confined to the bowels of the operating
>system, where they belong.

And would you mandate that C never be used for writing operating
systems (one of it's original purposes)? What about user programs that deal
with custom or non-standard hardware (like lab stuff)? Or things like
the Amiga, where you can have your message ports handled by software interrupts
if you prefer them to signals.
'Volatile' is extremely important for dealing with real-world
hardware. The contortions to work without it in these cases are horrible,
while it is a relatively easy thing to deal with if you don't need it (ignore
it). The fact that things that need volatile probably won't be portable
across all machines that have C compilers is a non-issue.

>"Noalias must go. This is | Henry Spencer @ U of Toronto Zoology
>non-negotiable." --DMR | {allegra,ihnp4,decvax,utai}!utzoo!henry

^^^^^^^^^^^^^^^^
Now that we can agree on!

// Randell Jesup Lunge Software Development
// Dedicated Amiga Programmer 13 Frear Ave, Troy, NY 12180
\\// beowulf!lunge!je...@steinmetz.UUCP (518) 272-2942
\/ (uunet!steinmetz!beowulf!lunge!jesup) BIX: rjesup

(-: The Few, The Proud, The Architects of the RPM40 40MIPS CMOS Micro :-)

Lawrence Crowl

unread,
Mar 27, 1988, 1:51:27 PM3/27/88
to
The `volatile' type qualifier of ANSI C has recently been criticized as a
frill. While this assertion is arguable for uniprocessors, it is not true for
shared-memory multiprocessors. Processes on such machines communicate via
updates to a shared variables. These updates may occur at arbitrary times
relative to one of the observing processes. If there is no mechanism to
indicate when a variable referenced by one process may be modified by another
process, the compiler must assume that all variables may be modified at any
time. In other words, the compiler must assume that all variables are
`volatile'. This limits the optimizing effectiveness of compilers
substantially. This limitation is severe because most variables are not
shared. The compiler is forced to use sub-optimial code for 99% of its
references in order to obtain correctness on the other 1%. Shared-memory
multiprocessors need the `volatile' concept in order to use highly optimizing
compilers. The `volatile' concept could be provided as a pragma, but the
concept must exist.
--
Lawrence Crowl 716-275-9499 University of Rochester
cr...@cs.rochester.edu Computer Science Department
...!{allegra,decvax,rutgers}!rochester!crowl Rochester, New York, 14627

Doug Gwyn

unread,
Mar 27, 1988, 2:24:21 PM3/27/88
to
In article <81...@sol.ARPA> cr...@cs.rochester.edu (Lawrence Crowl) writes:
>shared-memory multiprocessors. Processes on such machines communicate via
>updates to a shared variables.

You need a hell of a lot more than "volatile" to properly
synchronize concurrent processes.

Jim Shankland

unread,
Mar 28, 1988, 2:01:10 AM3/28/88
to
In article <1988Mar25....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>>>`Volatile,' in particular, is a frill for esoteric applications...
>>
>> What about an interrupt routine ....

>
>Interrupt routines are almost by definition esoteric, not to mention highly
>machine-specific. Only on PCs do users commonly write their own interrupt
>routines....

Oh, all right, I'll rise to the bait. What about shared memory applications?
Surely memory that can be written by another process at any time is volatile.
Do we really want to claim that all code addressing shared memory is part
of an "esoteric application"?
Jim Shankland
..!ihnp4!cpsc6a!\
sun!rtech!jas
..!ucbvax!mtxinu!/

> The preceding message was brought to you courtesy of Eddie <
> Enterprises, a broadly diversified, multinational corporation <
> bringing software, roofing supplies, exquisite keyboard sounds, <
> and other fine products to a hungry world. <

ELIN Forsch.z.

unread,
Mar 28, 1988, 8:09:19 AM3/28/88
to
In article <1988Mar25....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>Interrupt routines are almost by definition esoteric, not to mention highly
>machine-specific.

Signal handlers will be at least very similar to interrupt routines. Still it
does not seem to be esoteric to me, if I set a flag in such a handler. And now
please tell me, how to tell the compiler it must not `optimize' the access to
this flag?


Dietmar Weickert,
ALCATEL-ELIN Research Center, Vienna, Austria.

Sean Fagan

unread,
Mar 28, 1988, 9:55:20 AM3/28/88
to
In article <5...@imagine.PAWL.RPI.EDU> beowulf!lunge!je...@steinmetz.UUCP writes:
>In article <1988Mar25....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>>>>`Volatile,' in particular, is a frill for esoteric applications...
>>
>>Interrupt routines are almost by definition esoteric, not to mention highly
>>machine-specific.
> 'Volatile' is extremely important for dealing with real-world
>hardware.

Another use I haven't seen mentioned is for shared memory. Since this can
be accessed (and modified) by more than one process, having a heavily
optimizing compiler move one location (or more) into a register would be a
bad idea. Doing something like

volatile char shm_seg[1024];
shmat(...,shm_seg,...);

seems like it would be nice to have (I may have screwed up the syntax of the
shared memory stuff, pardon me).

>>"Noalias must go. This is | Henry Spencer @ U of Toronto Zoology
>>non-negotiable." --DMR | {allegra,ihnp4,decvax,utai}!utzoo!henry
> ^^^^^^^^^^^^^^^^
>Now that we can agree on!

As has been stated before, when this man (dmr@alice) speaks, ANSI should
listen!

> // Randell Jesup Lunge Software Development

--

Sean Fagan uucp: {ihnp4,hplabs,psivax}!csun!sef
CSUN Computer Center BITNET: 1GTLSEF@CALSTATE
Northridge, CA 91330 (818) 885-2790

Tom Neff

unread,
Mar 28, 1988, 10:23:15 AM3/28/88
to
In article <1988Mar25....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>Interrupt routines are almost by definition esoteric, not to mention highly
>machine-specific. Only on PCs do users commonly write their own interrupt
>routines...

It would be fairer to say "only on microcomputers" rather than "only on
PCs." I write real-time systems for a living, and so do a lot of other
folks I know. We do write interrupt routines, and plenty of 'em. "C" is
a strong contender among languages for this work, because of its portability
and lack of overhead. The basic concept of /volatile/ is very important to
me, and I'm glad XJ311 recognizes it. Many's the time I have had to surround
a few statements with forests of labels or calls to dummy() just to get one
compiler or another to stop optimizing access to a location!

I will admit, though, that /vol/ is a grown-up keyword, which plenty of
programmers will have little use for. But it needn't intrude in your lives
at all. Those who need it, use it. (Fortunately it's not too much of a pain
to implement -- effectively it just flags optimization off for certain
variables). It does sound like /noalias/ is making a much noisier and messier
splash on its arrival in the standard. I am not too keen on forcing a strange
new keyword into half the declarations, for instance, in dear old stdio.h. TMN


--

Tom Neff

Tom Neff

unread,
Mar 28, 1988, 10:44:14 AM3/28/88
to
In article <75...@brl-smoke.ARPA> gw...@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>You need a hell of a lot more than "volatile" to properly
>synchronize concurrent processes.

You do, but not from the language itself! Just about everything else you
need for multiprocessing, you can write yourself as external support routines.
Interrupt handlers and volatile variables are all the language has to give
you. Fortunately most implementations have some sort of interrupt extension,
but even where there isn't one you can write an assembly-language front end
to call your "C" handler cleanly. It's not that simple with the shared
variables (or memory mapped I/O, which is just as prevalent) - you really
need some help from the compiler to do things efficiently. TMN

--

Tom Neff

Walter Bays

unread,
Mar 28, 1988, 5:10:24 PM3/28/88
to
In article <81...@sol.ARPA> cr...@cs.rochester.edu (Lawrence Crowl) writes:
>The `volatile' type qualifier of ANSI C has recently been criticized as a
>frill. While this assertion is arguable for uniprocessors, it is not true for
>shared-memory multiprocessors. [...] If there is no mechanism to

>indicate when a variable referenced by one process may be modified by
>another process, the compiler must assume that all variables may be
>modified at any time. [...] This limits the optimizing effectiveness
>of compilers substantially. [...]

The 'volatile' keyword would also work for uniprocessor device
drivers. How about setjmp()? Or side effects of functions with
"dangerous" pointers?
--
------------------------------------------------------------------------------
Any similarities between my opinions and those of the
person who signs my paychecks is purely coincidental.
E-Mail route: ...!pyramid!garth!walter
USPS: Intergraph APD, 2400 Geng Road, Palo Alto, California 94303
Phone: (415) 852-2384
------------------------------------------------------------------------------

Henry Spencer

unread,
Mar 28, 1988, 7:44:54 PM3/28/88
to
> >... such things generally are confined to the bowels of the operating

> >system, where they belong.
>
> And would you mandate that C never be used for writing operating
> systems (one of it's original purposes)? ...

Nobody is saying that the concept is not necessary in certain specialized
situations. The point is that these are a sufficiently small subset of C
applications that the need should addressed with #pragma, rather than by
cluttering up the type system with it. The principal problem with #pragma
is that it is not portable, since its semantics are not standardized, but
the sort of code we're talking about isn't portable anyway.
--

Jim Shankland

unread,
Mar 28, 1988, 8:36:55 PM3/28/88
to
In article <75...@brl-smoke.ARPA> gw...@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
> [About "volatile" being necessary for concurrent processes using
> shared memory:]

>You need a hell of a lot more than "volatile" to properly
>synchronize concurrent processes.

True enough, but not relevant. Assuming you *have* the "hell of a lot
more" -- System V semaphores, for example -- you still need "volatilie."
Therefore, "volatile" is hardly an esoteric frill.

Per Fogelstr|m

unread,
Mar 29, 1988, 2:31:23 AM3/29/88
to
In article <75...@brl-smoke.ARPA> gw...@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:

I don't beleive that "volatile" was intended to be a mechanisim for
processor synchronization, rather a way to indicate that a "memory"
location has side effects, for example when it's read. For those of
You that don't normally do system and driver programming it's qite
meaningless, but boy how nice it is to be able to use the -O switch
when compiling a driver wich requires fast interrupt turnaround.

Tom Neff

unread,
Mar 29, 1988, 8:15:30 AM3/29/88
to
In article <1988Mar29....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
> ... The point is that [OS-type programs where /volatile/ is important]
>are a sufficiently small subset of C applications that the need should be

>addressed with #pragma, rather than by cluttering up the type system with it.

Well, in all fairness I could easily live with #pragma volatile(foo) instead,
*IF* compiler writers actually bothered to code the pragmas when XJ311 "let
them off the hook" by degrading /volatile/ from a required language feature
to a totally elective pragma. I'm not sure they would, especially if they
were busy trying to figure out /noalias/. :-) TMN
--

Tom Neff

Henry Spencer

unread,
Mar 29, 1988, 11:27:11 AM3/29/88
to
With shared memory, again, volatile is the least of your problems.

Mike Wexler

unread,
Mar 29, 1988, 2:35:16 PM3/29/88
to
In article <1988Mar29....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>... The principal problem with #pragma

>is that it is not portable, since its semantics are not standardized, but
>the sort of code we're talking about isn't portable anyway.
I would disagree that is isn't possible to write portable code that requires
volatiles. An example(possibly the only one), is the use of System V
or Berkeley shared memory. With either of these you can have volatile
values in portable(At least to similar Unix systems) programs. Given
this it might be useful for the Posix standard to require the C compiler
to support volatile or a volatile pragma.

Walter Bays

unread,
Mar 29, 1988, 6:42:39 PM3/29/88
to
In article <1988Mar29....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>Nobody is saying that the concept is not necessary in certain specialized
>situations. The point is that these are a sufficiently small subset of C
>applications that the need should addressed with #pragma, rather than by
>cluttering up the type system with it. The principal problem with #pragma
>is that it is not portable, since its semantics are not standardized, but
>the sort of code we're talking about isn't portable anyway.

Programs using signal handlers and/or shared memory could be portable.

00704a-Liber

unread,
Mar 29, 1988, 6:48:25 PM3/29/88
to
In article <12...@brl-adm.ARPA> PEPRBV%CFAAMP...@husc6.harvard.EDU (Bob Babcock) writes:
>>`Volatile,' in particular, is a frill for
>>esoteric applications, and much better expressed by other
>>means. Its chief virtue is that nearly everyone can forget
>>about it.

>What about an interrupt routine which receives control on a keyboard
>interrupt and sets a globally known flag.

This is not really legal within C, since you are not allowed to dereference
an absolute address (such as doing x = *NULL, where NULL == 0). However,
because of the relationship between C and actual memory address, I can see
how you would want a 'consistent' way of declaring 'volatile' objects (even
though it is non-portable).

The arguments for and against this are very close to the arguments for and
against a portable asm (actually, though, what was wanted was a CONSISTENT
way of declaring inline assembly code). If ANSI is going to discuss
consistency of non-portable constructs, then volatile should still be
considered for ANSI C. To be fair, though, all the other consistent
non-portable constructs should also be considered (a real BIG can of worms).


BTW, there already IS a semi-portable way of doing inline machine code.
Just look Sjoerd Mullender & Robert van Renesse's winning entry in the 1984
Obfuscated C Contest!! :-) :-)
--
_ __ NEVIN J. LIBER ..!ihnp4!ihlpf!nevin1 (312) 510-6194
' ) ) "The secret compartment of my ring I fill
/ / _ , __o ____ with an Underdog super-energy pill."
/ (_</_\/ <__/ / <_ These are solely MY opinions, not AT&T's, blah blah blah

00704a-Liber

unread,
Mar 29, 1988, 7:36:34 PM3/29/88
to
In article <5...@garth.UUCP> wal...@garth.UUCP (Walter Bays) writes:
>The 'volatile' keyword would also work for uniprocessor device
>drivers. How about setjmp()? Or side effects of functions with
>"dangerous" pointers?

setjmp() is a function call (in much the same way as fork(), exec(),
exit(), etc.) and is not part of the language specification itself (it is
not in section 3 of the draft standard). Same is true about side effects of
functions of dangerous pointers. 'Volatile', however, IS part of the
language specification. I consider it to be a 'frill' because nothing else
in the language specification addresses hardware, per se.

Barry Margolin

unread,
Mar 29, 1988, 9:38:40 PM3/29/88
to
In article <1...@wyse.wyse.com> mi...@wyse.UUCP (Mike Wexler) writes:
>I would disagree that is isn't possible to write portable code that requires
>volatiles. An example(possibly the only one), is the use of System V
>or Berkeley shared memory. With either of these you can have volatile
>values in portable(At least to similar Unix systems) programs. Given
>this it might be useful for the Posix standard to require the C compiler
>to support volatile or a volatile pragma.

But such programs are NOT portable. A program using System V shared
memory is not portable to a BSD system and vice-versa. And none of
them are portable to non-Unix systems.

As you yourself implied in your last sentence, the right place for
such a requirement is in the Posix standard, not the C standard. And
the mechanism that can be used for this is #pragma. The C standard
doesn't specify the format of particular pragmas (whether this is wise
is debatable), but Posix already requires various extra C features
(for example, I believe it adds things to include files that are
specified in the C standard), so it could also require that compilers
implement a particular set of pragmas with a given syntax.


Barry Margolin
Thinking Machines Corp.

bar...@think.com
uunet!think!barmar

gil...@uiucdcsp.cs.uiuc.edu

unread,
Mar 29, 1988, 10:37:00 PM3/29/88
to

C is not a multiprocessor systems programming language. I'm sorry for
you multiprocessor programmers. My advice to you is to buy
hypercubes, write in assembly language, or develop your own language.

We don't yet understand how to program multiprocessors well, or even
if shared-memory multiprocessing is the wave of the future. Please
don't jump the gun by extending the C language too soon. When
multiprocessing is solved, C will probably have been dead for many
years, and a multiprocessing language (perhaps a distant descendant)
will perform its function.

You can get what you want by adding a compiler-specific (#pragma type)
extension, with no loss of generality. Do you think "volatile" will
make your programs portable to other multiprocessors???? Dream on!
Your arguments about shared-memory multiprocessors just are not
convincing.

THE ONLY reason to keep it in the language is if you can argue it's
important for uniprocessing. I believe it might be important for
someone implementing monitors (a la MESA), if monitor locks could span
blocks, not just entire procedures. But in this case, it's probably a
better idea to implement concurrency control directly in the language,
since this type of extension has been extensively researched.


I believe that you sincerely need this feature, but I also sincerely
believe that most people won't need it. In top-quality standards
work, you learn to leave out the nonessentials. Others can put them
in at their own discretion.

Don Gillies {ihnp4!uiucdcs!gillies} U of Illinois
{gil...@p.cs.uiuc.edu}

Lawrence V. Cipriani

unread,
Mar 29, 1988, 11:15:01 PM3/29/88
to
In article <1...@wyse.wyse.com> mi...@wyse.UUCP (Mike Wexler) writes:
>I would disagree that is isn't possible to write portable code that requires
>volatiles. An example(possibly the only one), is the use of System V
>or Berkeley shared memory. ...

I might not understand volatile correctly but this might also be an
example:

volatile int customer_changeable_var = 0;

main( )
...

if (customer_chageable_var != 0)
{
...
}

If the volatile were dropped off, the compiler would be free to
optimize out the "impossible" code. A customer changeable global
variable is a handy way for implementing optional features that
customers may or may not want; especially in programs that should
avoid disk i/o.

--
Larry Cipriani, AT&T Networks Systems (day) Ohio State University (night)
Domain: l...@tut.cis.ohio-state.edu
Path: ...!cbosgd!osu-cis!tut.cis.ohio-state.edu!lvc (weird but right)

Karl Heuer

unread,
Mar 30, 1988, 1:16:49 PM3/30/88
to
In article <1...@wyse.wyse.com> mi...@wyse.UUCP (Mike Wexler) writes:
>In article <1988Mar29....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>>the sort of code we're talking about isn't portable anyway.
>I would disagree that is isn't possible to write portable code that requires
>volatiles. An example(possibly the only one), is the use of System V
>or Berkeley shared memory.

Why drag shared memory into it? Isn't the following an example of a strictly
conforming program that needs volatile?

#include <signal.h>
static sig_atomic_t volatile gotcha;
static void catch(int signo) { gotcha = 1; }
int main(void) {
(void)signal(SIGINT, catch);
gotcha = 0;
do; while (!gotcha);
return (0);
}

Karl W. Z. Heuer (ima!haddock!karl or ka...@haddock.isc.com), The Walking Lint

Barnacle Wes

unread,
Mar 30, 1988, 1:28:06 PM3/30/88
to
In article <81...@sol.ARPA>, cr...@cs.rochester.edu (Lawrence Crowl) writes:
> The `volatile' type qualifier of ANSI C has recently been criticized as a
> frill. While this assertion is arguable for uniprocessors, it is not true for
> shared-memory multiprocessors. Processes on such machines communicate via
> updates to a shared variables. These updates may occur at arbitrary times
> relative to one of the observing processes. If there is no mechanism to
> indicate when a variable referenced by one process may be modified by another
> process, the compiler must assume that all variables may be modified at any
> time.

The `volatile' qualifier is also a must for such things as I/O
processors that do not produce interrupts. Typically with such a
device, you will poll the status register at a predetermined interval,
and when the operation is complete, you can go on to the next
operation on that device.

These types of devices are used quite a bit in imbedded systems where
the speed of the device is not critical, and the interrupt(s) are
already heavily used for speed-critical devices/operations. You
certainly don't want the compiler to optimize away your check on the
status register!

--
/\ - "Against Stupidity, - {backbones}!
/\/\ . /\ - The Gods Themselves - utah-cs!utah-gr!
/ \/ \/\/ \ - Contend in Vain." - uplherc!sp7040!
/ U i n T e c h \ - Schiller - obie!wes

John Myers

unread,
Mar 30, 1988, 1:41:22 PM3/30/88
to

Is R. Stallman's reading of the ANSI draft wrong, or isn't it
necessary to declare automatic variables as 'volatile' in order to
guarantee that their values will be preseved across a setjmp/longjmp?
(as otherwise they could be placed in registers)

If RMS is right, then the committee botched setjmp/longjmp.

--
_.John G. Myers Internet: John....@cs.cmu.edu
LoseNet: ...!seismo!hao!wiscvm.wisc.edu!k!nobody

Bakul Shah

unread,
Mar 30, 1988, 2:08:16 PM3/30/88
to
You must be able to tell a compiler that certain variables have side
effects *IF* you are using a highly optimizing compiler and you do one or
more of the following:

o access a global variable from a signal handler
o access a shared variable
o patch a variable in the executable file
o implement co-routines
o access a memory mapped io address
o access a variable from procedures written in two different languages

An application program, written in ``pure'' C (that is, it does not use
shared memory, uses either routines written in C or standard routines, does
not use signal handling, does not need didling with executables, does not
have co-routines/lighweight processes, does not use setjmp/longjmp) does
not need volatile and can safely ignore it.

But if you write a program that does do any of the above strange things,
`volatile' is a *portable* way of telling the compiler about side effects.

If a compiler wishes to ``ignore'' volatile, it must treat all non-register
variables as implicitly volatile.

Since you don't know what kind of compiler is available on another machine,
I claim use of volatile will actually promote portability for your IO
drivers, co-routines, customizable applications, shared memory using
programs, non-trivial signal handlers, operating systems, etc. Granted,
you don't get complete portability but code needing change will be lot less
and need less work.
--
Bakul Shah

..!{ucbvax,sun}!amdcad!light!bvs

Richard Tobin

unread,
Mar 30, 1988, 3:04:58 PM3/30/88
to
In article <1988Mar29....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>situations. The point is that these are a sufficiently small subset of C
>applications that the need should addressed with #pragma, rather than by
>cluttering up the type system with it. The principal problem with #pragma
>is that it is not portable, since its semantics are not standardized, but
>the sort of code we're talking about isn't portable anyway.

It's true that any particular instance of the use of such constructs isn't
portable, but the concept behind it is. That is, of course code that
manipulates a memory-mapped device register (or similar) won't run on
different machines, but that doesn't mean that it's unreasonable to have
a standard way of expressing that a location is such a register.

Furthermore, #pragma isn't even portable between different compilers on
the same machine, whereas something like "volatile" is. And it's
increasingly common to have more than one C compiler available.

-- Richard
--
Richard Tobin, JANET: R.T...@uk.ac.ed
AI Applications Institute, ARPA: R.Tobin%uk.a...@nss.cs.ucl.ac.uk
Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin

Eddie Wyatt

unread,
Mar 30, 1988, 5:19:01 PM3/30/88
to
An aside:

> #include <signal.h>
> static sig_atomic_t volatile gotcha;
> static void catch(int signo) { gotcha = 1; }
> int main(void) {
> (void)signal(SIGINT, catch);
> gotcha = 0;
> do; while (!gotcha);
> return (0);
> }

PLEASE, declare the signal handler correctly Mr. Lint :-).

static void catch(int signo, code; struct sigcontext *scp) { gotcha = 1; }

In the pass I've had my signal handle return to random pieces of
code by not having the correct definition. I attributed the
problem of local's of the signal handle being over layed onto the
stack context pointer. The problem was fixed by using the
suggested defination for the signal handle which seems to
confirm the suspicion.

--

Eddie Wyatt e-mail: e...@ius1.cs.cmu.edu

Eric Bergan

unread,
Mar 30, 1988, 7:41:22 PM3/30/88
to
In article <12...@PT.CS.CMU.EDU>, j...@K.GP.CS.CMU.EDU (John Myers) writes:
>
> Is R. Stallman's reading of the ANSI draft wrong, or isn't it
> necessary to declare automatic variables as 'volatile' in order to
> guarantee that their values will be preseved across a setjmp/longjmp?
> (as otherwise they could be placed in registers)
>
> If RMS is right, then the committee botched setjmp/longjmp.

I'm jumping into the middle of this argument, so please forgive
me if this has been already stated.

I think there are more serious problems with setjmp/longjmp
than just the volatile issues of variables. There is also the problem
of common subexpressions kept in temporary registers spanning the
setjmp call. While perhaps far-fetched, it is possible to think of
expressions consisting solely of automatic variables that are provably
non-aliased, so that they would not be invalidated by a procedure
call (such as setjmp), and common subexpressions of these that might
be kept in registers, for use inside the body of the setjmp block.

Clearly, when longjmp jumps into this, these temporary registers
will probably no longer contain the expected subexpressions, and the
code within the setjmp block will fail.

My guess is that some kind of declaration of setjmp itself
is necessary, to let the compiler know that nothing can be trusted
across this function call. Either that, or a true exception handling
mechanism for C that doesn't completely invalidate modern optimizers.

Darin Johnson

unread,
Mar 30, 1988, 8:15:12 PM3/30/88
to

For a real life example... There are quite a few languages in VMS that
have a 'volatile' keyword as a language extension. I have actually
needed to use something like this to do the following (synopsis):

volatile int op_cnt;
.
.
void read_ast(.....) {
.
.
op_cnt += z;
.
.
}

.
.
sys$qio(.., read_ast, ..); /* sys$qio will call read_ast() asynchronously */
.
.
/* now do some expression involving op_cnt, pass it to a function,
take its address(!), etc. */

If the word volatile is removed, I could not get consistent results
when optimization was turned on. This was because op_cnt can get
changed at anytime, even between an add and a store instruction.
If I explicitly turned off optimization (it is on by default) then
everything would start working fine. Of course, the above code is
bad programming, but you should get the general idea.

A #pragma could be used instead, but if any sort of similar asynchronous
routines get put into a standard (POSIX or otherwise) then 'volatile' will
have to be used instead of '#pragma' to make the code portable (or
else require '#pragma volatile' to be in every compiler you want to
port to).
--
Darin Johnson (...ucbvax!sun!sunncal!leadsv!laic!darin)
(...lll-lcc.arpa!leadsv!laic!darin)
All aboard the DOOMED express!

00704a-Liber

unread,
Mar 30, 1988, 8:33:29 PM3/30/88
to
In article <91...@tut.cis.ohio-state.edu> l...@tut.cis.ohio-state.edu (Lawrence V. Cipriani) writes:
|I might not understand volatile correctly but this might also be an
|example:
|
| volatile int customer_changeable_var = 0;
|
| main( )
| ...
|
| if (customer_chageable_var != 0)
| {
| ...
| }
|
|If the volatile were dropped off, the compiler would be free to
|optimize out the "impossible" code.

The compiler would *not* be free to optimize out this code!! Because
customer_changeable_var is EXTERNAL to main(), this optimization cannot
occur. The fact that it is declared 'volatile' is irrelevant (unless you
are saying that the customer should be able to change the variable directly
by toggling a hardwired switch which is directly mapped to the memory
location at which customer_changeable_var is stored. But this case is
non-portable, and the previously posted arguments apply).

Chris Torek

unread,
Mar 30, 1988, 8:57:17 PM3/30/88
to
In article <12...@PT.CS.CMU.EDU> j...@K.GP.CS.CMU.EDU (John Myers) writes:
>Is R. Stallman's reading of the ANSI draft wrong, or isn't it
>necessary to declare automatic variables as 'volatile' in order to
>guarantee that their values will be preseved across a setjmp/longjmp?

[\S => section symbol; |word| => C-style text)

p. 119, \S 4.6.2.1, The |longjmp| function

All accessible objects have values as of the time |longjmp| was
called, except that the values of objects of automatic storage
duration that do not have |volatile| type and have been changed
between the |setjmp| invocation and |longjmp| call are indeterminate.

As it bypasses the usual function call and return mechanisms,
... However, if the |longjmp| function is invoked from a nested
signal handler (that is, from a function invoked as the result of
a signal raised during the handling of another signal), the behavior
is undefined. [This answers another recent question.]

On p. 118 (\S 4.6.1.1, The |setjmp| macro), however, we see that

The |setjmp| macro shall be implemented as a macro, not as an
actual function. If the macro definition is suppressed in order
to access an actual function, the behavior is undefined.

No reason is given here for this requirement (which, incidentally,
makes it technically illegal NOT to |#define setjmp| as something, even
if it is just as |_setjmp|), but it would make sense if it were
intended as a constraint on the *programmer* so that |<setjmp.h>| could
say, e.g.,

#define setjmp(env) _builtin_setjmp(env)

which would allow the compiler to implement this as a builtin, and
thus to `fix' all local automatic variables, so that the constraint
in \S 4.6.2.1 need not apply.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: ch...@mimsy.umd.edu Path: uunet!mimsy!chris

David Collier-Brown

unread,
Mar 30, 1988, 10:04:29 PM3/30/88
to

In article <1988Mar25....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
| Interrupt routines are almost by definition esoteric, not to mention highly
| machine-specific.

In article <597@tuvie> rc...@tuvie.UUCP (D. Weickert) writes:
| Signal handlers will be at least very similar to interrupt routines. Still it
| does not seem to be esoteric to me, if I set a flag in such a handler. And now
| please tell me, how to tell the compiler it must not `optimize' the access to
| this flag?

Well, they're interrupt-like in style, but not always in nature. It
is probably true that some machine and operating system somewhere on
this net has signals which run asynchronously to the rest of the
program, but in general they are executed in the normal context of
a C program, as a (simulated, perhaps) subroutine call and strictly
synchronously with the rest of the program. The CP/M machine I'm
using to write this posting from has signal handlers and dispatchers
in the great majority of its C programs: written by Drew Sullivan
(drew@lethe) many moons ago.

And you don't, therefore have to do anything to the said flag
variable. Except make it accessable.
--
David Collier-Brown. {mnetor yunexus utgpu}!geac!daveb
Geac Computers International Inc., | Computer Science loses its
350 Steelcase Road,Markham, Ontario, | memory (if not its mind)
CANADA, L3R 1B3 (416) 475-0525 x3279 | every 6 months.

Tom Neff

unread,
Mar 31, 1988, 1:00:44 AM3/31/88
to
In article <77200028@uiucdcsp> gil...@uiucdcsp.cs.uiuc.edu writes:
>C is not a multiprocessor systems programming language. I'm sorry for
>you multiprocessor programmers. My advice to you is to buy
>hypercubes, write in assembly language, or develop your own language.

Thank you very much, Don! You have taken the manly step of writing off
"C" as an operating systems language. Don't tell the Unix programmers,
though, they might take it to heart. :-)


--

Tom Neff

Barry Margolin

unread,
Mar 31, 1988, 1:09:37 AM3/31/88
to
In article <91...@tut.cis.ohio-state.edu> l...@tut.cis.ohio-state.edu (Lawrence V. Cipriani) writes:
> volatile int customer_changeable_var = 0;
>
> main( )
> ...
>
> if (customer_chageable_var != 0)
> {
> ...
> }
>If the volatile were dropped off, the compiler would be free to
>optimize out the "impossible" code. A customer changeable global
>variable is a handy way for implementing optional features that
>customers may or may not want; especially in programs that should
>avoid disk i/o.

I don't think volatile is necessary for the above example. If another
module were linked with this, and it included an "extern int
customer_changeable_var" declaration, it could assign a different
value to this variable. This is possible because you didn't specify
"static" in your declaration, and it is a global variable. The
compiler, therefore, cannot assume that this variable has a constant
value just because it doesn't see any assignments in this module.

If you were add the "static" modifier to the declaration, the compiler
WOULD be free to optimize away the unreachable code. But that's OK,
because in order for the customer to change the variable's value he
would have to edit the source and recompile the module.

The only other case, and maybe this is what you are talking about, is
if the module you are describing is part of the kernel, and the
variable is intended to be updated by patching the core image. In
that case, if you declare it static then you do, indeed, need the
volatile modifier, but if you don't declare it static you don't have
to declare it volatile, either, because of the reason in my first
paragraph.

Henry Spencer

unread,
Mar 31, 1988, 2:14:24 AM3/31/88
to
> Signal handlers will be at least very similar to interrupt routines. ... it
> does not seem to be esoteric to me, if I set a flag in such a handler. ...
> ... how to tell the compiler it must not `optimize' the access to
> this flag?

It is very difficult to say much about what signal handlers can do safely.
Essentially the *one* thing that X3J11 guarantees is that they can set a
flag of type sig_atomic_t, an implementation-defined type that can have
any desired magic properties.

Doug Gwyn

unread,
Mar 31, 1988, 5:41:50 AM3/31/88
to
In article <12...@PT.CS.CMU.EDU> e...@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>static void catch(int signo, code; struct sigcontext *scp) { gotcha = 1; }

This Berkeley extension does not conform to the standard,
which states that the signal handler has precisely one argument
(of type int). The extension is benign on some architectures but
definitely not on all.

P.S. Yes, X3J11 discussed this issue at some length, and decided
to uphold established practice instead of switching to the Berkeley
invention.

ELIN Forsch.z.

unread,
Mar 31, 1988, 6:40:34 AM3/31/88
to
>With shared memory, again, volatile is the least of your problems.

With signal handling, it may be one of your main problems. (The same may
be with `errno', if you can't declare it volatile.)

Dietmar Weickert,
ALCATEL-ELIN Research Center, Vienna, Austria.

Eddie Wyatt

unread,
Mar 31, 1988, 8:22:34 AM3/31/88
to

>You need a hell of a lot more than "volatile" to properly
>synchronize concurrent processes.

However, your synchronization primatives may use shared mem that requires
the volatile semantics. One example is spin locks.

David Wolverton

unread,
Mar 31, 1988, 9:40:45 AM3/31/88
to
In article <77200028@uiucdcsp>, gil...@uiucdcsp.cs.uiuc.edu writes:
[stuff deleted about multiprocessing]
> THE ONLY reason to keep it [volatile] in the language is if you can argue it's
> important for uniprocessing....

[I think this discussion is getting sidetracked. The question is whether
the volatile type qualifier should have been included in the ANSI C (draft)
standard.]

As an implementor of an optimizer, I rejoiced when I saw that the committee
had added 'volatile' to the language.

The point of volatile is that 98% of a program's variables (and 99% in portable
programs) will *not* be qualified with 'volatile', which allows optimizers
to make assumptions about the optimizations which can be applied to a variable.
Without 'volatile', the optimizer has to use a pessimistic assumption about
the variables so that it won't stomp on the 1-5% of the variables which care
about it!

'volatile' is *not* present to help any specific thing like interrupt handlers,
multiprocessing, shared memory, etc. Rather, it helps them all, because its
*absence* in "normal" code tells the optimizer that none of those funky things
are happening behind its back. That is why 'volatile' is in the language.

Dave Wolverton
AT&T

Henry Spencer

unread,
Mar 31, 1988, 11:52:41 AM3/31/88
to
> Well, in all fairness I could easily live with #pragma volatile(foo) instead,
> *IF* compiler writers actually bothered to code the pragmas...

If they don't, don't buy their compilers!

Dave Cornutt

unread,
Mar 31, 1988, 11:58:59 AM3/31/88
to
In article <77200028@uiucdcsp> gil...@uiucdcsp.cs.uiuc.edu writes:
> C is not a multiprocessor systems programming language. I'm sorry for
> you multiprocessor programmers. My advice to you is to buy
> hypercubes, write in assembly language, or develop your own language.

One of the reasons C exists is to replace assembly language in many
applications.

> We don't yet understand how to program multiprocessors well, or even
> if shared-memory multiprocessing is the wave of the future.

Shared memory is not confined to multiprocessors; it's useful on
uniprocessors too. And it's not something in the far future;
it exists now, in both the SysV and BSD implementations of Unix
(although neither one is really spiffy), and in VMS, Amigados,
OS/2 I think, and probably a bunch more OS'es that I don't know
about. Although the calls to set up the shared memory spaces on
these systems are not portable, the use of the resulting space
should be, since it's just a memory space. C will lose out if
it fails to support these uses.

> You can get what you want by adding a compiler-specific (#pragma type)
> extension, with no loss of generality.

On the contrary, all generality is lost. If it is made a pragma, vendors
will not be required to support it, and no specific syntax will be required
of those that do.

> THE ONLY reason to keep it in the language is if you can argue it's
> important for uniprocessing.

Here's a list of some of the things that you can't do properly on an
optimizing compiler without it:

signal catching
coroutines
device drivers
any kind of asynchronous event handler

These are common things right now. What you're suggesting is that these
should not be considered conforming programs, because they use OS features
that are not portable to another OS. Unfortunately, if you provide no
standardized way to do volatiles, then you not only can't port this code
to a different machine, you probably can't even port it to a different
conforming compiler ON THE SAME MACHINE! Not only that, but you might
not even be able to port it to a different version of the SAME compiler!

An optimizing compiler without a volatile primitive cannot properly
compile a Unix kernel (or any other).

--
Dave Cornutt, AT&T Bell Labs (rm 4A406,x1088), Holmdel, NJ
UUCP:{ihnp4,allegra,cbosgd}!hotly!dkc
"The opinions expressed herein are not necessarily my employer's, not
necessarily mine, and probably not necessary"

Henry Spencer

unread,
Mar 31, 1988, 12:02:22 PM3/31/88
to
> > static void catch(int signo) { gotcha = 1; }
>
> PLEASE, declare the signal handler correctly Mr. Lint :-).

He did. Page 120 of the X3J11 draft: void (*func)(int). Any provision
for additional parameters is a non-standard extension. Any *requirement*
for additional parameters is a major mistake.

Chris Torek

unread,
Mar 31, 1988, 12:57:26 PM3/31/88
to
-In article <91...@tut.cis.ohio-state.edu> l...@tut.cis.ohio-state.edu
-(Lawrence V. Cipriani) writes:
-> volatile int customer_changeable_var = 0;
-> if (customer_chageable_var != 0)
->[without something like volatile] the compiler would be free to
->optimize out the "impossible" code.

In article <18...@think.UUCP> bar...@think.COM (Barry Margolin) writes:
-I don't think volatile is necessary for the above example.

and in article <42...@ihlpf.ATT.COM> nev...@ihlpf.ATT.COM (00704a-Liber)
writes:
-The compiler would *not* be free to optimize out this code!! Because
-customer_changeable_var is EXTERNAL to main(), this optimization cannot
-occur.

lvc is right; barmar and nevin1 are wrong. Remember, compilation
need not take place until after everything is linked together.
Admittedly there are few (possibly no) compilers which would make
this `optimisation' today. I expect this to change in the near
future.

Karl Heuer

unread,
Mar 31, 1988, 1:51:16 PM3/31/88
to
In article <12...@PT.CS.CMU.EDU> e...@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>> static void catch(int signo) { gotcha = 1; }
>PLEASE, declare the signal handler correctly Mr. Lint :-).

I did. Note that I was writing a "strictly conforming program".

>static void catch(int signo, code; struct sigcontext *scp) { gotcha = 1; }
>
>In the pass I've had my signal handle return to random pieces of
>code by not having the correct definition.

Yeah, I've also been bitten occasionally by bugs in Berzerkeley code.

Chip Salzenberg

unread,
Mar 31, 1988, 2:33:59 PM3/31/88
to
In article <1988Mar29....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>Nobody is saying that the concept is not necessary in certain specialized
>situations.
>[...] the sort of code we're talking about isn't portable anyway.

What about signal handlers?

/* begin example */

volatile int hit = 0;

int foo();

main()
{
signal(SIGINT, foo);
while (!hit)
;
exit(0);
}

foo()
{
++hit;
}

/* end example */

Without volatile, you can't protect this program from being over-optimized.

>"Noalias must go. This is non-negotiable." --DMR
Definitely.
--
Chip Salzenberg "ch...@ateng.UU.NET" or "codas!ateng!chip"
A T Engineering My employer's opinions are a trade secret.
"Anything that works is better than anything that doesn't."

Walter Bays

unread,
Mar 31, 1988, 3:06:01 PM3/31/88
to
In article <77200028@uiucdcsp> gil...@uiucdcsp.cs.uiuc.edu writes:
>C is not a multiprocessor systems programming language. I'm sorry for
>you multiprocessor programmers. My advice to you is to buy
>hypercubes, write in assembly language, or develop your own language [...]

>You can get what you want by adding a compiler-specific (#pragma type)
>extension, with no loss of generality. [...]

>THE ONLY reason to keep it in the language is if you can argue it's
>important for uniprocessing. [...]

I agree that C is a poor language for multiprocessors, though I'd
probably choose Ada over assembler. I'm not concerned with
multiprocessors. I am concerned with a C compiler that can generate
highly optimized code for 95% of application programs without fear of
generating incorrect code for systems programs, or for 5% of programs
with dangerous use of pointers and signals. Yes, a #pragma would work
just fine. So would a 'cc -Passed_Lint', but it would be nice if the
same mechanism worked on any UNIX machine, and great if it also worked
on non-UNIX machines. You're right that, for standards, simpler is
better (another reference to Ada :-). Maybe this is a POSIX issue
rather than a C issue.
--
------------------------------------------------------------------------------
Any similarities between my opinions and those of the
person who signs my paychecks is purely coincidental.
E-Mail route: ...!pyramid!garth!walter
USPS: Intergraph APD, 2400 Geng Road, Palo Alto, California 94303
Phone: (415) 852-2384
------------------------------------------------------------------------------

Eddie Wyatt

unread,
Mar 31, 1988, 4:51:50 PM3/31/88
to

>>> static void catch(int signo) { gotcha = 1; }
>>PLEASE, declare the signal handler correctly Mr. Lint :-).
>
>I did. Note that I was writing a "strictly conforming program".
>
>>static void catch(int signo, code; struct sigcontext *scp) { gotcha = 1; }
>>
>>In the pass I've had my signal handle return to random pieces of
>>code by not having the correct definition.
>
>Yeah, I've also been bitten occasionally by bugs in Berzerkeley code.

It's questionable whether its a bug or not. The Sun man page reads:

The handler routine can be declared:

handler(sig, code, scp)
int sig, code;
struct sigcontext *scp;


What bothers me about this entry is it doesn't say you have to
declare the function that way. There's no entry in the BUGS
section eluding to what happen if you don't conform either.

Lawrence V. Cipriani

unread,
Mar 31, 1988, 5:08:09 PM3/31/88
to
In article <18...@think.UUCP> bar...@fafnir.think.com.UUCP (Barry Margolin) writes:
>In article <91...@tut.cis.ohio-state.edu> l...@tut.cis.ohio-state.edu (Lawrence V. Cipriani) writes:
>> ... my small example of using volatile ...

>>
>>If the volatile were dropped off, the compiler would be free to
>>optimize out the "impossible" code. ...

> ... Notes on use of static ...
>Barry Margolin

You are right. Try this instead:

volatile static customer_changeable_var = 0;

main()
...blah blah blah...

if (customer_changeable_var != 0)
{
...code for optional feature...
}

This would be in a compiled program a customer could edit with adb
or sdb. If the compiler were free to optimize out the "impossible"
code this would no longer work. Thanks for the note.

--
Larry Cipriani, AT&T Network Systems and Ohio State University
Domain: l...@tut.cis.ohio-state.edu
Path: ...!cbosgd!osu-cis!tut.cis.ohio-state.edu!lvc (weird but right)

Henry Spencer

unread,
Apr 1, 1988, 6:31:29 PM4/1/88
to
> My guess is that some kind of declaration of setjmp itself
> is necessary, to let the compiler know that nothing can be trusted
> across this function call...

If you inspect the X3J11 rules about setjmp carefully, you will see a
set of restrictions aimed at making it easy for compilers to recognize
it as a special case. Optimizing compilers undoubtedly will. Non-
optimizing compilers will simply have to be a bit conservative. This
is not a disaster.

The current rules about automatic variables *are* a bit of a disaster,
but nobody in his right mind will implement them (and some of us are
going to try to get them changed). The traditional rule, that only
explicitly-register variables are unsafe after longjmp, is adequate:
any compiler that is smart enough to promote things into registers
without being asked is smart enough to notice the setjmp and take
precautions.

Stephen J. Friedl

unread,
Apr 2, 1988, 2:44:12 AM4/2/88
to
In article <3...@aiva.ed.ac.uk>, ric...@aiva.ed.ac.uk (Richard Tobin) writes:
> [ talking here about #pragma volatile(foo) ]

> It's true that any particular instance of the use of such constructs
> isn't portable, but the concept behind it is. That is, of course code that
> manipulates a memory-mapped device register (or similar) won't run on
> different machines, but that doesn't mean that it's unreasonable to have
> a standard way of expressing that a location is such a register.
>
> Furthermore, #pragma isn't even portable between different compilers on
> the same machine, whereas something like "volatile" is. And it's
> increasingly common to have more than one C compiler available.

There has been incredible volume of widely varying opinion
in this newsgroup about /noalias/, which many consider BY ITSELF
to be an evil thing. On the other hand, the only objections to
/volatile/ I have seen have been "Yes, it is handy but so tied to
nonportable code that it is not worth making a change to C to
handle it."

X3J11 has the unenviable task of striking a balance between:

(A) hands off except for matter-of-life-or-death changes
and
(B) let's turn C into ADA.

I generally tend to the (A) side of the fence, but if a
significant and diverse body of really smart people come up with
compelling technical reasons for a feature that doesn't break
existing code, I listen. If my only countering argument is a
general "KYFHO" then perhaps it is time to compromise on this
one.

Steve

P.S. - Give it up, Henry :^)

--
Steve Friedl V-Systems, Inc. *Hi Mom*
fri...@vsi.com {uunet,ihnp4}!vsi.com!friedl attmail!friedl

gor...@sneaky.uucp

unread,
Apr 2, 1988, 2:33:00 PM4/2/88
to

> The |setjmp| macro shall be implemented as a macro, not as an
> actual function. If the macro definition is suppressed in order
> to access an actual function, the behavior is undefined.
> No reason is given here for this requirement (which, incidentally,
> makes it technically illegal NOT to |#define setjmp| as something, even
> if it is just as |_setjmp|), but it would make sense if it were
> intended as a constraint on the *programmer* so that |<setjmp.h>| could
> say, e.g.,
> #define setjmp(env) _builtin_setjmp(env)

I interpret the requirement that setjmp be implemented as a macro as
requiring that you cannot (portably) take the address of setjmp, and
put it in a function pointer. Therefore, the compiler may assume that
all calls through function pointers are NOT calls to setjmp. Further, you
can make the compiler recognize all calls to setjmp, by doing things
like:

# define setjmp(env) (_builtin_setjmp(env) + 0)

where the +0 ensures that &setjmp draws an error message, and the name
_builtin_setjmp is recognized by the compiler and makes it flush out
common subexpressions, etc.


Gordon Burditt
...!ihnp4!sys1!sneaky!gordon

Stan Friesen

unread,
Apr 3, 1988, 5:21:14 PM4/3/88
to
In article <41...@ihlpf.ATT.COM> nev...@ihlpf.UUCP (00704a-Liber,N.J.) writes:
>
> 'Volatile', however, IS part of the
>language specification. I consider it to be a 'frill' because nothing else
>in the language specification addresses hardware, per se.

But 'volatile' does NOT address *hardware*, it addresses asynchronous
change is a value, which *may* be due to hardware, or to the execution of a
logically asynchronous control thread(either a seperate process or a control
thread in a single process such as a signal handler). It is needed often enough
that I think it makes a meaningful addition to the language.

Stan Friesen

unread,
Apr 3, 1988, 5:31:51 PM4/3/88
to
In article <25...@geac.UUCP> da...@geac.UUCP (David Collier-Brown) writes:
>
>
>In article <597@tuvie> rc...@tuvie.UUCP (D. Weickert) writes:
>|Signal handlers will be at least very similar to interrupt routines. Still it
>|does not seem to be esoteric to me, if I set a flag in such a handler. And now
>|please tell me, how to tell the compiler it must not `optimize' the access to
>|this flag?
>
>Well, they're interrupt-like in style, but not always in nature. It
>is probably true that some machine and operating system somewhere on
>this net has signals which run asynchronously to the rest of the
>program, but in general they are executed in the normal context of
>a C program, as a (simulated, perhaps) subroutine call and strictly
>synchronously with the rest of the program.

You and I seem to have a different definition of asynchronous! When I
use the term I mean that the timing of two routines in the system are
indeterminate relative to one another, *not* that only one is executing at any
given time. Yes most signal handlers are run as simulated subroutines in the
user context, BUT these pseudo-routines may be "called" at *any* time, such as
between a load and a store instruction. The programmer has no idea where the
'main' path will be executing when the handler is activated. THIS is what makes
handlers asynchronous, and what makes volatile necessary.

> And you don't, therefore have to do anything to the said flag
>variable. Except make it accessable.

Only if you do not use the -O flag! With optimization on the compiler
may decide that it has already loaded a value into a register and use the
cached value instead of loading fresh from the real variable. In the case
of a flag set by a signal handler this is *wrong*, since the handler may
have been called between the original load and the ultimate store. So
you do have to declare such variable'volatile', at least if you wish a
verifiably correct program.

John Mashey

unread,
Apr 4, 1988, 1:11:48 AM4/4/88
to
(Cross-posted to unix.wizards: see comments at ned)

In article <1988Mar30.1...@light.uucp> b...@light.UUCP (Bakul Shah) writes:
>You must be able to tell a compiler that certain variables have side
>effects *IF* you are using a highly optimizing compiler and you do one or
>more of the following:
(a good list)

I've just been catching up with this. Let's try some data in place of theory.

1) I grepped both UMIPS kernels (BSD & V). Each has about 200
"volatile" declarations. Most of this was in device drivers, but
there were a few other places.

2) Did we do this for fun? NO. We just couldn't globally optimize huge
pieces of the kernel, until:
a) Our compiler team put in volatile, and until
b) We got volatile to act completely right. [nontrivial]

We [the OS group] had just BARRELS of fun when we turned on -O
before volatile was right. Every device driver, and various other
things broke. This was 2 years ago, and I've mercifully forgotten
many of the details, but I still remember this one (a structure
not unusual in drivers):

/* touch device until ready */
register struct device_stuff *p; int junk;

while (p->status != READY)
junk = p->control; /* or something like that */

The first time we tried that, the optimizer generated a single
fetch of p->status [and never went back]. Then we declared
p volatile , and at least the loop was there, but the compiler
had noticed junk was never used, so it eliminated junk from any
of its tables, and that wiped out the whole reference
inside the loop....until the optimizer got fixed to be very, very
careful to make exactly the right number of memory references
for volatile variables [no more, no less].

3) With volatile, it is relatively easy to import device drivers,
usually by declaring all of the pointers to device structures to be
(volatile *), and still be able to use a serious global optimizer.
Otherwise, good luck. Hopefully, more drivers will start being written
with volatile declarations.

4) It is easy enough to #define volatile away if you need to deal
with a compiler that doesn't support it. I suppose there's some
way to do this with a #pragma, volatile seems cleaner.

5) Perhaps UNIX kernel code is "an unusual case". I'd be curious if
there is anyone out there, who:
a) Globally optimizes their UNIX kernels, including drivers, but
b) Uses something other than volatile. (how?)
--
-john mashey DISCLAIMER: <generic disclaimer, I speak for me only, etc>
UUCP: {ames,decwrl,prls,pyramid}!mips!mash OR ma...@mips.com
DDD: 408-991-0253 or 408-720-1700, x253
USPS: MIPS Computer Systems, 930 E. Arques, Sunnyvale, CA 94086

Chris Torek

unread,
Apr 4, 1988, 1:20:51 AM4/4/88
to
[This article was reported as truncated; if you have seen it before, skip it]

Peter da Silva

unread,
Apr 4, 1988, 10:44:27 AM4/4/88
to
In article <77200028@uiucdcsp>, gil...@uiucdcsp.cs.uiuc.edu writes:
> I believe that you sincerely need this feature, but I also sincerely
> believe that most people won't need it. In top-quality standards
> work, you learn to leave out the nonessentials. Others can put them
> in at their own discretion.

You need volatile to efficiently implement device drivers.

Given this, and assuming that you actually do want to write your drivers
in something other than assembly, volatile is necessary.
--
-- Peter da Silva `-_-' ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

Kevin Braunsdorf

unread,
Apr 4, 1988, 6:11:39 PM4/4/88
to
What I'm going to try to explain here is what *I think* the ANSI C group
is trying to provide via "const" "volatile" "noalias", and a better
model that I use.

First I will explain *my* model: what I want to do here is define a set
of type qualifiers that work in theory to specify all the things an
optimizer needs to know to optimize a language like C.

The three main type qualifiers are:
exclusive ordinary volatile

which may be further qualified by:
null read write rmw

{yeah, I know `read' and `write' are important UNIX system calls...
just for the sake of argument keep reading, and put down the soap box :-)}

I define them thus:

A type qualifier on a type tells the compiler something about how
the current context should treat the data that is of that type. It
may also imply how other contexts may be (possibly concurrently)
accessing the same data. It may imply that no other context can be
accessing the data.

A type qualifier "exclusive" tells the compiler that the current
context is the *only* context that can access the data at hand. In
addition, it further promises that this data is only accessible through
the "exclusive" qualified name {path}.

A type qualifier of "ordinary" tells the compiler that the current
context has all active names for the data, and that they all have the
same unqualified type. No other context may read or write to this data
while this context has control (relinquish control only with data synced).

A type qualifier of "volatile" tells the compiler that the current
context is *not* the only context that can see this data, some other
context may have a name for this data, or there may be another name for
this data in this context that may have another (unrelated) type.

Any type qualifier may be followed by an access limiter:

Access of "null": this data may not be read or written, but its address may be
used in address computation.

Access of "read": this data may only be read.

Access of "write": this data may only be written.

Access of "rmw": this data may be read, or written.

The default access limiter is "rmw".

Thus
ANSI mine
---- ----
const ordinary read
noalias exclusive [rmw]
noalias const exclusive read
volatile volatile [rmw]
volatile const volatile read

Now, how may data move around? I won't insult your intelligence with the
rules for access limiters: you cannot assign to something limited for
read only....

But assuming you pass the access limiter constraint the rest of the
type qualifier can safely be ignored for simple data movement:

exclusive int ei;
volatile int vi;
ordinary int oi;

ei = vi = oi; /* all OK. */

The only rules we need to look at now are the rules for creating and
asigning pointers to qualified types:

There are only nine legal combinations:

- a pointer to an exclusive {type} may be passed as a parameter, or
assigned by initialization to a pointer to an exclusive {type}.

- a pointer to an ordinary {type} may be passed as a parameter, or
assigned by initialization, or assigned via the assignment operator
to a pointer to an ordinary {type}.

- a pointer to an ordinary {type} may be passed as a parameter, or
assigned by initialization, or assigned via the assignment operator
to a pointer to a volatile {type}.

- a pointer to an volatile {type} may be passed as a parameter, or
assigned by initialization, or assigned via the assignment operator
to a pointer to a volatile {type}.

- a pointer to a rmw limited {type} may be passed as a parameter, or
assigned by initialization, or assigned via the assignment operator
to a pointer to a read limited {type}.

- a pointer to a rmw limited {type} may be passed as a parameter, or
assigned by initialization, or assigned via the assignment operator
to a pointer to a write limited {type}.

- a pointer to a rmw, read, or write limited {type} may be passed
as a parameter, or assigned by initialization, or assigned via the
assignment operator to a pointer to a null limited {type}.

No other pointer combinations are legal. Attempts to remove access
limitations or change qualifications on object should result in stern
admonishments from the compiler.

{ Note that all constants should be "ordinary read" by default... }

It is obvious from these rules that one needs to be able to specify the
access limiter and type qualifier on any constant: otherwise it is not
possible to initialize a pointer to an exclusive int... or a pointer to
a rmw int (so what else is new in C: one can't do that now).

....

There is much more to talk about WRT this topic: let me simply state
that the ANSI solution doesn't address all the issues involved in
this complex topic.

- does exclusive apply if I move the pointer? warning?
- does a volatile pointer imply volatile indirection?
- how much optimization does this allow that I couldn't do anyway?
- how hard to implement?
- maintain this kind of code?
- ~90% programming, or ~50% programming?
- why are we bothering?

If anyone is interested enough in more discussion of this we should do
it via mail, Please.

Thanks for all you time:
Kevin Braunsdorf pur-ee!ksb or k...@j.cc.purdue.edu
K Project pur-ee!gawk!klang

00704a-Liber

unread,
Apr 4, 1988, 7:41:47 PM4/4/88
to

Ane I quote from section 3.5.3 of the standard:

"Examples

An object declared

extern const volatile int real_time_clock;

may be modifilable by hardware, but cannot be assigned to,
incremented, or decremented."

"[footnote] 52. A volatile declaration may be used to describe an
object corresponding to a memory-mapped input/output port or an
object accessed by an asynchronously interrupting function. [...]"

Although what you say about asynchronous functions are true, I still
maintain that 'volatile' does indeed address hardware. I do believe that
there is a need for a 'do_not_optimize' keyword (at least in non-strict
conforming programs); why call it volatile when we really mean
do_not_optimize??
--
_ __ NEVIN J. LIBER ..!ihnp4!ihlpf!nevin1 (312) 510-6194
' ) ) "The secret compartment of my ring I fill
/ / _ , __o ____ with an Underdog super-energy pill."
/ (_</_\/ <__/ / <_ These are solely MY opinions, not AT&T's, blah blah blah

00704a-Liber

unread,
Apr 4, 1988, 7:47:20 PM4/4/88
to
In article <19...@winchester.mips.COM> ma...@winchester.UUCP (John Mashey) writes:
>(Cross-posted to unix.wizards: see comments at ned)

>In article <1988Mar30.1...@light.uucp> b...@light.UUCP (Bakul Shah) writes:
> a) Our compiler team put in volatile, and until
> b) We got volatile to act completely right. [nontrivial]

In other words, you implemented 'volatile' to conform with the final
definition in the ANSI standard?? What powers of prediction you have!! :-)
What are you going to do if volatile doesn't act quite the way you defined
it when your compiler team put in volatile??

00704a-Liber

unread,
Apr 4, 1988, 8:02:19 PM4/4/88
to
I've got a question on 'volatile'. In the following code fragment:

/*...*/
extern volatile int foo;
int bar;
int int_function();
/*...*/
bar = foo++ + int_function();
/*...*/

how is foo incremented? Is the value saved when it is read for the
addition, the value 1 added to it, and stored back in foo? Is foo just
incremented whenever the compiler would normally increment a post-increment
non-volatile variable? Is this just an error that a compiler should flag.
I've looked in the standard for the answer and I can't find one.

Pablo Halpern

unread,
Apr 4, 1988, 8:11:46 PM4/4/88
to
In article <1988Mar29....@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>... The principal problem with #pragma
>is that it is not portable, since its semantics are not standardized, but

>the sort of code we're talking about isn't portable anyway.

Not true. Volatile was invented to solve some of the problems associated
with multiprocessing or multitasking. These problems surface even in
programs that do no interprocess communication if they use the signal()
fuction which exists in the standard library. A signal handler is very
similar to a separate task that shares memory with the main-line program.
Any variable that might be changed by a signal handler should be declared
volatile since it may change at any time on receipt of a signal. If
it is not declared volatile, the main-line program may continue to use
an old cached value long after the variable has changed, potentially
going into an endless loop waiting for it to change. Similar situations
occure with setjmp()/longjmp().

From article <41...@ihlpf.ATT.COM>, by nev...@ihlpf.ATT.COM (00704a-Liber):
> setjmp() is a function call (in much the same way as fork(), exec(),
> exit(), etc.) and is not part of the language specification itself (it is
> not in section 3 of the draft standard). Same is true about side effects of
> functions of dangerous pointers. 'Volatile', however, IS part of the


> language specification. I consider it to be a 'frill' because nothing else
> in the language specification addresses hardware, per se.

This is also true of signal() but without volatile, signal() could not
be written. I see nothing wrong with having language features that support
the library definition. After all, the purpose of this whole process is
to design a language that supports the writing of programs.

FLAME ON
I'm also sick of people implying that any program that is not
strictly conforming is totally non-portable. I write a lot of
programs that are portable to a large number of machines but
are not portable to ALL machines. I also write a lot of programs
that have small, self-contained, sections that handle non-portable
things like shared memory allocation, interupt handling, semaphores,
etc.. Volatile would allow me to keep these sections small and
isolated because the program could "admit" that it might be
running in a multi-tasking environment. As it is, I'm already
playing it a bit dangerous when it comes to signal handlers.

If volatile were a #pragma, then every compiler could choose its
own syntax and semantics for it, if it were implemented at all.
Even among Unix systems, code that used volatile would not be
portable! Then maybe IEEE would have to get into the act and
define a superset of ANSI C (called POSIX C?) which specifies
a standard syntax for the volatile #pragma. Ugg!
FLAME OFF

Volatile must stay, noalias must go!

Pablo Halpern | mit-eddie \
Polygen Corp. | princeton \ !polygen!pablo (UUCP)
200 Fifth Ave. | bu-cs /
Waltham, MA 02254 | stellar /

Art Boyne

unread,
Apr 5, 1988, 10:43:27 AM4/5/88
to
As regards the "volatile" discussion:

There are many of us out here who use C in other than
Un*x applications. For example, C is now the language
of choice in this division of Hewlett-Packard for all
firmware going into instruments. The existing C compiler
doesn't support the keyword "volatile" but does support
a compiler directive $AMNESIA ON$, which gives somewhat
the same effect. This directive is used in a lot of
sources that deal directly with the hardware; without it,
we get the optimize-into-oblivion behavior described
in the base note.

For all of us in nitty-gritty land, lets hear it for
volatile!

Art Boyne, hplabs!hplvly!boyne

Henry Spencer

unread,
Apr 5, 1988, 5:30:59 PM4/5/88
to
> What about signal handlers?

I'm only gonna say this one more time: just about the only fully portable
thing a signal handler can do is set a flag. Not just any flag, but a
flag of type sig_atomic_t, defined in <signal.h> in an ANSI C implementation.
Since sig_atomic_t can be as magic as necessary, volatile isn't *really*
needed here. (I concede that it is useful in some classes of semi-portable
code.)

John Mashey

unread,
Apr 6, 1988, 1:10:11 AM4/6/88
to
In article <42...@ihlpf.ATT.COM> nev...@ihlpf.UUCP (00704a-Liber,N.J.) writes:
>In article <19...@winchester.mips.COM> ma...@winchester.UUCP (John Mashey) writes:
>> a) Our compiler team put in volatile, and until
>> b) We got volatile to act completely right. [nontrivial]

>In other words, you implemented 'volatile' to conform with the final
>definition in the ANSI standard?? What powers of prediction you have!! :-)
>What are you going to do if volatile doesn't act quite the way you defined
>it when your compiler team put in volatile??

Change it, of course. However:
1) During standards efforts, if you're either involved with the efforts,
or talk to people who are, it's not that hard to get a sense of:
a) A feature is pretty well-understood, at least in intent,
and you think that the syntax is going to be left alone, even if
the descriptive material gets tuned.
b) A feature is close, but there may well still be some tweaking.
c) A proposed feature is causing outright battles.

2) In late 1985, it was pretty clear that volatile seemed in category a),
or at worst, b), but certainly not c). It did not take precognitive
abilities to be able to take a chance on implementing it.

3) The difficulties in getting it right were not in understanding what
it meant, or worrying about how it was supposed to act, they were in
implementing a well-understood intent inside an aggressive optimization
system in a sensible way, when this is a mechanism not otherwise included,
and when meeting volatile's intent required inhibiting more optimizations
than obvious on first glance.
There is of course a very simple way to do it if necessary: if anything
says volatile, treat the entire C module as though all variables are
volatile other than automatics. This would meet the letter of the spec.
Actually, we also have a -volatile option that says "keep the optimization,
but assume nonlocals are all volatile". This is very convenient when
first importing some code. Then you go thru and put in volatile declarations,
and delete the -volatile option.

ag...@urbsdc.urbana.gould.com

unread,
Apr 6, 1988, 3:04:00 PM4/6/88
to

>Interrupt routines are almost by definition esoteric, not to mention highly
>machine-specific. Only on PCs do users commonly write their own interrupt
>routines; in more modern environments [MSDOS is a Neanderthal operating
>system, its only saving grace being some of the nifty applications that run
>on it] such things generally are confined to the bowels of the operating
>system, where they belong.

Strongly disagree. A decent signal interface should be comparable to
an interrupt routine. Too often is asynchronous communication neglected
in favour of synchronous IPC.


Andy "Krazy" Glew. Gould CSD-Urbana. 1101 E. University, Urbana, IL 61801
ag...@gould.com - preferred, if you have MX records
ag...@xenurus.gould.com - if you don't
...!ihnp4!uiucuxc!ccvaxa!aglew - paths may still be the only way

My opinions are my own, and are not the opinions of my employer, or any
other organisation. I indicate my company only so that the reader may
account for any possible bias I may have towards our products.

Karl Heuer

unread,
Apr 6, 1988, 5:58:28 PM4/6/88
to
In article <-63852956@sneaky> gor...@sneaky.UUCP writes:
># define setjmp(env) (_builtin_setjmp(env) + 0)
>where the +0 ensures that &setjmp draws an error message

It doesn't work that way. "&setjmp" (more generally, any use of a function-
-like macro without a left parenthesis) will not be recognized as a macro and
hence no substitution will take place. (This feature allows you to take the
address of putchar, for example, even if it's implemented as a macro.) So you
might as well use "#define setjmp(env) __builtin_setjmp(env)" and let the
linker complain about the unresolved symbol "setjmp".

Chip Salzenberg

unread,
Apr 7, 1988, 7:51:24 AM4/7/88
to
In article <42...@ihlpf.ATT.COM> nev...@ihlpf.UUCP (00704a-Liber,N.J.) writes:
>Although what you say about asynchronous functions are true, I still
>maintain that 'volatile' does indeed address hardware. I do believe that
>there is a need for a 'do_not_optimize' keyword (at least in non-strict
>conforming programs); why call it volatile when we really mean
>do_not_optimize??

"Prior art."

Besides, I'm sure you use "creat" despite its poorly chosen name. :-)

Wayne A. Throop

unread,
Apr 7, 1988, 10:58:24 AM4/7/88
to

> he...@utzoo.uucp (Henry Spencer)

> I'm only gonna say this one more time: just about the only fully portable
> thing a signal handler can do is set a flag. Not just any flag, but a
> flag of type sig_atomic_t, defined in <signal.h> in an ANSI C implementation.

This reminds me of an issue I'd thought of before. If the only portable
thing that receipt of a signal can provoke is the setting of a flag, why
doesn't ANSI specify signal catching routines where the user can specify
SIG_DFL, SIG_IGN, or the address of a flag of type sig_atomic_t?

The current non-portable, more general routines could be kept as "common
extensions", but the more portable thing would be required.

--
Everyone can be taught to scilpt: Michelangelo would have had to be
taught how not to. So it is with the great programmers.
--- Alan J. Perlis
--
Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw

Ned Nowotny

unread,
Apr 7, 1988, 7:24:26 PM4/7/88
to
Many people have claimed that "volatile" is necessary for a variety of
applications. Every one of which has been successfully written at one
time or another. Does this mean that all these signal handlers,
interrupt handlers, etc. are written in assembly or some other language?
I suppose it also means that those which are written in K&R C are
incorrect... Uh... completely unoptimizable. (To -O or not to -O...)

In fact, why is it assumed that silent optimaztion of poorly (or,
perhaps, correctly) written code is desirable? Just because a compiler
can be made smart enough to move a loop invariant out of a loop does not
mean that it is a good idea. It makes more sense to just provide the
programmer with a warning. If the code is incorrect, the programmer
learns something valuable. If it is correct, the programmer may save
himself (or herself) a frustrating bout of debugging.

Optimizers should not do optimazations which can be expressed in the
source language itself. However, if they recognize a possibly
poor construct, they should warn the programmer. (At least until
automatic code generators can be made better programmers than your
typical Unix wizard.)

--

Ned Nowotny (n...@ghostwheel.aca.mcc.com.UUCP)

Pablo Halpern

unread,
Apr 7, 1988, 8:51:00 PM4/7/88
to
Sorry if you got this twice, but I think my original posting got lost ...

William E. Davidsen Jr

unread,
Apr 8, 1988, 10:41:34 AM4/8/88
to
I never thought I'd be defending the ANSI committee, but I have seen
several postings recently which cast some undeserved doubt on the
workings of the committee.

Please note that I am NOT commenting on the technical points involved,
simply the statements which infer collusion of vendors.

>In article <77...@alice.UUCP>, d...@alice.UUCP writes:
> ... notes on volatile ...
>
> Has anyone else noticed that a lot of the more peculiar things that X3J11
> has added (volatile, and especially noalias) are there for the
> benefit of compiler writers and benchmarkers, and not for the user?
> (I know how it happens, though; after all, I invented 'register.')

>From: l...@tut.cis.ohio-state.edu (Lawrence V. Cipriani)
>Subject: Re: volatile isn't necessary, but it's there
>Summary: abs() belongs in <math.h>
>Date: 7 Apr 88 23:51:56 GMT
>...
>Flame on: Of all the stupid things I read in the draft this takes the
>cake. Why don't the vendors fix their stupid compilers and leave the
><math.h> users alone! Come on! abs() is a math function and <math.h>
>is where it belongs!
>Flame off:
>...
>Future language standardizations should have more representation by
>users, and this should be required by ANSI. We've been had one too
>many times.

>Subject: Re: volatile isn't necessary, but it's there
>Date: 7 Apr 88 16:15:33 GMT
>Reply-To: gw...@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>)
>...
>As I suspect Dennis knows, by far the majority of the X3J11 committee
>are C implementors or at least represent the interests of C implementors.
>The "user advocates" sometimes have an uphill battle, especially on
>issues that are perceived as affecting the marketability of C compilers.
>...

I hate to put my neck out, but I was there. I was representing GE Corp
R&D Center for the first two years of the standards work (until out T&L
budget got cut), and it wasn't like that.

For some time I was the sole non-vendor member, and I did have to
bring up a number of points on behalf of the user. A the rest of the
committee listened! These people use C, too, and they want it to be a
good language standard.

There were times when a change was proposed, and someone would explain
what it took to implement, and the change would be dropped. Not because
it was "too hard" to do it, but because the result would be to big and
slow to run on smaller computers. That's a valid point, and there were
only a few of these issues.

I feel that I was able to present my user-only point of view, but
really, I don't think the standard would have been much diferent if I
hadn't been there. All this sniping about the vendors doing this and
that to the detriment of the users is I'll considered, and in my mind
detracts from the strength of the technical points being made.

{ descend from soapbox to cheers of crowd }
--
bill davidsen (we...@ge-crd.arpa)
{uunet | philabs | seismo}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

Neal Weidenhofer

unread,
Apr 8, 1988, 1:28:30 PM4/8/88
to
In article <42...@ihlpf.ATT.COM>, nev...@ihlpf.ATT.COM (00704a-Liber) writes:
> I've got a question on 'volatile'. In the following code fragment:
>
> /*...*/
> extern volatile int foo;
> int bar;
> int int_function();
> /*...*/
> bar = foo++ + int_function();
> /*...*/
>
> how is foo incremented? Is the value saved when it is read for the
> addition, the value 1 added to it, and stored back in foo? Is foo just
> incremented whenever the compiler would normally increment a post-increment
> non-volatile variable? Is this just an error that a compiler should flag.
> I've looked in the standard for the answer and I can't find one.
> --
> _ __ NEVIN J. LIBER ..!ihnp4!ihlpf!nevin1 (312) 510-6194

It's not an error but any of the other possibilities you list are valid.

All that dpANS mandates of a conforming implementation in a case like this
is that: At some time after the last sequence point before the beginning
of the statement and before the sequence point at the end of the statement,
the varaible foo is "read" once and "written" once (whatever this may mean
for a specific implementation.) Or that the results of running the program are
the same as they would be if this were true--the "as if" rule. (N.B. There are
also lots of mandates about the arithmetic, etc. that I don't believe are
relevant to your question.)

Extra disclaimer: Even though I'm a member of the committee, I'm not a
spokesperson for us. The above represents my understanding of our intent.

The opinions expressed above are mine (but I'm willing to share.)

Regards,
Neal Weidenhofer
It's not the earth ...{hplabs|ihnp4|ames|decwrl}!amdahl!nw
The meek inherit, Amdahl Corporation
It's the dirt. 1250 E. Arques Ave. (M/S 316)
P. O. Box 3470
Sunnyvale, CA 94088-3470
(408)737-5007

Henry Spencer

unread,
Apr 8, 1988, 2:42:54 PM4/8/88
to
> ... If the only portable

> thing that receipt of a signal can provoke is the setting of a flag, why
> doesn't ANSI specify signal catching routines where the user can specify
> SIG_DFL, SIG_IGN, or the address of a flag of type sig_atomic_t?

Somehow this doesn't seem worth a new invention. C has no shortage of
tools that one has to use wisely if one wants the programs to be portable
(or, for that matter, to work); signal() is just one more.

00704a-Liber

unread,
Apr 8, 1988, 3:23:51 PM4/8/88
to
In article <1...@ghostwheel.UUCP> n...@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
|Many people have claimed that "volatile" is necessary for a variety of
|applications. Every one of which has been successfully written at one
|time or another. Does this mean that all these signal handlers,
|interrupt handlers, etc. are written in assembly or some other language?
|I suppose it also means that those which are written in K&R C are
|incorrect... Uh... completely unoptimizable. (To -O or not to -O...)

No, what this means is that in the future, when we have highly optimizing
compilers and highly efficient hardware (such as caches,etc.), that this code
may break. In order to do certain types of optimizations, certain assumptions
have to be made. For example, if I know that a certain variable has no
aliases, then in the implementation I can keep it's value in a cache (which
is faster) without having to update the actual memory location it is
suppose to be stored at. As things stand now, these assumptions are made
on a compiler-by-compiler basis.

|In fact, why is it assumed that silent optimaztion of poorly (or,
|perhaps, correctly) written code is desirable? Just because a compiler
|can be made smart enough to move a loop invariant out of a loop does not
|mean that it is a good idea. It makes more sense to just provide the
|programmer with a warning. If the code is incorrect, the programmer
|learns something valuable. If it is correct, the programmer may save
|himself (or herself) a frustrating bout of debugging.

|Optimizers should not do optimazations which can be expressed in the
|source language itself.

Not all optimizations can be 'hand-coded'. For those which can be
hand-coded, however, I would still rather have the compiler do all the work
for me. Hand-optimizing takes a lot of time and usually turns well-wriiten
readable code into something that can be entered in the Obfuscated C Contest
:-).

|However, if they recognize a possibly
|poor construct, they should warn the programmer. (At least until
|automatic code generators can be made better programmers than your
|typical Unix wizard.)

Lint, not C, is suppose to warn the programmer of possibly poor constructs.
Code generators are not better designers (which is what you should be using
your typical Unix wizard for :-)), but they can be better implementers.
:-)


--
_ __ NEVIN J. LIBER ..!ihnp4!ihlpf!nevin1 (312) 510-6194

Stephen J. Friedl

unread,
Apr 8, 1988, 9:58:55 PM4/8/88
to
In article <1...@ghostwheel.UUCP>, n...@ghostwheel.UUCP (Ned Nowotny) writes:
> Optimizers should not do optimazations which can be expressed in the
> source language itself. However, if they recognize a possibly
> poor construct, they should warn the programmer.

Huh? I think this is terribly naive. First, a construct
"source-optimized" for one machine may turn out to be
counterproductive on another machine. The best way to do
pre/post ++ and -- probably varies from one architecture to
another, and surely there are a host of other examples (array
referencing, function calls, etc.)

Second, how far should this be carried? Require traversing
a chunk of data with pointers rather than with an array index?
Require inline |asm| code? Mental data-flow analysis?

Finally, and most importantly, isn't one major goal of a
high-level language to insulate us from those details? Defining
"poor construct" solely from the view of the compiler or CPU
rather than from the view of a human is contrary to this notion;
surely I am not the only one who has sometimes sacrificed
"efficiency" in favor of other issues (readability, portability)
when it was appropriate. Having a smart translation system helps
me get the best of both worlds.

Steve
--
Steve Friedl V-Systems, Inc. "Yes, I'm jeff@unh's brother"
fri...@vsi.com {backbones}!vsi.com!friedl attmail!vsi!friedl

Michael Meissner

unread,
Apr 9, 1988, 12:57:35 PM4/9/88
to
In article <1...@polygen.UUCP> pa...@polygen.uucp (Pablo Halpern) writes:
| Not true. Volatile was invented to solve some of the problems associated
| with multiprocessing or multitasking. ...

Ughhh, let me throw some facts on this issue. Volatile was NOT
originally added for shared memory multiprocessing systems. Around the
ANSI X3J11 meeting in Concord or the meeting before that (around 3-4
years ago), const had been put in from the C++ implementation. At that
time, it was felt that about half of the C programmers in the world were
writing C for the bare iron, ie OS developers, and device controllers
(which some in the committee calls toasters in a pejoritive sense), and
the other half were writing on UNIX. It was for the first set of users
that volatile was invented, since we had many people who for example
wanted to do something silly like run highly optimizing compilers on
their operating system or product without breaking it (once they
identified the critical places). If you look at the current C
programmers, I would suspect the bare iron people are considerably in
the minority, and that MSDOS C programmers have surpased the UNIX C
programmers.
--
Michael Meissner, Data General. Uucp: ...!mcnc!rti!xyzzy!meissner
Arpa/Csnet: meis...@dg-rtp.DG.COM

gil...@uiucdcsp.cs.uiuc.edu

unread,
Apr 9, 1988, 1:22:00 PM4/9/88
to

That's a very good point: Since volatile is so machine/application
specific (do I need it on a stack machine? unlikely!) It may be a
bad idea to nail it down in a particular way. For instance:

1. Do we want volatile to apply to individual variables?
2. Or would the programmer rather have a directive that makes a clump of
variables volatile? After all, it's a pain to make an entire
module "volatile"
3. Perhaps we want to have stretches of code that are "volatile",
(The HP method?) and in other places allow the variables to live in
registers or whatever.
4. I'm sure you can imagine useful applications for the other situations.

Can you honestly predict what these shared-memory multiprocessing guys
really need? Will they have to reimplement the feature themselves?
If so, then the answer is : Do not put it in.

Don Gillies {ihnp4!uiucdcs!gillies} U of Illinois
{gil...@p.cs.uiuc.edu}

Kevin Braunsdorf

unread,
Apr 9, 1988, 2:26:15 PM4/9/88
to
-------

All the members of this union should be tagged as being volatile.

union {
int oi;
char oc;
} u;
int *pi;

pi = & u.oi; /* should be a comment || warning */

You see why they cannot be ordinary in the union?

Another case:
union {
noalias int ei; /* should be a comment || warning */
char oops;
} u2;

the int is not exclusive in the union, it cannot be.

Do we all agree that a volatile is needed here (in unions)?

I'll discuss this through mail with anyone who cares.

kayessbee pur-ee!ksb k...@j.cc.purdue.edu

Henry Spencer

unread,
Apr 9, 1988, 8:24:25 PM4/9/88
to
> ... Too often is asynchronous communication neglected

> in favour of synchronous IPC.

With good reason, since it is much harder to use safely and correctly.
Note that the first thing most operating systems do is to turn the hardware's
asynchronous interrupts into some (at least semi-) synchronous form.

Walter Bays

unread,
Apr 9, 1988, 8:44:20 PM4/9/88
to
In article <43...@ihlpf.ATT.COM> nev...@ihlpf.UUCP (00704a-Liber,N.J.) writes:
>No, what this means is that in the future, when we have highly optimizing
>compilers and highly efficient hardware (such as caches,etc.), that this code
>may break. In order to do certain types of optimizations, certain assumptions
>have to be made. For example, if I know that a certain variable has no
>aliases, then in the implementation I can keep it's value in a cache (which
>is faster) without having to update the actual memory location it is
>suppose to be stored at. As things stand now, these assumptions are made
>on a compiler-by-compiler basis.

I agree. Worse, in many cases the future is now. Usually the
compiler must forgo optimizations that would work for nearly all
programs for fear of breaking a few. And remember, optimization is
more important for RISC than for CISC. C wizards will use 'volatile'
and 'noalias'. Ordinary users may totally ignore them, and will still
get the benefit of faster applications running on faster kernels.
--
------------------------------------------------------------------------------
Any similarities between my opinions and those of the
person who signs my paychecks is purely coincidental.
E-Mail route: ...!pyramid!garth!walter
USPS: Intergraph APD, 2400 Geng Road, Palo Alto, California 94303
Phone: (415) 852-2384
------------------------------------------------------------------------------

David Collier-Brown

unread,
Apr 10, 1988, 4:16:32 PM4/10/88
to
In article <1...@ghostwheel.UUCP> n...@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
| ... Just because a compiler

| can be made smart enough to move a loop invariant out of a loop does not
| mean that it is a good idea. It makes more sense to just provide the
| programmer with a warning. If the code is incorrect, the programmer
| learns something valuable...

Hmmn. I suspect that a source-to-source optimizer might be
worthwhile, expecially one which would annotate the source with
some of its assumptions while doing so.
It probably need not be written to be time- or space-efficent: I'd
take one written in prolong (oops! prolog).

--dave
--
David Collier-Brown. {mnetor yunexus utgpu}!geac!daveb
Geac Computers International Inc., | Computer Science loses its
350 Steelcase Road,Markham, Ontario, | memory (if not its mind)
CANADA, L3R 1B3 (416) 475-0525 x3279 | every 6 months.

Michael Zehr

unread,
Apr 11, 1988, 10:50:02 AM4/11/88
to
In article <77200031@uiucdcsp> gil...@uiucdcsp.cs.uiuc.edu writes:
>
>Can you honestly predict what these shared-memory multiprocessing guys
>really need?

If i understand what is meant by volatile, then there are uses on
regular machines too. For example:
while(!(user_interrupt))
{ /* do nothing */ }

where user_interrupt is a global variable that is changed by an
asynchrous interrupt (from a keyboard, mouse, etc.). I'm running on a
standard vaxstation II, so there's no fancy shared memory going on,
and it's only one process that's executing all the code. I've had
some real problems getting the compiler to do what i want, because it
keeps on wanting to optimize it out of a loop, or into a register, or
something.


-------
michael j zehr
"My opinions are my own ... as is my spelling."

Ray Dunn

unread,
Apr 11, 1988, 1:45:13 PM4/11/88
to
In article <77200028@uiucdcsp> gil...@uiucdcsp.cs.uiuc.edu writes:
>
>C is not a multiprocessor systems programming language. I'm sorry for
>you multiprocessor programmers. My advice to you is to buy
>hypercubes, write in assembly language, or develop your own language.
>
>We don't yet understand how to program multiprocessors well, or even
>if shared-memory multiprocessing is the wave of the future. Please
>don't jump the gun by extending the C language too soon....

Unfortunately, "multiprocessor systems" are more common than you might
think. We are not necessarily talking about esoteric new architectures when
talking multiprocessor.

As an example, there are many PC option cards, especially comms cards, which
are "intelligent", i.e. have a CPU on board. These often share memory with
the host CPU, and have software in two parts, an option card part, and a
host part, which communicate via this shared memory.

It would be nice to continue to program these devices in 'C'!

Ray Dunn. ..{philabs, mnetor)!micomvax!ray

Walter Bright

unread,
Apr 11, 1988, 2:36:05 PM4/11/88
to
In article <1...@ghostwheel.UUCP> n...@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
| ... Just because a compiler
| can be made smart enough to move a loop invariant out of a loop does not
| mean that it is a good idea. It makes more sense to just provide the
| programmer with a warning. If the code is incorrect, the programmer
| learns something valuable...

It's true, most optimizations performed by flow-analysis optimizers can
be done in the source code. The reasons for having the optimizer are:

o The goals of optimized code and clear, maintainable code are
usually not the same. I've spent a lot of time taking clear code
and converting it into code that would win the obfuscated C code
contest in the name of optimization. The optimization goal
succeeded (up to 3 * faster), but the resulting code looked horrible.
So I frequently put in:
#if 1
/* optimized version */
#else
/* original code left as documentation for above */
#endif
for critical routines that need the speed.

o Note the above 'spent a lot of time'. My time is more valuable
than machine time is. Even going through the code and experimenting
with which variables should be 'register' is time I'd rather
spend on my algorithms.

o The results of tuning a program are not portable (the code will
still work, but optimization for one machine may be unoptimization
for another). An example would be the varying number of address,
data and general purpose registers, and the varying styles of
addressing modes available.

o Only a small percentage of programmers understand the compiler
and the underlying hardware well enough to wring the max
performance out of a routine.

o C is frequently machine-generated. It is best to use a straight-forward
C-generation algorithm and let the C optimizer 'fix' it. This
is the approach I've taken in my C++ compiler, and it works well.

o Mopar rules.

mcdo...@uxe.cso.uiuc.edu

unread,
Apr 11, 1988, 8:55:00 PM4/11/88
to

>If you look at the current C
>programmers, I would suspect the bare iron people are considerably in
>the minority, and that MSDOS C programmers have surpased the UNIX C
>programmers.

MS-DOS ---IS--- "bare iron"!

00704a-Liber

unread,
Apr 11, 1988, 9:32:14 PM4/11/88
to
In article <68...@j.cc.purdue.edu> k...@j.cc.purdue.edu.UUCP (Kevin Braunsdorf) writes:
|All the members of this union should be tagged as being volatile.
|
| union {
| int oi;
| char oc;
| } u;
| int *pi;
|
| pi = & u.oi; /* should be a comment || warning */

|You see why they cannot be ordinary in the union?

No. What volatile means is that something besides this program can modify
this variable (such as a hardware interrupt, signal handler, etc.).

der Mouse

unread,
Apr 12, 1988, 4:52:28 AM4/12/88
to
In article <75...@brl-smoke.ARPA>, gw...@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <12...@PT.CS.CMU.EDU> e...@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>> static void catch(int signo, code; struct sigcontext *scp) { gotcha = 1; }
> This Berkeley extension does not conform to the standard,

Which standard? The dpANS? That's question-begging.

> P.S. Yes, X3J11 discussed this issue at some length, and decided to
> uphold established practice instead of switching to the Berkeley
> invention.

Berkeley practice seems pretty firmly established to me. What sort of
OS-centricism is going on here?

der Mouse

uucp: mo...@mcgill-vision.uucp
arpa: mo...@larry.mcrcim.mcgill.edu

Doug Gwyn

unread,
Apr 12, 1988, 10:26:37 AM4/12/88
to
In article <10...@mcgill-vision.UUCP> mo...@mcgill-vision.UUCP (der Mouse) writes:
>In article <75...@brl-smoke.ARPA>, gw...@brl-smoke.ARPA (Doug Gwyn ) writes:
>> In article <12...@PT.CS.CMU.EDU> e...@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>>> static void catch(int signo, code; struct sigcontext *scp) { gotcha = 1; }
>> This Berkeley extension does not conform to the standard,
>Berkeley practice seems pretty firmly established to me.

Far from it; the additional arguments were a fairly recent change in
the Berkeley variant of UNIX; they run counter to the established
definition and implementation of signal() AT THE TIME BERKELEY DECIDED
TO CHANGE THEIR IMPLEMENTATION, and to top it off, the problem of
variadic argument lists wasn't dealt with (because all the world's
a VAX, presumably). Thus Berkeley's approach is simply not suitable
for an OS-independent standard. I wish they would invent new
interfaces when they decide to change things like this.

Henry Spencer

unread,
Apr 13, 1988, 12:40:12 PM4/13/88
to
> Berkeley practice seems pretty firmly established to me. What sort of
> OS-centricism is going on here?

Berklocentrism, and it's you that's doing it. Recent releases of x.yBSD
are the *only* variants of Unix that interface to signal handlers in that
way. Not only that, but it is actively incompatible with the standard
interface ("standard" meaning the /usr/group standard and the SVID -- real
standards -- in addition to widespread existing practice and drafts of X3J11
and POSIX) on any machine that has trouble with varargs functions; the
Berkloids have this wretchedly stupid habit of not giving new interfaces
new names. All the world's a VAX, right? Grr.

Chris Torek

unread,
Apr 13, 1988, 12:42:56 PM4/13/88
to
>> extern volatile int user_interrupt;
>> while (!user_interrupt)
>> sleep(1);

In article <49...@sun.uucp> li...@sun.uucp (Greg Limes) writes:
>Please do not misunderstand me, I would like to see "volatile"
>added -- but why would it be required above? If "user_interrupt"
>is an external variable, then the compiler is not free to assume
>that it will not change across a function call.

The compiler *is* free to make that assumption if it examines the
function and finds that it does not write into user_interrupt.
For instance, if `sleep' is implemented as (say)

typedef unsigned long u_long;
sleep(unsigned n) {
static volatile u_long *const timerp = (u_long *)0xfc000040;
register u_long expect = *timerp + n;
while (*timerp < expect) /*void*/;
}

and the code for sleep is stored in some format that the
compiler can read, then the compiler can see that sleep cannot
change user_interrupt.

The main problem with volatile is that it does not have well-
defined semantics. It *cannot* have well-defined semantics.
Consider a load/store architecture versus a Vax-like architecture.
If I write

volatile char c;
...
c++;

the load/store machine must generate something like

movbl _c,r212
addl #1,r212
movlb r212,_c

which is one read and one write; the Vax-like machine just runs

incb _c

which is one read/modify/write.

The reason volatile exists is because it is a machine-independent
means of specifying something that is inherently machine-dependent
but which affects every implementation that does what might be
called `nonobvious optimisation'. Like the size of `pointer_t'
(void *) or the length of `size_t', volatile is a machine- and
compiler-dependent construct that can be used to give machine-
and compiler-independent results:

#include <atomic.h>

semaphore_t sem;

...
SEM_LOCK(&sem);
...
SEM_UNLOCK(&sem);

where <atomic.h> might say

typedef volatile int semaphore_t;
#define SEM_LOCK(semp) while ((*semp)++) --*(semp)
#define SEM_UNLOCK(semp) --*(semp)

or it might say instead

typedef volatile short semaphore_t;
#define SEM_LOCK(semp) \
while (_builtin_test_and_set(semp)) \
_builtin_atomic_clear(semp)
#define SEM_UNLOCK(semp) _builtin_atomic_clear(semp)

or any of a number of other possibilities.

What `volatile' DOES is machine-dependent. What `volatile'
EXPRESSES (`hands off! this is a weird object!') is not, or
not entirely.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: ch...@mimsy.umd.edu Path: uunet!mimsy!chris

Jerry Whitnell

unread,
Apr 13, 1988, 8:09:48 PM4/13/88
to

I beg to differ. Bare iron is much better the MS-DOS. There are no bugs
to get in your way :-).

Jerry Whitnell Been through Hell?
Communication Solutions, Inc. What did you bring back for me?
- A. Brilliant

ag...@urbsdc.urbana.gould.com

unread,
Apr 14, 1988, 11:33:00 AM4/14/88
to

>> extern volatile int user_interrupt;
>> while (!user_interrupt)
>> sleep(1);
>>
>> Carrick Talmadge c...@newton.physics.purdue.edu

>
>Please do not misunderstand me, I would like to see "volatile"
>added -- but why would it be required above? If "user_interrupt"
>is an external variable, then the compiler is not free to assume
>that it will not change across a function call. Since you call
>sleep() in the loop, the compiler is not free to use the cached value
>of user_interrupt from the previous iteration.
>
>Greg LImes [li...@sun.com]

I have some hope of seeing decent cross-procedural and global analysis
in production C compilers in my lifetime ;-}. In which case, the
compiler may be able to prove that user_interrupt is not modified
by any function called...

So, what do you want: "synchronous volatile" and "asynchronous
volatile"?

ag...@gould.com

It is loading more messages.
0 new messages