Where all to use volatile keyword in C - c

I know volatile keyword prevents compiler from optimizing a variable and read it from memory whenever it is read. Apart from memory mapped registers, what are all the situations where we need to use volatile? Given a conforming compiler, do I have to declare test_var as volatile in both scenarios?
1.
In file1.c
int test_var=100;
void func1()
{
test_var++;
}
In file2.c
extern int test_var;
void func2()
{
if(test_var==100)
{
....
}
}
2.
In file1.c
int test_var=100;
void func1()
{
}
In file2.c
extern int test_var;
void func2()
{
if(test_var==100)
{
....
}
}

memory mapped I/O is the only generic use of volatile in C. *)
With POSIX signals, a volatile can also be used together with the type sig_atomic_t like this:
volatile sig_atomic_t signal_occured = 0;
Neither of your scenarios should require volatile at all. If all you're interested in is a guarantee that the value is updated between different compilation units, see tofro's comment, extern already guarantees that. Particularly, volatile is not the correct tool for thread synchronization in C. It would only introduce bugs, because, as you state it, it does require actual read and write accesses to the variable, but it does not enforce their proper ordering with respect to threads (it's missing memory barriers, google for details).
Note that this is different from some other languages where volatile is designed to work between threads.
In an embedded system, volatile might be good enough for communicating between an ISR (interrupt service routine) and the main program, when combined with a data type that's read/written atomically, just like sig_atomic_t for POSIX signals. Consult the documentation of your compiler for that.
*) The C standard mentions this, along with the use-case of "asynchronously interrupting functions", only in a footnote, because memory-mapped I/O is outside the scope of the language. The language just defines the semantics of volatile in a way that make it suitable for memory-mapped I/O.

In neither of your examples is volatile necessary.
volatile is necessary:
anywhere a variable may be changed outside of the control of a single thread of execution,
anywhere the variable access is required to occur even when it semantically has no effect.
Case 1 includes:
memory mapped I/O registers,
memory used for DMA transfers,
memory shared between interrupt and/or thread contexts,
memory shared between independent processors (such as dual port RAM)
Case 2 includes:
loop counters used for empty delay loops, where the entire loop may otherwise be optimised away completely and take no time,
Variables written to but never read for observation in a debugger.
The above examples may not be exhaustive, but it is the semantics of volatile that are key; the language only has to perform an explicit access as indicated by the source code.

Besides extensions such as memory mapped devices, in standard C volatile has two use cases: interaction with signal handlers and modification of objects across usage of setjmp/longjmp. Both are case were there is unusual flow of control that an optimizer may not be aware of.

In C microcontroller applications using interrupts, the volatile keyword is essential in making sure that a value set in an interrupt is saved properly in the interrupt and later has the correct value in the main processing loop. Failure to use volatile is perhaps the single biggest reason that timer-based interrupts or ADC (analog-digital conversion) based interrupts for example will have a corrupted value when flow of control resumes after the processor state is returned post-interrupt. A canonical template from Atmel and GCC:
volatile uint8_t flag = 0;
ISR(TIMER_whatever_interrupt)
{
flag = 1;
}
while(1) // main loop
{
if (flag == 1)
{
<do something>
flag = 0;
}
}
Without the volatile it's guaranteed to not work as expected.

Apart from memory mapped registers, what are all the situations where
we need to use volatile?
If
execution is purely sequential (no threads and no signals delivered asynchronously);
you don't use longjmp;
you don't need to be able to debug a program compiled with optimizations;
you don't use constructs with vaguely specified semantics like floating point operations;
you don't do useless computations (computations where the result is ignored) as in a benchmark loop;
you don't do timings of any pure computations, that is anything that isn't I/O based (I/O based such as timings of accesses of network requests, external database accesses)
then you probably have no need for volatile.

Related

How to write strictly conforming interrupt service routines (on AVR)

The C Standard mandates that a signal handler may access only objects of type sig_atomic_t (besides lock-free atomics). Accesses to objects of other types produce UB. An interrupt service routine resembles a signal handler, so this restriction must be obeyed when writing ISRs.
avr-libc's signal.h is broken in that it does not declare type sig_atomic_t, though it does declare a variable of that name, of type volatile signed char. Presumably, that was meant to be a typedef.
But if you want an ISR to access, say, a systick counter of type uint32_t then that would produce UB.
Are there any special precautions / exceptions from the standard that avr-gcc imposes, so that it would be possible to write a strictly conforming ISR?
How to write strictly conforming interrupt service routines (on AVR)
As you tagged the question avr-gcc, I'll assume GCC1 in the remainder. It's not possible to do it in a performing way due to 2 reasons:
There is no way to write an ISR in a conforming way. avr-gcc uses attributes to implement this.
avr-gcc implements neither atomic types nor atomic builtins (where the latter are compiler specific of course, so you can ignore them for conforming discussion). Even if avr-gcc implemented atomic types, using libatomic would be considered inappropriate due to its resource consumption by most AVR folks. And even the simple atomic accesses that could be performed by the compiler without resorting to lib code are not implemented. Take for example:
int var;
_Atomic int aaa;
int get_var_atomic (void)
{
int v;
__atomic_load (&var, &v, __ATOMIC_SEQ_CST);
return v;
}
int get_var_atomic_n (void)
{
return __atomic_load_n (&var, __ATOMIC_SEQ_CST);
}
int get_aaa (void)
{
return aaa;
}
All three functions will forward to __atomic_load_2, which does not exists (as of avr-gcc v13), and respective insns don't exist, either. Or more precisely: there are generic versions in libatomic, but bachend avr has libatomic disabled.
So the closest you can do is to use these primitives to implement atomic magic, and also to provide these functions. By its very nature, these functions cannot be inlined. So the only reasonable approach is to implement this in the compiler backend itself, which is somewhere in ./gcc/config/avr/avr.md2,3.
1 Hence avr-gcc or avr-g++ and AVR-LibC. Dunno how the situation is for other compiler brands like IAR.
2 You can use the vanilla non-atomic loads and stores code emitters, but you'll have to get an 8-bit tmp reg Rx so you can
in Rx, SREG
cli
<vanilla-code>
out SREG, Rx
for the simple cases. __tmp_reg__ can't be used here for obvious reasons.
3 I just got ranted for globally switching off IRQs. So if you want to avoid that, you'll have to go the libatomic way and allocate semaphores. No need so say that this is extremely expensive compared to the usual approaches.

Is it good practice to make a global variable always volatile?

I know which is the meaning of volatile. I need to ask that if my variable is global, is it good practise to make it volatile, even i dont use interface with hardware.
Header:
typedef struct
{
int Value;
}Var_;
extern volatile Var_ myVariable;
Source:
volatile Var_ myVariable;
No. If you’re writing multi-threaded code, you want to use atomic variables, not volatile. For example, many concurrent structures need to be kept consistent, not modified one word at a time.
If no other thread, process or hardware is modifying the variable, you should not use either atomics or volatile. It will just complicate the program, run slower, and disable certain APIs for no reason.
The volatile keyword has historically been used for a few different things (such as telling the compiler not to optimize away a delay loop), but its purpose in C11 is narrow: to specify that a value in memory will change by some means that doesn’t follow the rules of atomics. You need it to write some kinds of device drivers, but it’s discouraged even in other low-level code such as OS kernels.
No, it is not good practice. volatile informs the C implementation (largely the compiler) that an object may be changed by something outside of the C implementation or that accesses to the object within the C implementation may have desired effects outside the C implementation. As long as your global object is only used and modified inside your own program, it has no volatile effects, and declaring it with volatile causes the compiler to suppress optimization and to generate unnecessary accesses to it within your program.

C optimization of extern global variables

In case I have a C file that uses an extern declared variable
and in the code the variable is modified and then an external function is called.
will the compiler optimization take into account the possibility that the variable can be touched by the function? so it won't change the C code order and make sure the variable is set in memory before the function is called?
You need to be careful of a number of things... but in a basic C application with a single thread, yes... this should be fine.
If, however you are (non-exhaustive):
Using multiple threads
Using shared memory between a number of processes
Running on a low-level system (e.g: AVR / STM32) and handling the variable in the an interrupt handler and under main()
Handling the variable in a signal handler and under main()
Reading memory / registers that are modified by hardware / DMA
Then you'll need to be careful.
The volatile keyword can be useful - it will inform the compiler that "this variable may change while you're not looking".
Even with the volatile keyword though, you may run into the Read-Modify-Write problem...
Knowing about the Read-Modify-Write problem is half the fight... the other half is mitigating it, which can be achieved by a number of optiosn such as using a technique called Mutual Exclusion / Critical Sections, or if appropriate by copying the data into a local variable before you operate on the value.

Volatile and its harmful implications

I am a embedded developer and use volatile keyword when working with I/O ports. But my Project manager suggested using volatile keyword is harmful and has lot of draw backs, But i find in most of the cases volatile is useful in embedded programming, As per my knowledge volatile is harmful in kernel code as the changes to our code will become unpredictable. There are any drawbacks using volatile in Embedded Systems also?
No, volatile is not harmful. In any situation. Ever. There is no possible well-formed piece of code that will break with the addition of volatile to an object (and pointers to that object). However, volatile is often poorly understood. The reason the kernel docs state that volatile is to be considered harmful is that people kept using it for synchronization between kernel threads in broken ways. In particular, they used volatile integer variables as though access to them was guaranteed to be atomic, which it isn't.
volatile is also not useless, and particularly if you go bare-metal, you will need it. But, like any other tool, it is important to understand the semantics of volatile before using it.
What volatile is
Access to volatile objects is, in the standard, considered a side-effect in the same way as incrementing or decrementing by ++ and --. In particular, this means that 5.1.2.3 (3), which says
(...) 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 (including any caused by calling a function or accessing a volatile object)
does not apply. The compiler has to chuck out everything it thinks it knows about the value of a volatile variable at every sequence point. (like other side-effects, when access to volatile objects happens is governed by sequence points)
The effect of this is largely the prohibition of certain optimizations. Take, for example, the code
int i;
void foo(void) {
i = 0;
while(i == 0) {
// do stuff that does not touch i
}
}
The compiler is allowed to make this into an infinite loop that never checks i again because it can deduce that the value of i is not changed in the loop, and thus that i == 0 will never be false. This holds true even if there is another thread or an interrupt handler that could conceivably change i. The compiler does not know about them, and it does not care. It is explicitly allowed to not care.
Contrast this with
int volatile i;
void foo(void) {
i = 0;
while(i == 0) { // Note: This is still broken, only a little less so.
// do stuff that does not touch i
}
}
Now the compiler has to assume that i can change at any time and cannot do this optimization. This means, of course, that if you deal with interrupt handlers and threads, volatile objects are necessary for synchronisation. They are not, however, sufficient.
What volatile isn't
What volatile does not guarantee is atomic access. This should make intuitive sense if you're used to embedded programming. Consider, if you will, the following piece of code for an 8-bit AVR MCU:
uint32_t volatile i;
ISR(TIMER0_OVF_vect) {
++i;
}
void some_function_in_the_main_loop(void) {
for(;;) {
do_something_with(i); // This is thoroughly broken.
}
}
The reason this code is broken is that access to i is not atomic -- cannot be atomic on an 8-bit MCU. In this simple case, for example, the following might happen:
i is 0x0000ffff
do_something_with(i) is about to be called
the high two bytes of i are copied into the parameter slot for this call
at this point, timer 0 overflows and the main loop is interrupted
the ISR changes i. The lower two bytes of i overflow and are now 0. i is now 0x00010000.
the main loop continues, and the lower two bytes of i are copied into the parameter slot
do_something_with is called with 0 as its parameter.
Similar things can happen on PCs and other platforms. If anything, more opportunities it can fail open up with a more complex architecture.
Takeaway
So no, using volatile is not bad, and you will (often) have to do it in bare-metal code. However, when you do use it, you have to keep in mind that it is not a magic wand, and that you will still have to make sure you don't trip over yourself. In embedded code, there's often a platform-specific way to handle the problem of atomicity; in the case of AVR, for example, the usual crowbar method is to disable interrupts for the duration, as in
uint32_t x;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
x = i;
}
do_something_with(x);
...where the ATOMIC_BLOCK macro calls cli() (disable interrupts) before and sei() (enable interrupts) afterwards if they were enabled beforehand.
With C11, which is the first C standard that explicitly acknowledges the existence of multithreading, a new family of atomic types and memory fencing operations have been introduced that can be used for inter-thread synchronisation and in many cases make use of volatile unnecessary. If you can use those, do it, but it'll likely be some time before they reach all common embedded toolchains. With them, the loop above could be fixed like this:
atomic_int i;
void foo(void) {
atomic_store(&i, 0);
while(atomic_load(&i) == 0) {
// do stuff that does not touch i
}
}
...in its most basic form. The precise semantics of the more relaxed memory order semantics go way beyond the scope of a SO answer, so I'll stick with the default sequentially consistent stuff here.
If you're interested in it, Gil Hamilton provided a link in the comments to an explanation of a lock-free stack implementation using C11 atomics, although I don't feel it's a terribly good write-up of the memory order semantics themselves. The C11 model does, however, appear to closely mirror the C++11 memory model, of which a useful presentation exists here. If I find a link to a C11-specific write-up, I will put it here later.
volatile is only useful when the so qualified object can change asynchronously. Such changes can happen
if the object is in fact an hardware IO register or similar that has changes external to your program
if the object might be changed by a signal handler
if the object is changed between calls to setjmp and longjmp
in all these cases you must declare your object volatile, otherwise your program will not work correctly. (And you might notice that objects shared between different threads is not in the list.)
In all other cases you shouldn't, because you may be missing optimization opportunities. On the other hand, qualifying an object volatile that doesn't fall under the points above will not make your code incorrect.
Not using volatile where necessary and appropriate is far more likely to be harmful! The solution to any perceived problems with volatile is not to ban its use, because there are a number of cases where it is necessary for safe and correct semantics. Rather the solution is to understand its purpose and its behaviour.
It is essential for any data that may be changed outside of the knowledge of the compiler, such as I/O and dual-ported or DMA memory. It is also necessary for access to memory shared between execution contexts such as threads and interrupt-handlers; this is where perhaps the confusion lies; it ensures an explicit read of such memory, and does not enforce atomicity or mutual exclusion - additional mechanisms are required for that, but that does not preclude volatile, but it is merely part of the solution to shared memory access.
See the following articles of the use of volatile (and send them to your project manager too!):
Place volatile accurately by Dan Saks.
Introduction to the volatile keyword by Nigel Jones
Guidelines for handling volatile variables by Colin Walls
Combining C's volatile and const keywords - Michael Barr
Volatile tells the compiler not to optimize anything that has to do with the volatile variable.
Why the "volatile" type class should not be used? - Best article in Kernel doc
https://www.kernel.org/doc/Documentation/volatile-considered-harmful.txt
volatile is a keyword in c which tell the compiler not to do any kind of optimization on that variable.
Let me give you a simple example:
int temp;
for ( i=0 ;i <5 ; i++ )
{
temp = 5;
}
what compiler will do to make the code optimized :
int temp;
temp = 5; /* assigned temp variable before the loop. */
for ( i=0 ;i <5 ; i++ )
{
}
But if we mention volatile keyword then compiler will not do any kind of optimization in temp variable.
volatile int temp;
for ( i=0 ;i <5 ; i++ )
{
temp = 5;
}
"Volatile Considered Harmful" ---> I don't consider volatile as harmful. You use volatile where you don't want any kind of optimization from compiler end.
For example consider this piece of code is used by a thermometer company and temp is a variable used to take the temperature of the atmosphere which can change anytime. So if we do not use volatile then compiler will do the optimization and the atmosphere temperature will always be same.

What does while(!volatile); do?

I saw this in a part that never gets called in a coworker's code:
volatile unsigned char vol_flag = 0;
// ...
while(!vol_flag);
vol_flag is declared in the header file, but is never changed. Am I correct that this will lead to the program hanging in an infinite loop? Is there a way out of it?
Usually a code like this indicates that vol_flag is expected to be changed externally at some point. Here, externally may mean a different thread, an interrupt handler, a piece of hardware (in case of memory mapped IO) etc. This loop effectively waits for the external event which changes the flag.
The volatile keyword is a way for the programmer to express the fact that it is not safe to assume what is apparent from the code: namely that the flag is not changed in the loop. Thus, it prevents the compiler from making optimizations which could compromise the intentions behind the code. Instead, the compiler is forced to make a memory reference to fetch the value of the flag.
Note that (unlike in Java) volatile in C/C++ does not establish happens-before relationship and does not guarantee any ordering or visibility of memory references across volatile access. Moreover, it does not ensure atomicity of variable references. Thus, it is not a tool for communication between threads. See this for details.

Resources