address@hidden wrote:
Eric,
The problem with the function is typical housekeeping overhead gets
wrapped up.
To take a silly example:
Say you want to send some message to ISR (via memory) using critical
function
critical void function(int *buffer, int *cValue)
{
*cValue++ = *buffer++;
}
Getting *buffer++ does not need ISR disabled. Perhaps neither does
the cValue++;
It is far more important to be correct than to be fast - thus it is
better to err on the side of disabling interrupts for too long. Of
course, in time-critical code disabling the interrupts for too long
could also make the code fail.
The point of the "critical" attribute is that it makes it very easy to
write correct code. If you want code to be as fast as possible, your
example should be written thus:
static inline critical void functionHelper(int v, int *cValue) {
*cValue = v;
}
void function(int *buffer, int *cValue) {
functionHelper(*buffer++, cValue++);
}
With small static inline functions, you have exactly the granularity
you want. And of course, you are still free to write out the
cli()/sreg code if you find that makes sense for critical code.
There are also ways to get atomic access which don't block interrupts.
(I expect you are already familiar with several methods, but this
could be of interest to others on this list too.) For example:
#define volatileAccess(v) *((volatile typeof((v)) *) &(v))
#define nonblock_atomic_read(v) ({ \
typeof(v) a, b; \
a = volatileAccess(v); \
b = volatileAccess(v); \
while (a != b) { \
a = b; \
b = volatileAccess(v); \
}; \
b; \
})
It's also possible to use a 1-byte flag for access control, since it
can always be written and read atomically. But these sorts of
solutions require more care and thought - a "critical" attribute is
makes it easier for programmers to write working code.
So this method, although not wrong, is something I would normally
reject for time critical systems, where latency is key.
Inline coding has less overhead but even then its not perfect -
though perhaps more palatable than assembler.
I do not know much about the gcc atomic operations. But it might be
worth reviewing. There may be some hooks that make
it work well with optimisations without adding a bunch of code hacks.
Also it makes code more portable (Atmel ARM or course!)
I believe the atomic operations are target-specific, and use
target-specific assembly. Many larger processors have atomic
operations of some sort - disabling interrupts won't work if you have
an SMP system.
It would be *very* nice if gcc had a set of atomic access buildins
that were consistent across a range of targets. It would also be
*very* nice if function attributes were consistent across ports. It
seems that every gcc port has its own function attribute for
specifying interrupt functions, for example. Sometimes they have the
same name, but different functions - the msp430 port has "interrupt"
and "signal" with slightly different syntax from the avr port, and
opposite effects. There are also attributes that only some ports have,
that could be easily* and usefully provided in all ports. Examples
are "critical", "naked", "interrupt", "near", "far", and "saveall".
* At least, it's easy to think out what the generated assembly would
look like - I don't know if that makes it easy to implement in practice!
mvh.,
David
_______________________________________________
AVR-GCC-list mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/avr-gcc-list