Changes from patch4: return types and declined values support (API changed)
Changes from patch5: use of 'inline' for C++ (API not changed)

 SYNOPSIS

   Main Setup:
     void ap_hook_init (void);
     void ap_hook_kill (void);

   Hook Configuration and Registration:
     
ap_hook_define_client(hook_name,ret_value,hook_parameters,hook_call,decline_value);
     int  ap_hook_configure_hook_name(ap_hook_mode modeid);
     int  ap_hook_unconfigure_hook_name();

     ap_hook_define_server(hook_name,ret_value,hook_parameters,hook_call);
     int  ap_hook_register_hook_name(ret_value (*func)hook_parameters);
     int  ap_hook_unregister_hook_name(ret_value (*func)hook_parameters);

     
ap_hook_define_client_global(mod_name,hook_name,ret_value,hook_parameters,hook_call,decline_value);
     ap_hook_define_client_realize(mod_name,hook_name,hook_parameters,hook_call);
     int  ap_hook_mod_name_configure_hook_name(ap_hook_mode modeid);
     int  ap_hook_mod_name_unconfigure_hook_name();

     
ap_hook_define_server_global(mod_name,hook_name,ret_value,hook_parameters,hook_call);
     ap_hook_define_server_realize(mod_name,hook_name,hook_parameters,hook_call);
     int  ap_hook_mod_name_register_hook_name(ret_value (*func)hook_parameters);
     int  ap_hook_mod_name_unregister_hook_name(ret_value (*func)hook_parameters);

   Hook Usage:
     int       ap_hook_configured_hook_name();
     int       ap_hook_registered_hook_name();
     int       ap_hook_registered_func_hook_name(ret_value (*func)hook_parameters);
     ret_value ap_hook_call_name(hook_parameters);

     int       ap_hook_mod_name_configured_hook_name();
     int       ap_hook_mod_name_registered_hook_name();
     int       ap_hook_mod_name_registered_func_hook_name(ret_value 
(*func)hook_parameters);
     ret_value ap_hook_mod_name_hook_name(hook_parameters);

 DESCRIPTION

   This implements a generic hook interface for Apache which can be used
   for loosely couple code through arbitrary hooks. There are two use cases
   for this mechanism:

   1. Inside a specific code section you want to perform a specific
      function call. But you want to allow one or even more modules to
      override this function call by registering hook functions.  Those
      functions are registered on a stack and could return TRUE or FALSE.
      As long as there are functions which return FALSE value the next
      function on the stack is tried.  When a function return TRUE the
      hook call stops.  The intent of this usage is to not hard-code
      function calls.  Note that the only return type allowed for hooks
      is int and only two values could be returned: TRUE and FALSE. If
      you want other return types or values use wrappers (see sample below).

   2. Inside a specific code you have a function you want to export.
      But you first want to allow other code to override this function.
      And second you want to export this function without real linker
      symbol references. Instead you want to register the function and let
      the users call this function via name. The intent of this usage is to
      allow inter-module communication without direct symbol references,
      which are a big NO-NO for the DSO situation.

   And we have one major design goal: The hook call should be very similar
   to the corresponding direct function call while still providing maximum
   flexiblity, i.e. any function signature (the set of types for the return
   value and the arguments) should be supported.

   Using this hook interface is always a four-step process(but see also
   "NOTE for DSO modules" below!):

   1. Initialize or destroy the hook mechanism inside your main program:

      ap_hook_init();
          :
      ap_hook_kill();

   2. Define and configure a particular hook by specifing its name and
      argumets type:

      ap_hook_define_client(lookup,void *,(void *x),(x),NULL);
      ap_hook_define_client(echo,int,(void *x),(x),0);

      ap_hook_configure_lookup(AP_HOOK_NORMAL);
      ap_hook_configure_echo(AP_HOOK_TOPMOST);

      This configures two hooks:
      - A hook named "lookup" with the signature "lookup(void **,void *)"
        and default return semantic.
      - A hook named "echo" with the signature "echo(int *,void *)" and a
        return code semantic which says: Only the top most function on the
        registered function stack is tried, independed what value it
        returns.

   3. Define and register the actual functions which should be used by
      the hook:

      ap_hook_define_server(lookup,void *,(void *x),(x));
      ap_hook_define_server(echo,int,(void *x),(x));

      ap_hook_register_lookup(mylookup);
      ap_hook_register_echo(myecho);

      This registers the function mylookup() under the "lookup" hook and
      function myecho() under the "echo" hook.

   4. Finally use the hook, i.e. instead of using direct function calls
      like

         vp = mylookup("foo");
         n  = myecho("bar");

      you now can use:

         vp = ap_hook_call_lookup("foo");
         n  = ap_hook_call_echo("bar");

      BTW, the return value of ap_hook_call() is of the same type as
      registered function itself. But declined value is special: if
      one hook will return declined value next hook will be used (if
      it's not AP_HOOK_TOPMOST hook, that is).

 NOTE for DSO modules

      If you plan to use this mechanism in DSO modules you SHOULD unregister
      all hooks on module unload phase:

      static void unregister_hooks(struct module_struct * m) {
          if (m == &client_module) {
              ap_hook_unconfigure_lookup();
              ap_hook_unconfigure_echo();
          }
      }

      static void unregister_hooks(struct module_struct * m) {
          if (m == &server_module) {
              ap_hook_unregister_lookup(mylookup);
              ap_hook_unregister_echo(myecho);
          }
      }

      Insert unregister_hooks function as remove_module hook in module
      structure.

 NOTE for modules with multiple source files

      It's safe to use ap_hook_define_client and/or ap_hook_define_server
      in .h file included in multiple .c files. The only possible problem
      will be with unregister_hooks functions (see above) -- you should
      call to ap_hook_unconfigure_function in THE SAME module where
      ap_hook_configure_function was called before and you SHOULD call
      ap_hook_configure_function before ap_hook_call_function in EACH
      module.  Plus if you have non-gcc based compiler this will lead to a
      lot of duplicated static functions.  So in this case you could use
      ap_hook_define_client_global and/or ap_hook_define_server_global in
      .h file.  In ONE .c file for each module you should use function
      ap_hook_define_client_realize and/or ap_hook_define_server_realize
      to make instances for functions.  And you should unregister functions
      in one file as well. You should include .h file with [or just call to]
      ap_hook_define_client_global and/or ap_hook_define_server_global
      before ap_hook_define_client_realize and/or ap_hook_define_server_realize.
      Unfortunatelly this usage of non-static functions could lead to
      namespace pollution.  To avoid this all autogenerated functions will
      be created with prefix ap_hook_module_name instead of just ap_hook
      (module name is first parameter in ap_hook_define_client_global,
      ap_hook_define_client_realize, ap_hook_define_server_global and
      ap_hook_define_server_realize macroses; all other parameters are
      borrowed from ap_hook_define_client and ap_hook_define_server).

      One more note for mixed C/C++ programs: if in your program
      ap_hook_define_client_global or ap_hook_define_server_global is
      called from .h file, included in C source file then you MUST use
      ap_hook_define_client_realize or ap_hook_define_server_realize in
      C source file as well.

 SPEED ISSUES

      This implementation is designed to be VERY fast. For example this
      program (direct function call):

      void main(void) {
          FILE *f=fopen("/dev/null","a");
          for (int i=0;i<10000000;i++) fputc(' ',f);
          fclose(f);
      }

      works 2.96 seconds on Pentium200MMX (egcs 1.1b with -O6 -mcpu=pentium).

      This program (call over hooks):

      ap_hook_define(fputc,int,(int c,FILE *stream),(c,stream),EOF);

      void main(void) {
          FILE *f=fopen("/dev/null","a");
          ap_hook_init();
          ap_hook_register_fputc(fputc);
          ap_hook_configure_fputc(AP_HOOK_NORMAL);
          for (int i=0;i<10000000;i++) {
              int dummy;
              ap_hook_call_fputc(' ',f);
          }
          fclose(f);
          ap_hook_kill();
      }

      will work 3.23 seconds on the same Pentium200MMX...

EAPI-2-EAPIk-4-2.1b9-SNAP.patch6.gz

Reply via email to