[En-Nut-Discussion] NutOS 4.4.0: NutEnterCritical / NutExitCritical
duane ellis
ethernut at duaneellis.com
Wed May 21 01:32:10 CEST 2008
Harald Kipp wrote:
> Andreas Helmcke wrote:
>
>> since the discussion about the Bug in NutEnterCritical / NutExitCritical
>> on ARM seems to have sort of "dried out" with, as far as I can see, no
>> real solution I just like to ask when there will be a changed / fixed
>> version.
>>
>
> If I got it right, the result of the discussion was, that no simple fix
> seems to be acceptable. The solution suggested by Duane is quite
> attractive, but would require some rewrite of interrupt handlers and a
> lot of time for testing. Unfortunately I wouldn't have the time right
> now to give it a try.
>
> Anyone else with enough time?
>
> Any other simple solution?
>
> Should we disable Enter/ExitCritical nesting temporarily?
>
>
There is another approach, if you look at for example how pthreads can
implement "cleanups".
It uses the C preprocessor, and some hidden hackary in the C code :-)
First - read carefully the description of some *detailed* man pages for
pthread_cleanup_pop() many man pages do not describe the trick.
(Linux guys can take a look at: /usr/include/pthread.h - line 593)
This one does: (the linux one does, but many one-line google'ed ones do
not go into detail)
http://www.opengroup.org/onlinepubs/000095399/functions/pthread_cleanup_pop.html
The idea is - ENTER/EXIT macros would be the two halves of a do { }
while(0) loop. Because the ENTER() macro opens a curly brace - one can
create a block local variable to save the irq state in. The EXIT() macro
- would then restore from that block local variable, and end the while().
==========
PROS:
Nesting works :-) one of the primary complaints
Enforces a specific coding style, and perhaps forcibly making
somebody do something the safe way.
Every ENTER - must be matched with an EXIT Clearly and unambiguously.
If you do not have a matching Enter/Exit - your code will not compile!
Hence, you cannot have a "I forgot one" bug.
The bug that can occur - is a return() in the middle.
That is simply enforced by visual inspection.
CONS:
Bad/lousy error messages from the compiler when you do this wrong.
In experienced programmers are often confused by this trick.
Example: See specifically how the open curly brace is in ENTER, and
close is in the EXIT.
===========
#define ENTER_CRITICAL() \
do { int __crit_save; ___crit_save = __disable_irqs();
#define EXIT_CRITICAL() \
__restore_irqs( __crit_save ); } while( 0 )
===========
This is ok (most common thing) = this would just work.
---
ENTER_CRITICAL();
... do stuff ....
for(...){
blah; blah; blah;
if( some_condition ){
break;
}
}
if( this ){
print(that);
}
while( i_have_no_beer() ){
pound_on_the_bar();
}
drink_drink_drink();
EXIT_CRITICAL()
---
This is *NOT*, and in fact it would not compile. (nut does this in some
places, example: os/thread.c)
---
ENTER_CRITICAL()
if( some_test_fails ){
EXIT_CRITICAL();
return -1;
}
.. do more ..
EXIT_CRITICAL()
---
This also would not compile ( and places in NUT does exactly this)
---
ENTER_CRITICAL()
for( ...some...loop... ){
do_some_setup();
EXIT_CRITICAL();
do more();
ENTER_CRITICAL();
}
EXIT_CRITICAL()
----
This would be a *BUG* - however - by visual inspection one immediately
would see the "rule: NO internal returns" is broken
I would view this bug as visually confirmed as a bug - period - no
questions asked.
---
ENTER_CRITICAL();
if( some_test_fails ){
return -1;
}
EXIT_CRITICAL();
More information about the En-Nut-Discussion
mailing list