6

I was wondering if in the following scenario a temporary volatile qualifier would yield correct behavior. Assume an ISR collects values in an array and once enough values have been collected it signals readiness.

int array[10]; // observe no volatile here
int idx = 0;   // neither here
volatile bool ready = false; // but here

Here's the ISR is pseudo-code

ISR() {
  if (idx < 10)
     array[idx++] = ...;
  ready = (idx >= 10);
}

Assume we can guarantee that array will be read only after ready is signalled, and elements are accessed via specific method only:

int read(int idx) {
  // temporary volatile semantics
  volatile int *e = (volatile int*)(array + idx);
  return *e;
}

which seems to be allowed according to cpp-reference

A cast of a non-volatile value to a volatile type has no effect. To access a non-volatile object using volatile semantics, its address must be cast to a pointer-to-volatile and then the access must be made through that pointer.

For completeness the main routine does the following

void loop() {
   if (ready) {
     int val = read(0); // Read value 
     // do something with val.
   }
}

In such a scenario should I expect to read correct values from array or is volatile on the array elements required to guarantee that writing to the array from within ISR() is actually performed in RAM?

Note that Why is volatile needed in C? does not detail whether or not in this special case volatile is needed.

Community
  • 1
  • 1
chrish.
  • 715
  • 5
  • 11
  • `volatile` prevent only compiler optimization. Does not take of variable access. – LPs Oct 28 '16 at 09:02
  • 1
    Possible duplicate of [Why is volatile needed in C?](http://stackoverflow.com/questions/246127/why-is-volatile-needed-in-c) – LPs Oct 28 '16 at 09:10
  • 1
    ISR = Interrupt Service Routine = non=portable anyway. Check your compiler documentation. – MSalters Oct 28 '16 at 09:13

1 Answers1

1

The write to array[] is not through volatile, so you can't rely on that being observable behavior. Yes, the compiler must issue a non-cached read of array, but that is only half of the picture.

You're talking about order as if that's affected by volatile - it isn't.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • But the compiler has to execute the write no matter if the array is volatile or not. There is no way for the compiler to deduct that "this written value is never read so I can skip the write" - it should rather deduct the opposite. Though I suppose that if the array is written in one translation unit and read in another, it might complicate the matter? Suppose the array was declared as `static`, guaranteeing that read/writes must be in the same translation unit? – Lundin Oct 28 '16 at 09:33
  • @Lundin exactly what I was thinking / hoping. The writes have to take place and by forcing volatile reads later on (in a non time critial path of execution) everything would be fine... – chrish. Oct 28 '16 at 09:49
  • @Lundin: By that logic "the compiler also has to execute all reads, there's no way it can detect a new value was written". You're trying to reason `volatile` away. As for `static`, that's insufficient. A compiler would need to do escape analysis to see if a pointer is leaked. – MSalters Oct 28 '16 at 12:27
  • Umm... no? The read in this case definitely has to be executed, because of the volatile qualifiers. If not for that, the compiler would of course be free to skip it. The very question here is if the write becomes mandatory because of the volatile access read. – Lundin Oct 28 '16 at 12:47
  • @Lundin: The analogy was that "If writes must be performed even in the absence of `volatile`, then reads without `volatile` must also be executed.". But no, a `volatile` read does not force a `volatile` write, if only because the `volatile` read might be paired with another `volatile` write in another TU. The compiler cannot assume these two operations are paired. – MSalters Oct 28 '16 at 12:54
  • To get back to my original comment, the compiler can't very well optimize away a write if it can't deduct that the variable isn't used. This is very clear in the C standard: "An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced". The compiler can deduce no such thing here, so if it would optimize away the write, it wouldn't be conforming. Now of course, the compiler might be dumb and not realize that the ISR is executed, in which case the code will break for that reason. – Lundin Oct 28 '16 at 13:06