[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-libc-dev] New Atomic.h header?
From: |
Paulo Marques |
Subject: |
Re: [avr-libc-dev] New Atomic.h header? |
Date: |
Mon, 08 Jan 2007 19:19:09 +0000 |
User-agent: |
Thunderbird 1.5.0.7 (X11/20060909) |
Dean wrote:
Hi guys!
Hi, Dean.
[...]
My macro allows for both atomic (interrupts disabled) and non-atomic
(interrupts enabled) blocks of code to be easily made. Unlike
conventional methods these macros are quite foolproof - the epilogue for
each is run automatically on block exit regardless of the exit path.
When compiled with -Os, it results in the smallest possible code.
First of all, I would like to say that I agree that we should improve
the way that atomic blocks are handled in avr-gcc, but I've found a few
problems with your solution, though.
The main problem is that the generated code doesn't always do what is
expected. Something like:
uint16_t counter1, counter2;
>
...
>
int main(void)
{
uint16_t a, b;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
a = counter1;
b = counter2;
}
PORTB = a;
PORTC = b;
return 0;
}
compiles to (using gcc 4.2.0):
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
64: 8f b7 in r24, 0x3f ; 63
66: f8 94 cli
68: 8f bf out 0x3f, r24 ; 63
a = counter1;
b = counter2;
}
PORTB = a;
6a: 80 91 60 00 lds r24, 0x0060
6e: 88 bb out 0x18, r24 ; 24
PORTC = b;
70: 80 91 62 00 lds r24, 0x0062
74: 85 bb out 0x15, r24 ; 21
As you can see, the 'a' and 'b' loads are not atomic as expected,
because the compiler doesn't know about side effects and reorders the
loads around the flags restore operation.
To avoid this there must be some way to tell the compiler that
everything inside the block must be treated as volatile.
Anyway, I usually don't need a lot of code to be atomic. My problem is
the other way around: I only need to access multi-byte variables in an
atomic way, while keeping the interrupt latency as small as possible.
That is why a while ago I suggested creating an atomic.h with special
accessor functions atomic_read/write_16/32(uint16/32_t *ptr) that used
the same "restore flags one instruction earlier" trick that we also use
to update the stack pointer in function prologues.
This only solves the problem of multi-byte variables though. For more
complex interactions, we need something like your solution, but we have
to solve the reordering problem :(
BTW, your atomic.h also forces the code to use -std=c99. I don't know if
this will be a problem, though, but I thought I should mention it.
--
Paulo Marques - www.grupopie.com
"The face of a child can say it all, especially the
mouth part of the face."