The following code contains an interrupt-service-routine and a normal function func(), which uses the global flag and additionally the static global g. Without any memory-barrier this code is faulty, since flag is modified asynchronously.
Introducing the global memory-barrier <1> fixes that, but also inhibits the optimizations on g. My expectation was that all access to g would be optimized out, since g is not accessible outside this TU.
I know that a global memory barried has the same effect as calling a non-inline function f() <3>. But here is the same question: since g is not visible outside this TU, why should not optimize the access to g.
I tried to use a specific memory-barrier against flag but that did not help either.
(I avoided qualifying flag as volatile: this would help here, but it should only be used accessing HW-registers).
The question now is how to get the accesses to g optimized?
Compiler: avr-gcc
https://godbolt.org/z/ob6YoKx5a
#include <stdint.h>
uint8_t flag;
void isr() __asm__("__vector_5") __attribute__ ((__signal__, __used__, __externally_visible__));
void isr() {
flag = 1;
}
static uint8_t g;
void f();
void func(void) {
for (uint8_t i=0; i<20; i++) {
// f(); // <3>
// __asm__ __volatile__ ("" : : : "memory"); // <1>
// __asm__ __volatile__ ("" : "=m" (flag)); // <2>
++g;
if (flag) {
flag = 0;
}
}
}
//void f(){}
Lots of misconceptions.
There is nothing called "static global", that's like saying "dog cat", they are each other's opposites. You can have variables declared at local scope or at file scope. You can have variables with internal linkage or external linkage.
A "global" - which isn't a formal term, is a variable declared at file scope with external linkage which may be referred to by other parts of the program using
extern. This is almost always bad practice and bad design.staticensures that a variable no matter where it was declared has internal linkage. So it is by definition not "global". Variables declaredstaticare only accessible inside the scope where they were declared. For details check out What does the static keyword do in C?Memory barriers is not a concept that makes much sense outside multicore systems. The purpose of memory barriers are to prevent concurrent execution/pipelining, pre-fetching or instruction reordering in multicore systems. Also, memory barriers do not guarantee re-entrancy on the software level.
This is some single core AVR, one of the simplest CPUs still manufactured, so memory barriers is not an applicable concept. Do not read articles about PC programming on 64 bit x86 and try to apply them to 8-bit legacy architectures from the 1990s. Wrong tool, wrong purpose, wrong system.
volatiledoes not necessarily act as a memory barrier even on systems where that concept is applicable. See for example https://stackoverflow.com/a/58697222/584518.volatiledoes not make code re-entrant/thread-safe/interrupt-safe on any system, including AVR.The purpose of
volatilein this context is to protect against incorrect compiler optimizations when the compiler doesn't realize that an ISR is called by hardware and not by the program. We can'tvolatilequalify functions or code in C, only objects, hence variables shared with an ISR need to bevolatilequalified. Details and examples here: https://electronics.stackexchange.com/questions/409545/using-volatile-in-embedded-c-development/409570#409570As for what you should be doing instead, I believe my answer to your other question here covers that.