[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