Guarantee of Atomic Statement and Test Compilation
01/16/2010: It frequently occurs in embedded systems that one wishes to ensure that a C-language statement or test is atomic. One might have available functions or macros to disable or enable interrupts, so one might write:
volatile int semaphore; DI(); semaphore++; EI();
Whether an increment can be handled atomically depends on the processor, where in memory the variable is located, its size, and on specific decisions the compiler makes.
Other operations that one might wish to ensure atomicity with include assignments, bitfield assignments, tests, etc.
For example, in the code:
volatile unsigned long x; if (x > 29204) ...
there might be a problem because an asynchronous process may update the variable and cause the test to fetch inconsistent bytes as it performs the test, leading to intermittent unpredictable results.
In most cases, one can protect the statements of concern with DI()/EI() or find a way to guarantee atomicity. The issue is that this method of protection can be inefficient. It consumes memory, consumes CPU cycles, and affects the timing of interrupts.
It is common to look through the assembly-language generated by a compiler to ensure that important statements are atomic. However, this approach has the following perceived disadvantages:
The problem doesn't normally exist when programming in assembly-language, as one can control the selection of instructions.
What is needed is a way to advise the compiler that certain statements and tests need to be compiled atomically, and to generate a compilation error if this can't be done.
A construct that would handle statements might be something like:
#pragma ASSERT_ATOMIC_STATEMENT_START semaphore++; #pragma ASSERT_ATOMIC_STATEMENT_END
However, it isn't clear the best way to advise the compiler that certain tests must be atomic.
I did post this question on comp.lang.c, and received an insightful reply:
David T. Ashley wrote: > This is slightly off-topic, as it involves implementation rather than > the C language. > > It frequently comes up in embedded systems that one wishes to ensure > that a C-language statement is atomic. One might have available > functions or macros to disable or enable interrupts, so one might write: > > volatile int semaphore; > > DI(); > semaphore++; > EI(); > > Whether an increment can be handled atomically depends on the processor, > where in memory the variable is located, its size, and on specific > decisions the compiler makes. > > Other operations that one might wish to ensure atomicity with include > assignments, bitfield assignments, tests, etc. > > For example, in the code: > > volatile unsigned long x; > > if (x > 29204) ... > > there might be a problem because an asynchronous process may update the > variable and cause the test to get inconsistent bytes as it performs the > test. The C standard (C99, at least, I believe) defines the type "sig_atomic_t" which is guaranteed to be accessible (read/write) as a whole, so it solves the problem with the ">" test, but not the problem with increment operations. However, "sig_atomic_t" is guaranteed only to be at least 8 bits wide, not "long". In practice "sig_atomic_t" is probably as large as the processor's memory interface allows, so it could be as wide as "long". > In most cases, one can protect the statements of concern with DI()/EI() > or find a way to guarantee atomicity. The issue is that this method of > protection can be inefficient. It consumes memory, consumes CPU cycles, > and affects the timing of interrupts. > > Here is my question: > > Has anyone seen any compilers that support guaranteeing that a certain > statement or test is atomic? I haven't, except for sig_atomic_t, which does less than you are asking for. > What I'd be looking for is something like: > > #pragma ASSERT_ATOMIC_STATEMENT_START > semaphore++; > #pragma ASSERT_ATOMIC_STATEMENT_END > > The pragmas would advise the compiler to: > > a)Try to compile the statement atomically (using a single instruction), and > > b)Create an error if it can't be compiled atomically. A good suggestion. But I suspect that compiler writers would find it easier to introduce compiler-specific "built-in" functions for things that can be done atomically, such as increment/decrement of a memory word, or swapping the contents of a memory word and a register. Maybe some such functions could be standardised? For example, a function called "atomic_increment" (decorated with suitable '_' marks to make it a reserved identifier). The compiler would accept or reject a call of such functions depending on the types of the parameters and on the capabilities of the target processor. GCC has a set of built-in atomic memory access functions (http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html). It seems that they don't support counting semaphores but do support locks (binary semaphores). -- Niklas Holsti Tidorum Ltd
01/27/2010: I did receive a very helpful reply from Mike Burns at Cosmic, and I replied back with one additional thought.
This web page is maintained by webmaster@dtashley.com. Sound credit: The Godfather. This sound is #42, randomly selected from the 76 sounds that are suitable for this page. A list of all 113 sounds in the database (some unsuitable for this page) can be found here. Local time on this server (at the time the page was served) is 1:44:25 pm on February 6, 2012.