My code is written in C. I have an ISR (Interrupt Service Routine) that communicates with the main code using global variables. The ISR is in a different compilation unit from the main code.
Is there any reason I cannot use "volatile" for the main code but leave it off in the ISR?
My reasoning is as follows:
The volatile qualifier is preventing the compiler from fully optimizing the ISR. From the ISR's point of view the variable is not volatile - i.e. it cannot be externally changed for the duration of the ISR and the value does not need to be output for the duration of the ISR. Additionally, if the ISR is in its own compilation unit, the compiler MUST have the ISR read the global from memory before its first use and it MUST store changes back before returning. My reasoning for this is: Different compilation units need not be compiled at the same time so the compiler has no idea what is happening beyond the confines of the ISR (or it should pretend to) and so it must ensure that the global is read/written at the boundaries of the ISR.
Perhaps, I am misunderstanding the significance of compilation units? One reference that I found said that GCC has made this volatile mismatch a compile time error; I am not sure how it could, if they are in different compilation units, shouldn't they be independent? Can I not compile a library function separately and link it in later?
Nine ways to break your systems code using volatile
Perhaps an argument could be made from the concept of sequence points. I do not fully understand the concepts of sequence points or side effects; but, the C99 spec states in 5.1.2.3 paragraph 2:
"... At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place."
Annex C, lists sequence points that include:
The call to a function, after the arguments have been evaluated.
Immediately before a library function returns.
Ref:WG14 Document: N1013, Date: 07-May-2003
Note: A previous question, Global Variable Access Relative to Function Calls and Returns asked whether globals are stored/written before/after function calls and and returns. But this is a different question which asks whether a global variable may be differently qualified as "volatile" in different compilation units. I used much of the same reasoning to justify my preliminary conclusions, which prompted some readers to think it is the same question.
ISO/IEC 9899:2011 (the C11 standard) says:
6.7.3 Type qualifiers
¶6 If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.133)
133) This applies to those objects that behave as if they were defined with qualified types, even if they are never actually defined as objects in the program (such as an object at a memory-mapped input/output address).
The second sentence of ¶6 says that you invoke undefined behaviour if you have either of the organizations shown here:
File main.c File isr.c:
volatile int thingamyjig = 37; extern int thingamyjig; // V1
extern int thingamyjig; volatile int thingamyjig = 37; // V2
In each case of V1 or V2, you run foul of the undefined behaviour specified in that section of the standard — though V1 is what I think you're describing in the question.
The volatile qualifier must be applied consistently:
File main.c File isr.c:
volatile int thingamyjig = 37; extern volatile int thingamyjig; // V3
extern volatile int thingamyjig; volatile int thingamyjig = 37; // V4
Both V3 and V4 preserve the volatile-qualifiers consistently.
Note that one valid manifestation of 'undefined behaviour' is 'it behaves sanely and as you would like it to'. Unfortunately, that is not the only, or necessarily the most plausible, possible manifestation of undefined behaviour. Don't risk it. Be self-consistent.
Related
volatile int vfoo = 0;
void func()
{
int bar;
do
{
bar = vfoo; // L.7
}while(bar!=1);
return;
}
This code busy-waits for the variable to turn to 1. If on first pass vfoo is not set to 1, will I get stuck inside.
This code compiles without warning.
What does the standard say about this?
vfoo is declared as volatile. Therefore, read to this variable should not be optimized.
However, bar is not volatile qualified. Is the compiler allowed to optimize the write to this bar? .i.e. the compiler would do a read access to vfoo, and is allowed to discard this value and not assign it to bar (at L.7).
If this is a special case where the standard has something to say, can you please include the clause and interpret the standard's lawyer talk?
What the standard has to say about this includes:
5.1.2.3 Program execution
¶2 Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression in general includes both value computations and initiation of side effects. Value computation for an lvalue expression includes determining the identity of the designated object.
¶4 In the abstract machine, all expressions are evaluated as specified by the semantics. 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).
¶6 The least requirements on a conforming implementation are:
Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.
...
The takeaway from ¶2 in particular should be that accessing a volatile object is no different from something like calling printf - it can't be elided because it has a side effect. Imagine your program with bar = vfoo; replaced by bar = printf("hello\n");
volatile variable has to be read on any access. In your code snippet that read cannot be optimized out. The compiler knows that bar might be affected by the side effect. So the condition will be checked correctly.
https://godbolt.org/z/nFd9BB
However, bar is not volatile qualified.
Variable bar is used to hold a value. Do you care about the value stored in it, or do you care about that variable being represented exactly according to the ABI?
Volatile would guarantee you the latter. Your program depends on the former.
Is the compiler allowed to optimize the write to this bar?
Of course. Why would you possibly care whether the value read was really written to a memory location allocated to the variable on the stack?
All you specified was that the value read was tested as an exit condition:
bar = ...
}while(bar!=1);
.i.e. the compiler would do a read access to vfoo, and is allowed to
discard this value and not assign it to bar (at L.7).
Of course not!
The compiler needs to hold the value obtained by the volatile read enough time to be able to compare it to 1. But no more time, as you don't ever use bar again latter.
It may be that a strange CPU as a EQ1 ("equal to 1") flag in the condition register, that is set whenever a value equal to 1 is loaded. Then the compiler would not even store temporarily the read value and just EQ1 condition test.
Under your hypothesis that compilers can discard variable values for all non volatile variables, non volatile objects would have almost no possible uses.
If I had the folowing declaration:
extern volatile int SOME_REGISTER;
and later on:
void trigger_read_register()
{
SOME_REGISTER;
}
would calling trigger_read_register() issue a read request on SOME_REGISTER ?
According to the C11 spec, accessing a volatile is considered a side effect, and thus the compiler shouldn't optimize the (otherwise useless) access in your example.
So, the answer is that yes, it should read from memory.
See C11 standard (draft), section 5.1.2.3 section 2:
Accessing a volatile object, modifying an object, modifying a file, or
calling a function that does any of those operations are all side
effects, which are changes in the state of the execution
environment. Evaluation of an expression in general includes both
value computations and initiation of side effects. Value computation
for an lvalue expression includes determining the identity of the
designated object.
Further, 4 says:
In the abstract machine, all expressions are evaluated as specified by
the semantics. 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).
I know when a program is run, the main() function is executed first. But when does the initialization of global variables declared outside the main() happens? I mean if I declare a variable like this:
unsigned long current_time = millis();
void main() {
while () {
//some code using the current_time global variable
}
}
Here, the exact time when the global variable initializes is important. Please tell what happens in this context.
Since you didn't define the language you're talking about, I assumed it to be C++.
In computer programming, a global variable is a variable that is accessible in every scope (unless shadowed). Interaction mechanisms with global variables are called global environment (see also global state) mechanisms. The global environment paradigm is contrasted with the local environment paradigm, where all variables are local with no shared memory (and therefore all interactions can be reconducted to message passing). Wikipedia.
In principle, a variable defined outside any function (that is, global, namespace, and class static variables) is initialized before main() is invoked. Such nonlocal variables in a translation unit are initialized in their declaration order (§10.4.9). If such a variable has no explicit initializer, it is by default initialized to the default for its type (§10.4.2). The default initializer value for built-in types and enumerations is 0. [...] There is no guaranteed order of initialization of global variables in different translation units. Consequently, it is unwise to create order dependencies between initializers of global variables in different compilation units. In addition, it is not possible to catch an exception thrown by the initializer of a global variable (§14.7). It is generally best to minimize the use of global variables and in particular to limit the use of global variables requiring complicated initialization. See.
(Quick answer: The C standard doesn't support this kind of initialization; you'll have to consult your compiler's documentation.)
Now that we know the language is C, we can see what the standard has to say about it.
C99 6.7.8 paragraph 4:
All the expressions in an initializer for an object that has static
storage duration shall be constant expressions or string literals.
And the new 2011 standard (at least the draft I has) says:
All the expressions in an initializer for an object that has static
storage duration shall be constant expressions or string literals.
So initializing a static object (e.g., a global such as your current_time) with a function call is a constraint violation. A compiler can reject it, or it can accept it with a warning and do whatever it likes if it provides an language extension.
The C standard doesn't say when the initialization occurs, because it doesn't permit that kind of initialization. Basically none of your code can execute before the main() function starts executing.
Apparently your compiler permits this as an extension (assuming you've actually compiled this code). You'll have to consult your compiler's documentation to find out what the semantics are.
(Normally main is declared as int main(void) or int main(int argc, char *argv[]) or equivalent, or in some implementation-defined manner. In many cases void main() indicates a programmer who's learned C from a poorly written book, of which there are far too many. But this applies only to hosted implementations. Freestanding implementations, typically for embedded systems, can define the program's entry point any way they like. Since you're targeting the Arduino, you're probably using a freestanding implementation, and you should declare main() however the compiler's documentation tells you to.)
Is accessing a non-const object through a const declaration allowed by the C standard?
E.g. is the following code guaranteed to compile and output 23 and 42 on a standard-conforming platform?
translation unit A:
int a = 23;
void foo(void) { a = 42; }
translation unit B:
#include <stdio.h>
extern volatile const int a;
void foo(void);
int main(void) {
printf("%i\n", a);
foo();
printf("%i\n", a);
return 0;
}
In the ISO/IEC 9899:1999, I just found (6.7.3, paragraph 5):
If an attempt is made to modify an object defined with a const-qualified type through use
of an lvalue with non-const-qualified type, the behavior is undefined.
But in the case above, the object is not defined as const (but just declared).
UPDATE
I finally found it in ISO/IEC 9899:1999.
6.2.7, 2
All declarations that refer to the same object or function shall have compatible type;
otherwise, the behavior is undefined.
6.7.3, 9
For two qualified types to be compatible, both shall have the identically qualified
version of a compatible type; [...]
So, it is undefined behaviour.
TU A contains the (only) definition of a. So a really is a non-const object, and it can be accessed as such from a function in A with no problems.
I'm pretty sure that TU B invokes undefined behavior, since its declaration of a doesn't agree with the definition. Best quote I've found so far to support that this is UB is 6.7.5/2:
Each declarator declares one identifier, and asserts that when an
operand of the same form as the declarator appears in an expression,
it designates a function or object with the scope, storage duration,
and type indicated by the declaration specifiers.
[Edit: the questioner has since found the proper reference in the standard, see the question.]
Here, the declaration in B asserts that a has type volatile const int. In fact the object does not have (qualified) type volatile const int, it has (qualified) type int. Violation of semantics is UB.
In practice what will happen is that TU A will be compiled as if a is non-const. TU B will be compiled as if a were a volatile const int, which means it won't cache the value of a at all. Thus, I'd expect it to work provided the linker doesn't notice and object to the mismatched types, because I don't immediately see how TU B could possibly emit code that goes wrong. However, my lack of imagination is not the same as guaranteed behavior.
AFAIK, there's nothing in the standard to say that volatile objects at file scope can't be stored in a completely different memory bank from other objects, that provides different instructions to read them. The implementation would still have to be capable of reading a normal object through, say, a volatile pointer, so suppose for example that the "normal" load instruction works on "special" objects, and it uses that when reading through a pointer to a volatile-qualified type. But if (as an optimization) the implementation emitted the special instruction for special objects, and the special instruction didn't work on normal objects, then boom. And I think that's the programmer's fault, although I confess I only invented this implementation 2 minutes ago so I can't be entirely confident that it conforms.
In the B translation unit, const would only prohibit modifying the a variable within the B translation unit itself.
Modifications of that value from outside (other translation units) will reflect on the value you see in B.
This is more of a linker issue than a language issue. The linker is free to frown upon the differing qualifications of the a symbol (if there is such information in the object files) when merging the compiled translation units.
Note, however, that if it's the other way around (const int a = 23 in A and extern int a in B), you would likely encounter a memory access violation in case of attempting to modify a from B, since a could be placed in a read-only area of the process, usually mapped directly from the .rodata section of the executable.
The declaration that has the initialization is the definition, so your object is indeed not a const qualified object and foo has all the rights to modify it.
In B your are providing access to that object that has the additional const qualification. Since the types (the const qualified version and the non-qualified version) have the same object representation, read access through that identifier is valid.
Your second printf, though, has a problem. Since you didn't qualify your B version of a as volatile you are not guaranteed to see the modification of a. The compiler is allowed to optimize and to reuse the previous value that he might have kept in a register.
Declaring it as const means that the instance is defined as const. You cannot access it from a not-const. Most compilers will not allow it, and the standard says it's not allowed either.
FWIW: In H&S5 is written (Section 4.4.3 Type Qualifiers, page 89):
"When used in a context that requires a value rather than a designator, the qualifiers are eliminated from the type." So the const only has an effect when someone tries to write something into the variable.
In this case, the printf's use a as an rvalue, and the added volatile (unnecessary IMHO) makes the program read the variable anew, so I would say, the program is required to produce the output the OP saw initially, on all platforms/compilers.
I'll look at the Standard, and add it if/when I find anything new.
EDIT: I couldn't find any definite solution to this question in the Standard (I used the latest draft for C1X), since all references to linker behavior concentrate on names being identical. Type qualifiers on external declarations do not seem to be covered.
Maybe we should forward this question to the C Standard Committee.
I have used a static global variable and a static volatile variable in file scope,
both are updated by an ISR and a main loop and main loop checks the value of the variable. here during optimization neither the global variable nor the volatile variable are optimized. So instead of using a volatile variable a global variable solves the problem.
So is it good to use global variable instead of volatile?
Any specific reason to use static volatile??
Any example program would be appreciable.
Thanks in advance..
First let me mention that a static global variable, is the same as a global variable, except that you are limiting the variable to the scope of the file. I.e. you can't use this global variable in other files via the extern keyword.
So you can reduce your question to global variables vs volatile variables.
Now onto volatile:
Like const, volatile is a type modifier.
The volatile keyword was created to prevent compiler optimizations that may make code incorrect, specifically when there are asynchronous events.
Objects declared as volatile may not be used in certain optimizations.
The system always reads the current true value of a volatile object at the point it is used, even if a previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment. That means there is no caching of a volatile variable into a CPU register.
Dr. Jobb's has a great article on volatile.
Here is an example from the Dr. Jobb's article:
class Gadget
{
public:
void Wait()
{
while (!flag_)
{
Sleep(1000); // sleeps for 1000 milliseconds
}
}
void Wakeup()
{
flag_ = true;
}
...
private:
bool flag_;
};
If the compiler sees that Sleep() is an external call, it will assume that Sleep() cannot possibly change the variable flag_'s value. So the compiler may store the value of flag_ in a register. And in that case, it will never change. But if another thread calls wakeup, the first thread is still reading from the CPU's register. Wait() will never wake-up.
So why not just never cache variables into registers and avoid the problem completely?
It turns out that this optimization can really save you a lot of time overall. So C/C++ allows you to explicitly disable it via the volatile keyword.
The fact above that flag_ was a member variable, and not a global variable (nor static global) does not matter. The explanation after the example gives the correct reasoning even if you're dealing with global variables (and static global variables).
A common misconception is that declaring a variable volatile is sufficient to ensure thread safety. Operations on the variable are still not atomic, even though they are not "cached" in registers
volatile with pointers:
Volatile with pointers, works like const with pointers.
A variable of type volatile int * means that the variable that the pointer points to is volatile.
A variable of type int * volatile means that the pointer itself is volatile.
They are different things. I'm not an expert in volatile semantics. But i think it makes sense what is described here.
Global
Global just means the identifier in question is declared at file-scope. There are different scopes, called function (where goto-labels are defined in), file (where globals reside), block (where normal local variables reside), and function prototype (where function parameters reside). This concept just exist to structure the visibility of identifiers. It doesn't have anything to do with optimizations.
Static
static is a storage duration (we won't look at that here) and a way to give a name declared within file scope internal linkage. This can be done for functions or objects only required within one translation unit. A typical example might be a help function printing out the accepted parameters, and which is only called from the main function defined in the same .c file.
6.2.2/2 in a C99 draft:
If the declaration of a file scope
identifier for an object or a function
contains the storage class specifier
static, the identifier has internal
linkage.
Internal linkage means that the identifier is not visible outside the current translation unit (like the help function of above).
Volatile
Volatile is a different thing: (6.7.3/6)
An object that has volatile-qualified
type may be modified in ways unknown to
the implementation or have other
unknown side effects. Therefore any
expression referring to such an object
shall be evaluated strictly according
to the rules of the abstract machine,
as described in 5.1.2.3. Furthermore,
at every sequence point the value last
stored in the object shall agree with
that prescribed by the abstract
machine, except as modified by the
unknown factors mentioned
previously.
The Standard provides an excellent example for an example where volatile would be redundant (5.1.2.3/8):
An implementation might define a
one-to-one correspondence between
abstract and actual semantics: at
every sequence point, the values of
the actual objects would agree with
those specified by the abstract
semantics. The keyword volatile
would then be redundant.
Sequence points are points where the effect of side effects concerning the abstract machine are completed (i.e external conditions like memory cell values are not included). Between the right and the left of && and ||, after ; and returning from a function call are sequence points for example.
The abstract semantics is what the compiler can deduce from seeing only the sequence of code within a particular program. Effects of optimizations are irrelevant here. actual semantics include the effect of side effects done by writing to objects (for example, changing of memory cells). Qualifying an object as volatile means one always gets the value of an object straight from memory ("as modified by the unknown factors"). The Standard doesn't mention threads anywhere, and if you must rely on the order of changes, or on atomicity of operations, you should use platform dependent ways to ensure that.
For an easy to understand overview, intel has a great article about it here.
What should i do now?
Keep declaring your file-scope (global) data as volatile. Global data in itself does not mean the variables' value will equal to the value stored in memory. And static does only make your objects local to the current translation unit (the current .c files and all other files #include'ed by it).
The "volatile" keyword suggests the compiler not to do certain optimizations on code involving that variable; if you just use a global variable, nothing prevents the compiler to wrongly optimize your code.
Example:
#define MYPORT 0xDEADB33F
volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';
Without "volatile", the first write may be optimized out.
The volatile keyword tells the compiler to make sure that variable will never be cached. All accesses to it must be made in a consistent way as to have a consistent value between all threads. If the value of the variable is to be changed by another thread while you have a loop checking for change, you want the variable to be volatile as there is no guarantee that a regular variable value won't be cached at some point and the loop will just assume it stays the same.
Volatile variable on Wikipedia
They may not be in different in your current environment, but subtle changes could affect the behavior.
Different hardware (more processors, different memory architecture)
A new version of the compiler with better optimization.
Random variation in timing between threads. A problem may only occur one time in 10 million.
Different compiler optimization settings.
It is much safer in the long run to use proper multithreading constructs from the beginning, even if things seem to work for now without them.
Of course, if your program is not multi-threaded then it doesn't matter.
I +1 friol's answer. I would like to add some precisions as there seem to be a lot of confusions in different answers: C's volatile is not Java's volatile.
So first, compilers can do a lot of optimizations on based on the data flow of your program, volatile in C prevents that, it makes sure you really load/store to the location every time (instead of using registers of wiping it out e.g.). It is useful when you have a memory mapped IO port, as friol's pointed out.
Volatile in C has NOTHING to do with hardware caches or multithreading. It does not insert memory fences, and you have absolutely no garanty on the order of operations if two threads do accesses to it. Java's volatile keyword does exactly that though: inserting memory fences where needed.
volatile variable means that the value assinged to it is not constant, i.e if a function containing a volatile variable "a=10" and the function is adding 1 in each call of that function then it will always return updated value.
{
volatile int a=10;
a++;
}
when the above function is called again and again then the variable a will not be re-initialised to 10, it will always show the updated value till the program runs.
1st output= 10
then 11
then 12
and so on.