[vox-tech] Where setjmp/longjmp went after C

Jeff Newmiller vox-tech@lists.lugod.org
Thu, 5 Sep 2002 13:16:13 -0700 (PDT)


On Wed, 4 Sep 2002, Haiying Wu wrote:

> "[vox-tech] Where setjmp/longjmp went after C" is a
> good article. But I have to point out a possible
> mistake.

Exceptions are indeed tough to implement in a fashion that always seems
"right".  Including them in the C++ language allowed this error-prone code
problem to be handled by the compiler so the programmer would have fewer
opportunities to screw it up.

> I think there are risks to define macro"#define 
> JB_ENDTRY  }JB_ULN}".

It does _look_ risky, but it isn't. :)

> for example, in code: 
> 
> void b( char volatile c )
> {
>   int caught=0;
> 
>   printf( "entered b with c=%c\n", c );
>   JB_TRY( &caught ) {
>     printf( "doing f\n" );
>     f( c );
>     printf( "did f\n" );
>     g( c );
>     printf( "did g\n" );
>   } JB_CATCH( EXCEP_MATHERR ) {
>     printf( "caught MATHERR exception in b\n" );
>     JB_RAISE( EXCEP_INVALIDARGS );
>   } JB_CATCHDEFAULT {
>     printf( "caught some other exception... c=%c,
> caught=%d\n", c, caught );
>     JB_RAISE( caught );
>   } JB_ENDTRY;
>   printf( "leaving b\n" );
> }
> 
> It's OK. But what if there is no another exception
> raised in catch block or catch-default block? See the
> following code:
> 
>   JB_CATCH( EXCEP_MATHERR ) {
>    printf( "caught MATHERR exception in b\n" );
>     /*JB_RAISE( EXCEP_INVALIDARGS );*/ //no new
> exception raised
>   }
> 
> then, JB_ENDTRY will be executed after JB_CATCH block
> .
> So, JB_ULN will be executed twice, it is dangerous!

It would be, except that the implementation of JB_ULN is simply to
overwrite the "head" pointer to the list with the "next" pointer from the
current context.  Overwriting a pointer with the same value twice doesn't
actually cause any ill effects.

The code

  JB_TRY( &caught ) {
    printf( "doing f\n" );
    f( c );
    printf( "did f\n" );
    g( c );
    printf( "did g\n" );
  } JB_CATCH( EXCEP_MATHERR ) {
    printf( "caught MATHERR exception in b\n" );
    /* JB_RAISE( EXCEP_INVALIDARGS ); */
  } JB_CATCHDEFAULT {
    printf( "caught some other exception... c=%c,
caught=%d\n", c, caught );
    JB_RAISE( caught );
  } JB_ENDTRY;

preprocesses to

  {jbnode
jbnode_local;jbnode_local.next=jbnode_head;jbnode_head=&jbnode_local; ;switc
h((*(  &caught  ))= _setjmp ( jbnode_head->this ) ){case 0:  {
    printf( "doing f\n" );
    f( c );
    printf( "did f\n" );
    g( c );
    printf( "did g\n" ); 
} break;case ( 1 ): jbnode_head=jbnode_local.next; ;  {
    printf( "caught MATHERR exception in b\n" );
     
  } break;default: jbnode_head=jbnode_local.next; ;  {
    printf( "caught some other exception... c=%c, caught=%d\n", c, caught
);
    longjmp(jbnode_head->this,(  caught  )); ;
  } }jbnode_head=jbnode_local.next; } ;

where the execution path through the default catch shows why the JB_ULN
needs to be in JB_CATCHDEFAULT (JB_RAISE needs to operate in the next
higher context), and the non-exception TRY path shows why it has to be in
JB_ENDTRY (if there were no exceptions, the context would have to be reset
at the end of the select statement).

> A possible solution to this problem is to:
> (1)#define JB_ENDTRY }}
> (2)#define JB_NORMAL_TERMINATE JN_ULN
> (3)add "JB_NORMAL_TERMINATE" at the end of normal code
> (try block).

I think I have explained why this is not necessary... there is no problem
invoking JB_ULN twice.  My offered syntax is more compact and easier to
remember when coding than the alternatives you offered.  It is still not
signal() safe though, so ideas on how to make it so would be welcome.

Thank you for your comments... an example of GooglePower!

---------------------------------------------------------------------------
Jeff Newmiller                        The     .....       .....  Go Live...
DCN:<jdnewmil@dcn.davis.ca.us>        Basics: ##.#.       ##.#.  Live Go...
                                      Live:   OO#.. Dead: OO#..  Playing
Research Engineer (Solar/Batteries            O.O#.       #.O#.  with
/Software/Embedded Controllers)               .OO#.       .OO#.  rocks...2k
---------------------------------------------------------------------------