1

I understand that the declaration

int *volatile ptr;

means that the pointer itself is volatile

int a=10;
int *volatile ptr=&a;

Now both ptr and a are being updated. Will it cause any potential problems like old value of a being returned when accessing ptr?

To clarify the use case of volatile pointer in my scenario:

  1. To communicate from interrupt context to task context I am passing addresses to circular queue (which is array of pointers) which will be accessed from task context.
  2. The pointers in this queue are declared volatile.
  3. At index x in queue ,pointer y is present which points to variable a.
  4. Now if I write new pointer to queue (example pointer z which points to variable b) at index x in interrupt context.
  5. When I read index x in task context, since queue is declared as volatile, the pointers will not be optimised.

My doubt is since what the pointer is pointing to is not volatile is there a chance that compiler has optimized for index x and on deferencing pointer at index x it will point to variable a instead of variable b

Furqan Qadri
  • 47
  • 1
  • 7
  • 1
    What do you mean "old value of a being returned"? Also, most of the time, it doesn't make any sense to use `*volatile` pointers. The only valid case that exists is when the pointer is actually a hardware index register. But then you would never use `int*`, so this code is just nonsense. – Lundin Apr 10 '18 at 12:44
  • What do you mean by `ptr` being updated? Are you wanting it to point to something else? – Bathsheba Apr 10 '18 at 12:45
  • This seems similar to [this](https://stackoverflow.com/questions/9935190/why-is-a-point-to-volatile-pointer-like-volatile-int-p-useful) – anakin Apr 10 '18 at 12:47
  • @anakin **negative**. The location of the star is significant here. – Antti Haapala -- Слава Україні Apr 10 '18 at 12:53
  • @AnttiHaapala My bad I paid more attention to the answer and not the question I referred to. The answer contains explanation about both scenarios. – anakin Apr 10 '18 at 12:57
  • @Lundin I've seen memory transfer units that return pointers via registers. – Matthias Apr 10 '18 at 13:00
  • If I understand you question correctly, you are asking whether reading values through such a pointer will be atomic operations and won't lead to race condition and related issues, right? – user7860670 Apr 10 '18 at 13:02
  • @lundin I have mentioned the use case of volatile pointers in the update to my question.Also the data type int in question is just for illustrative purpose. – Furqan Qadri Apr 10 '18 at 13:39

3 Answers3

2

If both ptr and the int that ptr points to are updated by a different thread or by your hardware, you have to declare ptr like this:

int volatile * volatile ptr=&a;

Or:

volatile int * volatile ptr=&a;

Typically in embedded programming, as @Lundin points out, the adresses don't change, so this is sufficient:

volatile int * ptr=&a;

Or:

int volatile * ptr=&a;
Matthias
  • 1,296
  • 8
  • 17
  • If either ptr and the int that ptr points to are updated by a different threads then there will be a potential race condition regardless of `volatile` use. – user7860670 Apr 10 '18 at 13:07
2

int* volatile only means that the pointer itself is volatile. The pointed-at data is not volatile-qualified, meaning that the following scenario may cause optimizer bugs:

int a=10;
int* volatile ptr=&a;

int main()
{
  for(;;)
  {
    printf("%d\n", *ptr);
  }
}

void some_ISR (void)
{
  a = something;
}

The compiler is careful not to assume that ptr does not point at the same address every lap in the loop, but apart from that it is free to assume: "aha, after reading ptr it is still pointing at a I see. It has not been updated and I know it is 10". In theory the compiler is free to generate machine code such as this pseudo:

val = *ptr

forever
{
  ptr = (update it by reading from memory)
  if ptr != previous
    val =*ptr

  print val        
  previous = ptr
}

Such optimizations may make sense if the compiler can keep the previous value stashed away in a CPU register etc. Suppose it can get rid of a lot of the printf overhead this way, that would be a major optimization.

So, no this does not give you protection against incorrect optimizations. To achieve that, use volatile int* instead. Or if the pointers themselves may also change, volatile int* volatile.


To communicate from interrupt context to task context I am passing addresses to circular queue (which is array of pointers) which will be accessed from task context.

That only makes sense if the pointer itself is changed to point elsewhere by the interrupt. Again, it doesn't mean that the pointed-at data will be updated. But as you write "The pointers in this queue are declared volatile.", you are good, assuming this means that the pointers are volatile* type and not type*volatile.

Unrelated to this whole issue, you also need a protection against non-atomic access of shared variables. volatile does not give that.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • For the example scenario pseudo-code, you have provided ,is it possible and justifiable, that the compiler optimizes ,such that even after (if ptr != previous) is True,compiler does not dereference the ptr? – Furqan Qadri Apr 10 '18 at 16:08
  • @FurqanQadri I don't see how that would be practical - if the address has changed, it makes most sense that the value would have to be updated. In theory, the compiler could make some sort of lookup table where it knows that each pointer address corresponds to a hard-coded value, but in practice I doubt any compiler would do that. – Lundin Apr 11 '18 at 10:03
0

Any use of a through a volatile pointer will make the dereference volatile also (as the value of the pointer is not cached, the dereference must be done anyway) But, the better is to make both uncacheable, so a possible way to implement is:

volatile int a;
volatile int * volatile ptr = &a;

Think twice, as you haven't declared a as volatile, should you have done it you'd get a warning:

pru.c

 #include <stdio.h>
 int main()
 {
    volatile int a;
    int * volatile ptr = &a;
 }

and output

$ make pru
pru.c:5:17: warning: initializing 'int *volatile' with an expression of type 'volatile int *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
    int * volatile ptr = &a;
                   ^     ~~
1 warning generated.

as you see from the warning, the qualifier discarded refers to the pointed value. In case of ptr being declared non-volatile the same warning is issued:

pru2.c

 #include <stdio.h>
 int main()
 {
    volatile int a;
    int * ptr = &a;
 }

and

$ make pru2
cc -O -pipe  pru.c  -o pru
pru.c:5:8: warning: initializing 'int *' with an expression of type 'volatile int *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
        int * ptr = &a;
              ^     ~~
1 warning generated.
Community
  • 1
  • 1
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • On a sane compiler, the fact that the pointer is volatile would cause the reference to be likewise, but the fact that a sane compiler would do something is no guarantee that gcc or clang will do so. A conforming compiler given `extern int * volatile vp; int x=*vp; int y=*vp;` could generate code equivalent to `int *t1 = vp; x= *t1; int *t2 = vp; y = (t1==t2) ? x : *t2;` The likelihood of such "optimization" offering any performance benefits seems much smaller than the likelihood of it breaking code that expects sane `volatile` behavior, but the authors of gcc and clang... – supercat Jun 07 '18 at 22:52
  • ...seem to invest more effort in "clever" optimizations than in avoiding things like redundant register moves. – supercat Jun 07 '18 at 22:53