FYI, the new kernel newbie column is out

Eric Battersby gyre-Ja3L+HSX0kI at public.gmane.org
Fri Jul 10 08:30:46 UTC 2009


On Wed, 8 Jul 2009, Alex Beamish wrote:

> With a couple of years of Perl development on top of a couple more
> years of C development, I'd propose using a table and some pointers:
>
> ======================================
> /*  Prototype the registration functions. */
>
> int register_this(void *, char *);
> int register_that(void *, char *);
> int register_those(void *, char *);
> int unregister_this(void *, char *);
> int unregister_that(void *, char *);
>
> /*  Define a skull element structure that contains a void pointer for a return
> *  value, as well as pointers to the functions that register and unregister.
> *  */
>
> typedef struct {
>  void	*pv;
>  int	(*pfiRegister)();
>  int	(*pfiUnRegister)();
> } SKULL_ELEMENT;
>
> /*  Define an array of skull elements and initialize them with function
> *  pointers or NULLs. */
>
> SKULL_ELEMENT astrStack[3] = {
>  NULL, register_this,  unregister_this,
>  NULL, register_that,  unregister_that,
>  NULL, register_those, NULL,
> };
>
> int registration ()
> {
>    SKULL_ELEMENT *pstr;
>
>    /*  Cycle through each the skull elements .. */
>
>    for ( pstr = astrStack; pstr <= &astrStack[2]; pstr++ ) {
>
>      /*  Try to register a skull using the appropriate pointer and function ..
>       *  */
>
>      int err = pstr->pfiRegister ( pstr->pv, "skull" );
>      if ( err ) {
>
> 	/*  If there was an error, go back through the stack and unregister any
> 	 *  prior registrations, and return the error.  */
>
>        while ( --pstr > astrStack ) {
>
> 	  pstr->pfiUnRegister ( pstr->pv, "skull" );
>
> 	}
> 	return ( err );
>      }
>    }
>
>    /*  Success!  */
>
>    return ( 0 );
> }
> ======================================
>
> I prefer the usage of 'if ( err )' rather than the somewhat
> counterintuitive 'if ( !err )', but that's probably a matter for
> discussion over beer, and not a mailing list.
>
> It looks like this code tries to register with three different
> functions, and if any of them fail, it unregisters from any that
> succeeded. I note that there are no tests for failure on
> unregistration -- perhaps they were removed from the example code for
> clarity.
>
> I didn't have the time to actually confirm that my code is
> functionally the same, but it does compile. I think I last used
> function pointers in C back in 1998, so I'm not positive I have the
> syntax right, but the meaning should be clear enough.


That code still looks a bit hairy to me.
Using a stack abstraction,
I think the actual code logic is easier to understand
and becomes easier to read.
This code is functionally the same as the orginal.

***

...

/* do single registration here */
int reg_it( int(*  reg)(char *p, char *s)
           , int(*unreg)(char *p, char *s)
           , char *p, char *s) {
     int err;

     err = reg( p, s );
     if (err) { pop_all();	    }  /* undo previous registrations */
     else     { push( unreg, p, s ); }  /* save new unregistration fn  */

     return( err );
}/* reg_it() */

/* macro to simplify relevant code and eliminate duplication */
#define REG_IT_OR_RETURN(name,ptr,str)				   \
     err = reg_it(register_##name , unregister_##name , ptr, str);  \
     if ( err ) return(err);

/* MAIN CODE LOGIC */
int proc(char *ptr1, char *ptr2, char *ptr3) {
     int err;
     gREG_stack_inx = 0;  /* reset stack */

     /* do registration with undo */
     REG_IT_OR_RETURN( this , ptr1, "skull");
     REG_IT_OR_RETURN( that , ptr2, "skull");
     REG_IT_OR_RETURN( those, ptr3, "skull");

     return 0;
}/* proc() */

--
Eric Battersby
--
The Toronto Linux Users Group.      Meetings: http://gtalug.org/
TLUG requests: Linux topics, No HTML, wrap text below 80 columns
How to UNSUBSCRIBE: http://gtalug.org/wiki/Mailing_lists





More information about the Legacy mailing list