stas        2002/12/09 08:29:58

  Modified:    src/docs/2.0/devel Changes.pod config.cfg
  Added:       src/docs/2.0/devel/core apache_integration.pod
                        coding_style.pod explained.pod
               src/docs/2.0/devel/debug c.pod perl.pod
               src/docs/2.0/devel/debug/code .debug-modperl-init
                        .debug-modperl-register .debug-modperl-xs
               src/docs/2.0/devel/performance size_matters.pod
  Removed:     src/docs/2.0/devel/core_explained core_explained.pod
               src/docs/2.0/devel/debug_c debug_c.pod
               src/docs/2.0/devel/debug_c/code .debug-modperl-init
                        .debug-modperl-register .debug-modperl-xs
               src/docs/2.0/devel/debug_perl debug_perl.pod
               src/docs/2.0/devel/modperl_style modperl_style.pod
               src/docs/2.0/devel/perf_sizeof perf_sizeof.pod
  Log:
  as the number of documents here grows, we need a better grouping. so this
  commit just changes some dir/file names, no content change.
  
  Revision  Changes    Path
  1.3       +5 -0      modperl-docs/src/docs/2.0/devel/Changes.pod
  
  Index: Changes.pod
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/2.0/devel/Changes.pod,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Changes.pod       31 Jul 2002 14:16:48 -0000      1.2
  +++ Changes.pod       9 Dec 2002 16:29:57 -0000       1.3
  @@ -9,6 +9,11 @@
   
   The most recent changes are listed first.
   
  +=head1 ???
  +
  +* Reshuffled the dir/file structure to make more sense, as new docs
  +  are getting added.
  +
   =head1 Wed Mar 20 21:20:20 SGT 2002
   
   * docs::general::testing::testing:
  
  
  
  1.12      +11 -6     modperl-docs/src/docs/2.0/devel/config.cfg
  
  Index: config.cfg
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/2.0/devel/config.cfg,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- config.cfg        13 Aug 2002 11:46:21 -0000      1.11
  +++ config.cfg        9 Dec 2002 16:29:57 -0000       1.12
  @@ -10,16 +10,21 @@
   
       group    => 'mod_perl 2.0 Core Development',
       chapters => [qw(
  -        core_explained/core_explained.pod
  -        modperl_style/modperl_style.pod
  -        perf_sizeof/perf_sizeof.pod
  +        core/explained.pod
  +        core/coding_style.pod
  +        performance/size_matters.pod
       )],
   
       group    => '3rd party modules Development with mod_perl 2.0',
       chapters => [qw(
           porting/porting.pod
  -        debug_perl/debug_perl.pod
  -        debug_c/debug_c.pod
  +    )],
  +
  +    group    => 'Debugging',
  +    chapters => [qw(
  +        porting/porting.pod
  +        debug/perl.pod
  +        debug/c.pod
       )],
   
       group    => 'Help',
  @@ -30,7 +35,7 @@
       changes => 'Changes.pod',
   
       copy_glob => [qw(
  -        debug_c/code
  +        debug/code
       )],
   
   
  
  
  
  1.1                  
modperl-docs/src/docs/2.0/devel/core/apache_integration.pod
  
  Index: apache_integration.pod
  ===================================================================
  =head1 NAME
  
  mod_perl internals: Apache 2.0 integration
  
  =head1 Description
  
  This document should help to understand the initialization, request
  processing and shutdown process of the mod_perl module. This knowledge
  is essential for a less-painful debugging experience. It should also
  help to know where a new code should be added when a new feature is
  added.
  
  Make sure to read also: L<Debugging mod_perl C
  Internals|docs::2.0::devel::debug::c>.
  
  =head1 Startup
  
  Apache starts itself and immediately restart itself. The following
  sections discuss what happens to mod_perl during this period.
  
  =head2 The Link Between mod_perl and httpd
  
  I<mod_perl.c> defines a special structure:
  
    module AP_MODULE_DECLARE_DATA perl_module = {
        STANDARD20_MODULE_STUFF, 
        modperl_config_dir_create, /* dir config creater */
        modperl_config_dir_merge,  /* dir merger --- default is to override */
        modperl_config_srv_create, /* server config */
        modperl_config_srv_merge,  /* merge server config */
        modperl_cmds,              /* table of config file commands       */
        modperl_register_hooks,    /* register hooks */
    };
  
  Apache uses this structure to hook mod_perl in, and it specifies six
  custom callbacks which Apache will call at various stages that will be
  explained later.
  
  C<STANDARD20_MODULE_STUFF> is a standard macro defined in
  I<httpd-2.0/include/http_config.h>. Currently its main use if for
  attaching Apache version magic numbers, so the previously compiled
  module won't be attempted to be used with newer Apache versions, whose
  API may have changed.
  
  C<modperl_cmds> is a struct, that defines the mod_perl configuration
  directives and the callbacks to be invoked for each of these.
  
  =head1 Configuration Tree Building
  
  At the C<ap_read_config> stage the configuration file is parsed and
  stored in a parsed configuration tree is created. Some sections are
  stored unmodified in the parsed configuration tree to be processed
  after the C<pre_config> hooks were run. Other sections are processed
  right away (e.g., the C<Include> directive includes extra
  configuration and has to include it as soon as it was seen) and they
  may or may not add a subtree to the configuration tree.
  
  C<ap_build_config> feeds the configuration file lines from to
  C<ap_build_config_sub>, which tokenizes the input, and uses the first
  token as a potential directive (command). It then calls
  C<ap_find_command_in_modules()> to find a module that has registered
  that command (remember mod_perl has registered the directives in the
  C<modperl_cmds> C<command_rec> array, which was passed to
  C<ap_add_module> inside the C<perl_module> struct?). If that command
  is found and it has the C<EXEC_ON_READ> flag set in its
  I<req_override> field, the callback for that command is
  invoked. Depending on the command, it may perform some action and
  return (e.g., C<User foo>), or it may continue reading from the
  configuration file and recursively execute other nested commands till
  it's done (e.g., C<E<lt>Location ...E<gt>>). If the command is found
  but the C<EXEC_ON_READ> flag is not set or the command is not found,
  the current node gets added to the configuration tree and will be
  processed during the C<ap_process_config_tree()> stage, after the
  C<pre_config> stage will be over.
  
  If the command needs to be executed at this stage as it was just
  explained, C<execute_now()> invokes the corresponding callback with
  C<invoke_cmd>.
  
  Since C<LoadModule> directive has the C<EXEC_ON_READ> flag set, that
  directive is executed as soon as it's seen and the modules its
  supposed to load get loaded right away.
  
  For mod_perl loaded as a DSO object, this is when mod_perl starts its
  game.
  
  =head2 Enabling the mod_perl Module and Installing its Callbacks
  
  mod_perl can be loaded as a DSO object at startup time, or be
  prelinked at compile time.
  
  For statically linked mod_perl, Apache enables mod_perl by calling
  C<ap_add_module()>, which happens during the
  C<ap_setup_prelinked_modules()> stage. The latter is happening before
  the configuration file is parsed.
  
  When mod_perl is loaded as DSO:
  
    <IfModule !mod_perl.c>
        LoadModule perl_module "modules/mod_perl.so"
    </IfModule>
  
  mod_dso's C<load_module> first loads the shared mod_perl object, and
  then immediately calls C<ap_add_loaded_module()> which calls
  C<ap_add_module()> to enable mod_perl.
  
  C<ap_add_module()> adds the C<perl_module> structure to the top of
  chained module list and calls C<ap_register_hooks()> which calls the
  C<modperl_register_hooks()> callback. This is the very first mod_perl
  hook that's called by Apache.
  
  C<modperl_register_hooks()> registers all the hooks that it wants to
  be called by Apache when the appropriate time comes. That includes
  configuration hooks, filter, connection and http protocol hooks. From
  now on most of the relationship between httpd and mod_perl is done via
  these hooks. Remember that in addition to these hooks, there are four
  hooks that were registered with C<ap_add_module()>, and there are:
  C<modperl_config_srv_create>, C<modperl_config_srv_merge>,
  C<modperl_config_dir_create> and C<modperl_config_dir_merge>.
  
  Finally after the hooks were registered,
  C<ap_single_module_configure()> (called from mod_dso's C<load_module>
  in case of DSO) runs the configuration process for the module. First
  it calls the C<modperl_config_srv_create> callback for the main
  server, followed by the C<modperl_config_dir_create> callback to
  create a directory structure for the main server. Notice that it
  passes C<NULL> for the directory path, since we at the very top level.
  
  If you need to do something as early as possible at mod_perl's
  startup, the C<modperl_register_hooks()> is the right place to do
  that.  For example we add a C<MODPERL2> define to the
  C<ap_server_config_defines> here:
  
    *(char **)apr_array_push(ap_server_config_defines) =
        apr_pstrdup(p, "MODPERL2");
  
  so the following code will work under mod_perl 2.0 enabled Apache
  without explicitly passing C<-DMODPERL2> at the server startup:
  
    <IfDefine MODPERL2>
        # 2.0 configuration
        PerlSwitches -wT
    </IfDefine>
  
  This section, of course, will see the define only if inserted after
  the C<LoadModule perl_module ...>, because that's when
  C<modperl_register_hooks> is called.
  
  One inconvenience with using that hook, is that the server object is
  not among its arguments, so if you need to access that object, the
  next earliest function is C<modperl_config_srv_create()>. However
  remember that it'll be called once for the main server and one more
  time for each virtual host, that has something to do with mod_perl. So
  if you need to invoke it only for the main server, you can use a
  C<s-E<gt>is_virtual> conditional. For example we need to enable the
  debug tracing as early as possible, but we need the server object in
  order to do that, so we perform this setting in
  C<modperl_config_srv_create()>:
  
    if (!s->is_virtual) {
        modperl_trace_level_set(s, NULL);
    }
  
  =head1 The pre_config stage
  
  After Apache processes its command line arguments, creates various
  pools and reads the configuration file in, it runs the registered
  I<pre_config> hooks by calling C<ap_run_pre_config()>. That's when
  C<modperl_hook_pre_config> is called. And it does nothing.
  
  
  =head2 Configuration Tree Processing
  
  C<ap_process_config_tree> calls C<ap_walk_config>, which scans through
  all directives in the parsed configuration tree, and executes each one
  by calling C<ap_walk_config_sub>. This is a recursive process with
  many twists.
  
  Similar to C<ap_build_config_sub> for each command (directive) in the
  configuration tree, it calls C<ap_find_command_in_modules> to find a
  module that registered that command. If the command is not found the
  server dies. Otherwise the callback for that command is invoked with
  C<invoke_cmd>, after fetching the current directory configuration:
  
    invoke_cmd(cmd, parms, dir_config, current->args);
  
  The C<invoke_cmd> command is the one that invokes mod_perl's
  directives callbacks, which reside in I<modperl_cmd.c>. C<invoke_cmd>
  knows how the arguments should be passed to the callbacks, based on
  the information in the C<modperl_cmds> array that we have just
  mentioned.
  
  Notice that before C<invoke_cmd> is invoked,
  C<ap_set_config_vectors()> is called which sets the current server and
  section configuration objects for the module in which the directive
  has been found. If these objects were't created yet, it calls the
  registered callbacks as C<create_dir_config> and
  C<create_server_config>, which are C<modperl_config_dir_create> and
  C<modperl_config_srv_create> for the mod_perl module. (If you write
  your L<custom module in Perl|docs::2.0::user::config::custom>, these
  correspond to the C<DIR_CREATE> and C<SERVER_CREATE> Perl
  subroutines.)
  
  The command callback won't be invoked if it has the C<EXEC_ON_READ>
  flag set, because it was already invoked earlier when the
  configuration tree was parsed. C<ap_set_config_vectors()> is called in
  any case, because it wasn't called during the C<ap_build_config>.
  
  So we have C<modperl_config_srv_create> and
  C<modperl_config_dir_create> both called once for the main server (at
  the end of processing the C<LoadModule perl_module ...> directive),
  and one more time for each virtual host in which at least one mod_perl
  directive is encountered. In addition C<modperl_config_dir_create> is
  called for every section and subsection that includes mod_perl
  directives (META: or inherits from such a section even though
  specifies no mod_perl directives in it?).
  
  =head1 Request Processing
  
  
  META: need to write
  
  =head1 Shutdown
  
  META: need to write
  
  =head1 Maintainers
  
  Maintainer is the person(s) you should contact with updates,
  corrections and patches.
  
  =over
  
  =item *
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =back
  
  
  =head1 Authors
  
  =over
  
  =item *
  
  =back
  
  Only the major authors are listed above. For contributors see the
  Changes file.
  
  
  
  =cut
  
  
  
  
  1.1                  modperl-docs/src/docs/2.0/devel/core/coding_style.pod
  
  Index: coding_style.pod
  ===================================================================
  =head1 NAME
  
  mod_perl Coding Style Guide
  
  =head1 Description
  
  This document explains the coding style used in the core mod_perl
  development and which should be followed by all core developers.
  
  =head1 Coding Style Guide
  
  We try hard to code mod_perl using an identical style. Because
  everyone in the team should be able to read and understand the code as
  quickly and easily as possible. Some will have to adjust their habits
  for the benefit of all.
  
  =over 4
  
  =item * C code
  
  mod_perl's C code follows the Apache style guide:
  http://dev.apache.org/styleguide.html
  
  =item * XS code
  
  C code inside XS modules also follows the Apache style guide.
  
  =item * Perl code
  
  mod_perl's Perl code also follows the Apache style guide, in terms of
  indentation, braces, etc. Style issues not covered by Apache style of
  guide should be looked up in the I<perlstyle> manpage.
  
  =back
  
  Here are the rough guidelines with more stress on the Perl coding
  style.
  
  =over 4
  
  =item Indentation and Tabs
  
  Do use 4 characters indentation.
  
  Do NOT use tabs.
  
  Here is how to setup your editor to do the right thing:
  
  =over
  
  =item * x?emacs: cperl-mode
  
    .xemacs/custom.el:
    ------------------
    (custom-set-variables
       '(cperl-indent-level 4)
       '(cperl-continued-statement-offset 4)
       '(cperl-tab-always-indent t)
       '(indent-tabs-mode nil)
    )
  
  =item * vim
  
    .vimrc:
    -------
    set expandtab " replaces any tab keypress with the appropriate number of 
spaces
    set tabstop=4 " sets tabs to 4 spaces
  
  =back
  
  
  =item Block Braces
  
  Do use a style similar to K&R style, not the same. The following
  example is the best guide:
  
  Do:
  
     sub foo {
         my($self, $cond, $baz, $taz) = @_;
    
         if ($cond) {
             bar();
         }
         else {
             $self->foo("one", 2, "...");
         }
    
         return $self;
     }
  
  Don't:
  
     sub foo
     {
         my ($self,$bar,$baz,$taz)[EMAIL PROTECTED];
         if( $cond )
         {
             &bar();
         } else { $self->foo ("one",2,"..."); }
         return $self;
     }
  
  =item Lists and Arrays
  
  Whenever you create a list or an array, always add a comma after the
  last item. The reason for doing this is that it's highly probable that
  new items will be appended to the end of the list in the future. If
  the comma is missing and this isn't noticed, there will be an error.
  
  Do:
  
    my @list = (
        "item1",
        "item2",
        "item3",
    );
  
  
  Don't:
  
    my @list = (
        "item1",
        "item2",
        "item3"
    );
  
  =item Last Statement in the Block
  
  The same goes for C<;> in the last statement of the block. Almost
  always add it even if it's not required, so when you add a new
  statement you don't have to remember to add C<;> on a previous line.
  
  Do:0
  
    sub foo {
        statement1;
        statement2;
        statement3;
    }
  
  Don't
  
    sub foo {
        statement1;
        statement2;
        statement3
    }
  
  =back
  
  
  
  =head1 Function and Variable Prefixes Convention
  
  =over 4
  
  =item modperl_
  
  The prefix for mod_perl C API functions.
  
  =item MP_
  
  The prefix for mod_perl C macros.
  
  =item mpxs_
  
  The prefix for mod_perl XS utility functions.
  
  =item mp_xs_
  
  The prefix for mod_perl I<generated> XS utility functions.
  
  =item MPXS_
  
  The prefix for mod_perl XSUBs with an XS() prototype.
  
  =back
  
  
  
  
  
  
  
  =head1 Coding Guidelines
  
  The following are the Perl coding guidelines:
  
  
  =head2 Global Variables
  
  =over 4
  
  =item avoid globals in general
  
  =item avoid $&, $', $`
  
  See C<Devel::SawAmpersand>'s I<README> that explains the evilness.
  Under mod_perl everybody suffers when one is seen anywhere since the
  interpreter is never shutdown.
  
  =back
  
  
  =head2 Modules
  
  =over 4
  
  =item Exporting/Importing
  
  Avoid too much exporting/importing (glob aliases eat up memory)
  
  When you do wish to import from a module try to use an explicit list or
  tag whenever possible, e.g.:
  
    use POSIX qw(strftime);
  
  When you do not wish to import from a module, always use an empty list
  to avoid any import, e.g.:
  
    use IO::File ();
  
  (explain how to use Apache::Status to find imported/exported
  functions)
  
  =back
  
  
  =head2 Methods
  
  =over 4
  
  =item indirect vs direct method calls
  
  Avoid indirect method calls, e.g.
  
  Do:
  
    CGI::Cookie->new
  
  Don't:
  
    new CGI::Cookie
  
  =back
  
  
  
  
  =head2 Inheritance
  
  =over 4
  
  =item Avoid inheriting from certain modules
  
  Exporter.
  To avoid inheriting B<AutoLoader::AUTOLOAD>
  
  Do:
  
    *import = \&Exporter::import;
  
  Don't:
  
    @MyClass::ISA = qw(Exporter);
  
  =back
  
  
  
  
  
  =head2 Symbol tables
  
  =over 4
  
  =item %main::
  
  stay away from C<main::> to avoid namespace clashes
  
  =back
  
  =head2 Use of $_ in loops
  
  Avoid using C<$_> in loops unless it's a short loop and you don't call
  any subs from within the loop. If the loop started as short and then
  started to grow make sure to remove the use of C<$_>:
  
  Do:
  
    for my $idx (1..100) {
        ....more than few lines...
        foo($idx);
        ....
    }
  
  Don't:
  
     for (1..100) {
         ....more than a few statements...
         foo();
         ....
     }
  
  Because foo() might change C<$_> if foo()'s author didn't localize C<$_>.
  
  This is OK:
  
     for (1..100) {
         .... a few statements with no subs called
         # do something with $_
         ....
     }
  
  
  
  
  
  =head1 Maintainers
  
  Maintainer is the person(s) you should contact with updates,
  corrections and patches.
  
  Stas Bekman E<lt>stas *at* stason.orgE<gt>
  
  =head1 Authors
  
  =over
  
  =item * 
  
  Doug MacEachernE<lt>dougm (at) covalent.netE<gt>
  
  =item *
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =back
  
  Only the major authors are listed above. For contributors see the
  Changes file.
  
  =cut
  
  
  
  
  1.1                  modperl-docs/src/docs/2.0/devel/core/explained.pod
  
  Index: explained.pod
  ===================================================================
  =head1 NAME
  
  mod_perl 2.0 Source Code Explained
  
  =head1 Description
  
  This document explains how to navigate the mod_perl source code,
  modify and rebuild the existing code and most important: how to add
  new functionality.
  
  =head1 Project's Filesystem Layout
  
  In its pristine state the project is comprised of the following
  directories and files residing at the root directory of the project:
  
    Apache-Test/      - test kit for mod_perl and Apache::* modules
    ModPerl-Registry/ - ModPerl::Registry sub-project
    build/            - utilities used during project build
    docs/             - documentation
    lib/              - Perl modules
    src/              - C code that builds libmodperl.so
    t/                - mod_perl tests
    todo/             - things to be done
    util/             - useful utilities for developers
    xs/               - source xs code and maps
    Changes           - Changes file
    LICENSE           - ASF LICENSE document
    Makefile.PL       - generates all the needed Makefiles
  
  After building the project, the following root directories and files
  get generated:
  
    Makefile     - Makefile
    WrapXS/      - autogenerated XS code
    blib/        - ready to install version of the package
  
  =head1 Directory src
  
  =head2 Directory src/modules/perl/
  
  The directory I<src/modules/perl> includes the C source files needed
  to build the I<libmodperl> library.
  
  Notice that several files in this directory are autogenerated during
  the I<perl Makefile> stage.
  
  When adding new source files to this directory you should add their
  names to the C<@c_src_names> variable in I<lib/ModPerl/Code.pm>, so
  they will be picked up by the autogenerated I<Makefile>.
  
  =head1 Directory xs/
  
    Apache/                 - Apache specific XS code
    APR/                    - APR specific XS code
    ModPerl/                - ModPerl specific XS code
    maps/                   - 
    tables/                 - 
    Makefile.PL             - 
    modperl_xs_sv_convert.h - 
    modperl_xs_typedefs.h   - 
    modperl_xs_util.h       - 
    typemap                 - 
  
  =head2 xs/Apache, xs/APR and xs/ModPerl
  
  The I<xs/Apache>, I<xs/APR> and I<xs/ModPerl> directories include I<.h> files 
which
  have C and XS code in them. They all have the I<.h> extension because
  they are always C<#include-d>, never compiled into their own object
  file.  and only the file that C<#include-s> an I<.h> file from these
  directories should be able to see what's in there.  Anything else
  belongs in a I<src/modules/perl/foo.c> public API.
  
  =head2 xs/maps
  
  The I<xs/maps> directory includes mapping files which describe how
  Apache Perl API should be constructed and various XS typemapping.
  
  These files get modified whenever:
  
  =over
  
  =item *
  
  a new function is added or the API of the existing one is modified.
  
  =item *
  
  a new struct is added or the existing one is modified
  
  =item *
  
  a new C datatype or Perl typemap is added or an existing one is
  modified.
  
  =back
  
  The execution of:
  
    % make source_scan
  
  or:
  
    % perl build/source_scan.pl 
  
  converts these map files into their Perl table representation in the
  I<xs/tables/current/> directory. This Perl representation is then used
  during C<perl Makefile.PL> to generate the XS code in the I<./WrapXS/>
  directory by the xs_generate() function. This XS code is combined of
  the Apache API Perl glue and mod_perl specific extensions.
  
  NOTE: source_scan requires C::Scan 0.75, which at the moment is
  unreleased, there is a working copy here:
  http://perl.apache.org/~dougm/Scan.pm
  
  
  If you need to skip certain unwanted C defines from being picked by
  the source scanning you can add them to the array
  C<$Apache::ParseSource::defines_unwanted> in
  I<lib/Apache/ParseSource.pm>.
  
  Notice that I<source_scan> target is normally not run during the
  project build process, since the source scanning is not stable yet,
  therefore everytime the map files change, C<make source_scan> should
  be run manually and the updated files ending up in the
  I<xs/tables/current/> directory should be committed to the cvs
  repository.
  
  The I<source_scan> make target is actually to run
  I<build/source_scan.pl>, which can be run directly without needing to
  create I<Makefile> first.
  
  There are three different types of map files in the I<xs/maps/>
  directory:
  
  =over
  
  =item * Functions Mapping
  
    apache_functions.map
    modperl_functions.map
    apr_functions.map
  
  =item * Structures Mapping
  
    apache_structures.map
    apr_structures.map
  
  =item * Types Mapping
  
    apache_types.map
    apr_types.map
    modperl_types.map
  
  =back
  
  The following sections describe the syntax of the files in each group
  
  =head3 Functions Mapping
  
  The functions mapping file is comprised of groups of function
  definitions. Each group starts with a header similar to XS syntax:
  
    MODULE=... PACKAGE=... PREFIX=... BOOT=... ISA=...
  
  where:
  
  =over
  
  =item * C<MODULE>
  
  the module name where the functions should be put.  e.g. C<MODULE
  Apache::Connection> will place the functions into 
  I<WrapXS/Apache/Connection.{pm,xs}>.
  
  =item * C<PACKAGE>
  
  the package name functions belong to, defaults to C<MODULE>.  The
  value of I<guess> indicates that package name should be guessed based
  on first argument found that maps to a Perl class.  If the value is
  not defined and the function's name starts with I<ap_> the C<Apache>
  package will be used, if it starts with I<apr_> then the C<APR>
  package is used.
  
  =item * C<PREFIX>
  
  prefix string to be stripped from the function name.  If not specified
  it defaults to C<PACKAGE>, converted to C name convention, e.g.
  C<APR::Base64> makes the prefix: I<apr_base64_>.  If the converted
  prefix does not match, defaults to I<ap_> or I<apr_>.
  
  =item * C<BOOT>
  
  The C<BOOT> directive tells the XS generator, whether to add the boot
  function to the autogenerated XS file or not. If the value of C<BOOT>
  is not true or it's simply not declared, the boot function won't be
  added.
  
  If the value is true, a boot function will be added to the XS file.
  Note, that this function is not declared in the map file.
  
  The boot function name must be constructed from three parts:
  
    'mpxs_' . MODULE . '_BOOT'
  
  where C<MODULE> is the one declared with C<MODULE=> in the map file.
  
  For example if we want to have an XS boot function for a class
  C<APR::IO>, we create this function in I<xs/APR/IO/APR__IO.h>:
  
    static void mpxs_APR__IO_BOOT(pTHX)
    {
       /* boot code here */
    }
  
  and now we add the C<BOOT=1> declaration to the
  I<xs/maps/modperl_functions.map> file:
  
    MODULE=APR::IO PACKAGE=APR::IO BOOT=1
  
  Notice that the C<PACKAGE=> declaration is a must.
  
  When I<make xs_generate> is run (after running I<make source_scan>),
  it autogenerates I<Wrap/APR/IO/IO.xs> and amongst other things will
  include:
  
    BOOT:
        mpxs_APR__IO_BOOT(aTHXo);
  
  
  =item * C<ISA>
  
  META: complete
  
  =back
  
  Every function definition is declared on a separate line (use C<\> if
  the line is too long), using the following format:
  
    C function name | Dispatch function name | Argspec | Perl alias
  
  where:
  
  =over
  
  =item * C function name
  
  The name of the real C function.
  
  Function names that do not begin with C</^\w/> are skipped. For
  details see: C<%ModPerl::MapUtil::disabled_map>.
  
  The return type can be specified before the C function name. It
  defaults to I<return_type> in C<{Apache,ModPerl}::FunctionTable>.
  
  META: DEFINE nuances
  
  =item * Dispatch function name
  
  Dispatch function name defaults to C function name. If the dispatch
  name is just a prefix (I<mpxs_>, I<MPXS_>) the C function name is
  appended to it.
  
  See the explanation about function naming and arguments passing.
  
  =item * Argspec
  
  The argspec defaults to arguments in
  C<{Apache,ModPerl}::FunctionTable>.  Argument types can be specified
  to override those in the C<FunctionTable>.  Default values can be
  specified, e.g. C<arg=default_value>. Argspec of C<...> indicates
  I<passthru>, calling the function with C<(aTHX_ I32 items, SP **sp, SV
  **MARK)>.
  
  =item * Perl alias
  
  the Perl alias will be created in the current C<PACKAGE>.
  
  =back
  
  =head3 Structures Mapping
  
  META: complete
  
  =head3 Types Mapping
  
  META: complete
  
  =head3 Modifying Maps
  
  As explained in the beginning of this section, whenever the map file
  is modified you need first to run:
  
    % make source_scan
  
  Next check that the conversion to Perl tables is properly done by
  verifying the resulting corresponding file in
  I<xs/tables/current>. For example I<xs/maps/modperl_functions.map> is
  converted into I<xs/tables/current/ModPerl/FunctionTable.pm>.
  
  If you want to do a visual check on how XS code will be generated, run:
  
    % make xs_generate
  
  and verify that the autogenerated XS code under the directory
  I<./WrapXS> is correct. Otherwise build the project normally:
  
     % perl Makefile.PL ...
  
  =head2 XS generation process
  
  As mentioned before XS code is generated in the I<WrapXS> directory
  either during C<perl Makefile.PL> via xs_generate() if
  C<MP_GENERATE_XS=1> is used (which is the default) or explicitly via:
  
    % make xs_generate
  
  In addition it creates a number of files in the I<xs/> directory:
  
    modperl_xs_sv_convert.h
    modperl_xs_typedefs.h
  
  =head1 Gluing Existing APIs
  
  If you have an API that you simply want to provide the Perl interface
  without writing any code... 
  
  META: complete
  
  WrapXS allows you to adjust some arguments and supply default values
  for function arguments without writing any code
  
  META: complete
  
  C<MPXS_> functions are final C<XSUBs> and always accept:
  
    aTHX_ I32 items, SP **sp, SV **MARK
  
  as their arguments. Whereas C<mpxs_> functions are either intermediate
  thin wrappers for the existing C functions or functions that do
  something by themselves. C<MPXS_> functions also can be used for
  writing thin wrappers for C macros.
  
  =head1 Adding Wrappers for existing APIs and Creating New APIs
  
  In certain cases the existing APIs need to be adjusted. There are a
  few reasons for doing this.
  
  First, is to make the given C API more Perlish. For example C
  functions cannot return more than one value, and the pass by reference
  technique is used. This is not Perlish. Perl has no problem returning
  a list of value, and passing by reference is used only when an array
  or a hash in addition to any other variables need to be passes or
  returned from the function. Therefore we may want to adjust the C API
  to return a list rather than passing a reference to a return value,
  which is not intuitive for Perl programmers.
  
  Second, is to adjust the functionality, i.e. we still use the C API
  but may want to adjust its arguments before calling the original
  function, or do something with return values. And of course optionally
  adding some new code.
  
  Third, is to create completely new APIs. It's quite possible that we
  need more functionality built on top of the existing API. In that case
  we simply create new APIs.
  
  The following sections discuss various techniques for retrieving
  function arguments and returning values to the caller. They range from
  using usual C argument passing and returning to more complex Perl
  arguments' stack manipulation. Once you know how to retrieve the
  arguments in various situations and how to put the return values on
  the stack, the rest is usually normal C programming potentially
  involving using Perl APIs.
  
  Let's look at various ways we can declare functions and what options
  various declarions provide to us:
  
  =head2 Functions Returning a Single Value (or Nothing)
  
  If its know deterministically what the function returns and there is
  only a single return value (or nothing is returned == I<void>), we are
  on the C playground and we don't need to manipulate the returning
  stack.  However if the function may return a single value or nothing
  at all, depending on the inputs and the code, we have to manually
  manipulate the stack and therefore this section doesn't apply.
  
  Let's look at various requirements and implement these using simple
  examples. The following testing code exercises the interfaces we are
  about to develop, so refer to this code to see how the functions are
  invoked from Perl and what is returned:
  
    file:t/response/TestApache/coredemo.pm
    ----------------------------------------
    package TestApache::coredemo;
    
    use strict;
    use warnings FATAL => 'all';
    
    use Apache::Const -compile => 'OK';
    
    use Apache::Test;
    use Apache::TestUtil;
    
    use Apache::CoreDemo;
    
    sub handler {
        my $r = shift;
    
        plan $r, tests => 7;
    
        my $a = 7;
        my $b = 3;
        my ($add, $subst);
    
        $add = Apache::CoreDemo::print($a, $b);
        t_debug "print";
        ok !$add;
    
        $add = Apache::CoreDemo::add($a, $b);
        ok t_cmp($a + $b, $add, "add");
    
        $add = Apache::CoreDemo::add_sv($a, $b);
        ok t_cmp($a + $b, $add, "add: return sv");
    
        $add = Apache::CoreDemo::add_sv_sv($a, $b);
        ok t_cmp($a + $b, $add, "add: pass/return svs");
    
        ($add, $subst) = @{ Apache::CoreDemo::add_subst($a, $b) };
        ok t_cmp($a + $b, $add,   "add_subst: add");
        ok t_cmp($a - $b, $subst, "add_subst: subst");
    
        $subst = Apache::CoreDemo::subst_sp($a, $b);
        ok t_cmp($a - $b, $subst, "subst via SP");
    
        Apache::OK;
    }
    
    1;
  
  The first case is the simplest: pass two integer arguments, print
  these to the STDERR stream and return nothing:
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    static MP_INLINE
    void mpxs_Apache__CoreDemo_print(int a, int b)
    {
        fprintf(stderr, "%d, %d\n", a, b);
    }
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
     mpxs_Apache__CoreDemo_print
  
  Now let's say that the I<b> argument is optional and in case it wasn't
  provided, we want to use a default value, e.g. 0. In that case we
  don't need to change the code, but simply adjust the map file to be:
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
     mpxs_Apache__CoreDemo_print | | a, b=0
  
  In the previous example, we didn't list the arguments in the map file
  since they were automatically retrieved from the source code. In this
  example we tell WrapXS to assign a value of C<0> to the argument b, if
  it wasn't supplied by the caller. All the arguments must be listed and
  in the same order as they are defined in the function.
  
  You may add an extra test that test teh default value assignment:
  
        $add = Apache::CoreDemo::add($a);
        ok t_cmp($a + 0, $add, "add (b=0 default)");
  
  The second case: pass two integer arguments and return their sum:
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    static MP_INLINE
    int mpxs_Apache__CoreDemo_add(int a, int b)
    {
        return a + b;
    }
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
     mpxs_Apache__CoreDemo_add
  
  The third case is similar to the previous one, but we return the sum
  as as a Perl scalar. Though in C we say SV*, in the Perl space we will
  get a normal scalar:
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    static MP_INLINE
    SV *mpxs_Apache__CoreDemo_add_sv(pTHX_ int a, int b)
    {
        return newSViv(a + b);
    }
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
     mpxs_Apache__CoreDemo_add_sv
  
  In the second example the XSUB function was converting the returned
  I<int> value to a Perl scalar behind the scenes. In this example we
  return the scalar ourselves. This is of course to demonstrate that you
  can return a Perl scalar, which can be a reference to a complex Perl
  datastructure, which we will see in the fifth example.
  
  The forth case demonstrates that you can pass Perl variables to your
  functions without needing XSUB to do the conversion. In all previous
  examples XSUB was automatically converting Perl scalars in the
  argument list to the corresponding C variables, using the typemap
  definitions.
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    static MP_INLINE
    SV *mpxs_Apache__CoreDemo_add_sv_sv(pTHX_ SV *a_sv, SV *b_sv)
    {
        int a = (int)SvIV(a_sv);
        int b = (int)SvIV(b_sv);
        
        return newSViv(a + b);
    }
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
     mpxs_Apache__CoreDemo_add_sv_sv
  
  So this example is the same simple case of addition, though we
  manually convert the Perl variables to C variables, perform the
  addition operation, convert the result to a Perl Scalar of kind I<IV>
  (Integer Value) and return it directly to the caller.
  
  In case where more than one value needs to be returned, we can still
  implement this without directly manipulating the stack before a
  function returns. The fifth case demonstrates a function that returns
  the result of addition and substruction operations on its arguments:
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    static MP_INLINE
    SV *mpxs_Apache__CoreDemo_add_subst(pTHX_ int a, int b)
    {
        AV *av = newAV();
    
        av_push(av, newSViv(a + b));
        av_push(av, newSViv(a - b));
    
        return newRV_noinc((SV*)av);   
    }
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
     mpxs_Apache__CoreDemo_add_subst
  
  If you look at the corresponding testing code:
  
        ($add, $subst) = @{ Apache::CoreDemo::add_subst($a, $b) };
        ok t_cmp($a + $b, $add,   "add_subst: add");
        ok t_cmp($a - $b, $subst, "add_subst: subst");
  
  you can see that this technique comes at a price of needing to
  dereference the return value to turn it into a list. The actual code
  is very similar to the C<Apache::CoreDemo::add_sv> function which
  was doing only the addition operation and returning a Perl
  scalar. Here we perform the addition and the substraction operation
  and push the two results into a previously created I<AV*> data
  structure, which represents an array. Since only the I<SV>
  datastructures are allowed to be put on stack, we take a reference
  I<RV> (which is of an I<SV> kind) to the existing I<AV> and return it.
  
  The sixth case demonstrates a situation where the number of arguments
  or their types may vary and aren't known at compile time. Though
  notice that we still know that we are returning at compile time (zero
  or one arguments), I<int> in this example:
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    static MP_INLINE
    int mpxs_Apache__CoreDemo_subst_sp(pTHX_ I32 items, SV **MARK, SV **SP)
    {
        int a, b;
    
        if (items != 2) {
            Perl_croak(aTHX_ "usage: ...");
        }
        
        a = mp_xs_sv2_int(*MARK);
        b = mp_xs_sv2_int(*(MARK+1));
        
        return a - b;
    }
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
     mpxs_Apache__CoreDemo_subst_sp | | ...
  
  In the map file we use a special token C<...> which tells the XSUB
  constructor to pass C<items>, C<MARK> and C<SP> arguments to the
  function. The macro C<MARK> points to the first argument passed by the
  caller in the Perl namespace. For example to access the second
  argument to retrieve the value of C<b> we use C<*(MARK+1)>, which if
  you remember represented as an I<SV> variable, which nees to be
  converted to the corresponding C type.
  
  In this example we use the macro I<mp_xs_sv2_int>, automatically
  generated based on the data from the I<xs/typemap> and
  I<xs/maps/*_types.map> files, and placed into the
  I<xs/modperl_xs_sv_convert.h> file. In the case of I<int> C type the
  macro is:
  
    #define mp_xs_sv2_int(sv) (int)SvIV(sv)
  
  which simply converts the I<SV> variable on the stack and generates an
  I<int> value.
  
  While in this example you have an access to the stack, you cannot
  manipulate the return values, because the XSUB wrapper expects a
  single return value of type I<int>, so even if you put something on
  the stack it will be ignored.
  
  
  =head2 Functions Returning Variable Number of Values
  
  We saw earlier that if we want to return an array one of the ways to
  go is to return a reference to an array as a single return value,
  which fits the C paradigm. So we simply declare the return value as
  C<SV*>.
  
  This section talks about cases where it's unknown at compile time how
  many return values will be or it's known that there will be more than
  one return value--something that C cannot handle via its return
  mechanism.
  
  Let's rewrite the function C<mpxs_Apache__CoreDemo_add_subst> from
  the earlier section to return two results instead of a reference to a
  list:
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    static XS(MPXS_Apache__CoreDemo_add_subst_sp)
    {
        dXSARGS;
        int a, b;
        
        if (items != 2) {
            Perl_croak(aTHX_ "usage: Apache::CoreDemo::add_subst_sp($a, $b)");
        }
        a = mp_xs_sv2_int(ST(0));
        b = mp_xs_sv2_int(ST(1));
        
        SP -= items;
        
        if (GIMME == G_ARRAY) {
        EXTEND(sp, 2);
        PUSHs(sv_2mortal(newSViv(a + b)));
        PUSHs(sv_2mortal(newSViv(a - b)));
        }
        else {
            XPUSHs(sv_2mortal(newSViv(a + b)));
        }
    
        PUTBACK;
    }
  
  Before explaining the function here is the prototype we add to the map
  file:
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
    DEFINE_add_subst_sp | MPXS_Apache__CoreDemo_add_subst_sp | ...
  
  The C<mpxs_> functions declare in the third column the arguments that
  they expect to receive (and optionally the default values). The
  C<MPXS> functions are the real C<XSUBs> and therefore they always
  accept:
  
    aTHX_ I32 items, SP **sp, SV **MARK
  
  as their arguments. Thefore it doesn't matter what is placed in this
  column when the C<MPXS_> function is declared. Usually for
  documentation the Perl side arguments are listed. For example you can
  say:
  
    DEFINE_add_subst_sp | MPXS_Apache__CoreDemo_add_subst_sp | x, y
  
  In this function we manually manipulate the stack to retrieve the
  arguments passed on the Perl side and put the results back onto the
  stack.  Therefore the first thing we do is to initialize a few special
  variables using the C<dXSARGS> macro defined in I<XSUB.h>, which in
  fact calls a bunch of other macros. These variables help to manipulate
  the stack. C<dSP> is one of these macros and it declares and initial­
  izes a local copy of the Perl stack pointer C<sp> which . This local
  copy should always be accessed as C<SP>.
  
  We retrieve the original function arguments using the C<ST()>
  macros. C<ST(0)> and C<ST(1)> point to the first and the second
  argument on the stack, respectively. But first we check that we have
  exactly two arguments on the stack, and if not we abort the
  function. The C<items> variable is the function argument.
  
  Once we have retrieved all the arguments from the stack we set the
  local stack pointer C<SP> to point to the bottom of the stack (like
  there are no items on the stack):
  
        SP -= items;
  
  Now we can do whatever processing is needed and put the results back
  on the stack. In our example we return the results of addition and
  substraction operations if the function is called in the list
  context. In the scalar context the function returns only the result of
  the addition operation. We use the C<GIMME> macro which tells us the
  context.
  
  In the list context we make sure that we have two spare slots on the
  stack since we are going to push two items, and then we push them
  using the C<PUSHs> macro:
  
        EXTEND(sp, 2);
        PUSHs(sv_2mortal(newSViv(a + b)));
        PUSHs(sv_2mortal(newSViv(a - b)));
  
  Alternatively we could use:
  
        XPUSHs(sv_2mortal(newSViv(a + b)));
        XPUSHs(sv_2mortal(newSViv(a - b)));
  
  The C<XPUSHs> macro eI<X>tends the stack before pushing the item into
  it if needed. If we plan to push more than a single item onto the
  stack, it's more efficient to extend the stack in one call.
  
  In the scalar context we push only one item, so here we use the
  C<XPUSHs> macro:
  
         XPUSHs(sv_2mortal(newSViv(a + b)));
  
  The last command we call is:
  
        PUTBACK;
  
  which makes the local stack pointer global. This is a must call if the
  state of the stack was changed when the function is about to
  return. The stack changes if something was popped from or pushed to
  it, or both and changed the number of items on the stack.
  
  In our example we don't need to call C<PUTBACK> if the function is
  called in the list context. Because in this case we return two
  variables, the same as two function arguments, the count didn't
  change. Though in the scalar context we push onto the stack only one
  argument, so the function won't return what is expected. The simplest
  way to avoid errors here is to always call C<PUTBACK> when the stack
  is changed.
  
  For more information refer to the I<perlcall> manpage which explains
  the stack manipulation process in great details.
  
  Finally we test the function in the list and scalar contexts:
  
    file:t/response/TestApache/coredemo.pm
    ----------------------------------------
    ...
    my $a = 7;
    my $b = 3;
    my ($add, $subst);
    
    # list context
    ($add, $subst) = Apache::CoreDemo::add_subst_sp($a, $b);
    ok t_cmp($a + $b, $add,   "add_subst_sp list context: add");
    ok t_cmp($a - $b, $subst, "add_subst_sp list context: subst");
    
    # scalar context
    $add = Apache::CoreDemo::add_subst_sp($a, $b);
    ok t_cmp($a + $b, $add,   "add_subs_spt scalar context: add");
    ...
  
  =head2 Wrappers Functions for C Macros
  
  Let's say you have a C macro which you want to provide a Perl
  interface for. For example let's take a simple macro which performs
  the power of function:
  
    file:xs/Apache/CoreDemo/Apache__CoreDemo.h
    ----------------------------------------------
    #define mpxs_Apache__CoreDemo_power(x, y) pow(x, y)
  
  To create the XS glue code we use the following entry in the map file:
  
    file:xs/maps/modperl_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
    double:DEFINE_power | | double:x, double:y
  
  This works very similar to the C<MPXS_Apache__CoreDemo_add_subst_sp>
  function presented earlier. But since this is a macro the XS wrapper
  needs to know the types of the arguments and the return type, so these
  are added. The return type is added just before the function name and
  separated from it by the colon (C<:>), the argument types are
  specified in the third column. The type is always separated from the
  name of the variable by the colon (C<:>).
  
  And of course finally we need to test that the function works in Perl:
  
    file:t/response/TestApache/coredemo.pm
    ----------------------------------------
    ...
    my $a = 7;
    my $b = 3;
    my $power = Apache::CoreDemo::power($a, $b);
    ok t_cmp($a ** $b, $power, "power macro");
    ...
  
  =head1 Wrappers for modperl_, apr_ and ap_ APIs
  
  If you already have a C function whose name starts from I<modperl_>,
  I<apr_> or I<ap_> and you want to do something before calling the real
  C function, you can write a XS wrapper using the same method as in the
  L<MPXS_Apache__CoreDemo_add_subst_sp
  |/Functions_Returning_Variable_Number_of_Values>. The only difference
  is that it'll be clearly seen in the map file that this is a wrapper
  for an existing C API.
  
  Let's say that we have an existing C function apr_power(), this is how
  we declare its wrapper:
  
    file:xs/maps/apr_functions.map
    ----------------------------------
    MODULE=APR::Foo
    apr_power | MPXS_ | x, y
  
  The first column specifies the existing function's name, the second
  tells that the XS wrapper will use the C<MPXS_> prefix, which means
  that the wrapper must be called C<MPXS_apr_power>. The third column
  specifies the argument names, but for C<MPXS_> no matter what you
  specify there the C<...> will be passed:
  
    aTHX_ I32 items, SP **sp, SV **MARK
  
  so you can leave that column empty, but here we use C<x> and C<y> to
  remind us that these two arguments are passed from Perl.
  
  If the forth column is empty this function will be called
  C<APR::Foo::power> in the Perl namespace. But you can use that column
  to give a different Perl name, e.g with:
  
    apr_power | MPXS_ | x, y | pow
  
  This function will be available from Perl as C<APR::Foo::pow>.
  
  Similarly you can write a C<MPXS_modperl_power> wrapper for a
  C<modperl_power()> function but here you have to explicitly give the
  Perl function's name in the forth column:
  
    file:xs/maps/apr_functions.map
    ----------------------------------
    MODULE=Apache::CoreDemo
    modperl_power | MPXS_ | x, y | mypower
  
  and the Perl function will be called C<Apache::CoreDemo::mypower>.
  
  The C<MPXS_> wrapper's implementation is similar to
  L<MPXS_Apache__CoreDemo_add_subst_sp
  |/Functions_Returning_Variable_Number_of_Values>.
  
  =head1 MP_INLINE vs C Macros vs Normal Functions
  
  To make the code maintainable and reusable functions and macros are
  used in when programming in C (and other languages :).
  
  When function is marked as I<inlined> it's merely a hint to the
  compiler to replace the call to a function with the code inside this
  function (i.e. inlined). Not every function can be inlined. Some
  typical reasons why inlining is sometimes not done include:
  
  =over
  
  =item *
  
  the function calls itself, that is, is recursive
  
  =item *
  
  the function contains loops such as C<for(;;)> or C<while()>
  
  =item *
  
  the function size is too large
  
  =back
  
  Most of the advantage of inline functions comes from avoiding the
  overhead of calling an actual function. Such overhead includes saving
  registers, setting up stack frames, etc. But with large functions the
  overhead becomes less important.
  
  Use the C<MP_INLINE> keyword in the declaration of the functions that
  are to be inlined. The functions should be inlined when:
  
  =over
  
  =item *
  
  Only ever called once (the I<wrappers> that are called from I<.xs>
  files), no matter what the size of code is.
  
  =item *
  
  Short bodies of code called in a I<hot> code (like
  I<modperl_env_hv_store>, which is called many times inside of a loop),
  where it is cleaner to see the code in function form rather than macro
  with lots of C<\>'s. Remember that an inline function takes much more
  space than a normal functions if called from many places in the code.
  
  =back
  
  Of course C macros are a bit faster then inlined functions, since
  there is not even I<short jump> to be made, the code is literally
  copied into the place it's called from. However using macros comes at
  a price:
  
  =over
  
  =item *
  
  Also unlike macros, in functions argument types are checked, and
  necessary conversions are performed correctly. With macros it's
  possible that weird things will happen if the caller has passed
  arguments of the wrong type when calling a macro.
  
  =item *
  
  One should be careful to pass only absolute values as I<"arguments">
  to macros. Consider a macro that returns an absolute value of the
  passed argument:
  
    #define ABS(v) ( (v) >= 0 ? (v) : -(v) )
  
  In our example if you happen to pass a function it will be called
  twice:
  
    abs_val = ABS(f());
  
  Since it'll be extended as:
  
    abs_val = f() >= 0 ? f() : -f();
  
  You cannot do simple operation like increment--in our example it will
  be called twice:
  
    abs_val = ABS(i++);
  
  Because it becomes:
  
    abs_val = i++ >= 0 ? i++ : -i++;
  
  =item *
  
  It's dangerous to use the if() condition without enclosing the code in
  C<{}>, since the macro may be called from inside another if-else
  condition, which may cause the else part called if the if() part from
  the macro fails.
  
  But we always use C<{}> for the code inside the if-else condition, so
  it's not a problem here.
  
  =item *
  
  A multi-line macro can cause problems if someone uses the macro in a
  context that demands a single statement.
  
    while (foo) MYMACRO(bar);
  
  But again, we always enclose any code in conditional with C<{}>, so
  it's not a problem for us.
  
  =item *
  
  Inline functions present a problem for debuggers and profilers,
  because the function is expanded at the point of call and loses its
  identity. This makes the debugging process a nightmare.
  
  A compiler will typically have some option available to disable
  inlining.
  
  =back
  
  In all other cases use normal functions.
  
  =head1 Adding New Interfaces
  
  
  
  =head2 Adding Typemaps for new C Data Types
  
  Sometimes when a new interface is added it may include C data types
  for which we don't have corresponding XS typemaps yet. In such a case,
  the first thing to do is to provide the required typemaps.
  
  Let's add a prototype for the I<typedef struct scoreboard> data type
  defined in I<httpd-2.0/include/scoreboard.h>.
  
  First we include the relevant header files in
  I<src/modules/perl/modperl_apache_includes.h>:
  
    #include "scoreboard.h"
  
  If you want to specify your own type and don't have a header file for
  it (e.g. if you extend some existing datatype within mod_perl) you may
  add the I<typedef> to I<src/modules/perl/modperl_types.h>.
  
  After deciding that C<Apache::Scoreboard> is the Perl class will be
  used for manipulating C I<scoreboard> data structures, we map the
  I<scoreboard> data structure to the C<Apache::Scoreboard>
  class. Therefore we add to I<xs/maps/apache_types.map>:
  
    struct scoreboard       | Apache::Scoreboard
  
  Since we want the I<scoreboard> data structure to be an opaque object
  on the perl side, we simply let mod_perl use the default C<T_PTROBJ>
  typemap. After running C<make xs_generate> you can check the assigned
  typemap in the autogenerated I<WrapXS/typemap> file.
  
  If you need to do some special handling while converting from C to
  Perl and back, you need to add the conversion functions to the
  I<xs/typemap> file. For example the C<Apache::RequestRec> objects need
  special handling, so you can see the special C<INPUT> and C<OUTPUT>
  typemappings for the corresponding C<T_APACHEOBJ> object type.
  
  Now we run C<make xs_generate> and find the following definitions in
  the autogenerated files:
  
    file:xs/modperl_xs_typedefs.h
    -----------------------------
    typedef scoreboard * Apache__Scoreboard;
  
    file:xs/modperl_xs_sv_convert.h
    -------------------------------
    #define mp_xs_sv2_Apache__Scoreboard(sv) \
    ((SvROK(sv) && (SvTYPE(SvRV(sv)) == SVt_PVMG)) \
    || (Perl_croak(aTHX_ "argument is not a blessed reference \
    (expecting an Apache::Scoreboard derived object)"),0) ? \
    (scoreboard *)SvIV((SV*)SvRV(sv)) : (scoreboard *)NULL)
    
    #define mp_xs_Apache__Scoreboard_2obj(ptr) \
    sv_setref_pv(sv_newmortal(), "Apache::Scoreboard", (void*)ptr)
  
  The file I<xs/modperl_xs_typedefs.h> declares the typemapping from C
  to Perl and equivalent to the C<TYPEMAP> section of the XS's
  I<typemap> file. The second file I<xs/modperl_xs_sv_convert.h>
  generates two macros. The first macro is used to convert from Perl to
  C datatype and equivalent to the I<typemap> file's C<INPUT>
  section. The second macro is used to convert from C to Perl datatype
  and equivalent to the I<typemap>'s C<OUTPUT> section.
  
  Now proceed on adding the glue code for the new interface.
  
  =head2 Importing Constants and Enums into Perl API
  
  To I<import> httpd and APR constants and enums into Perl API, edit
  I<lib/Apache/ParseSource.pm>. To add a new type of C<DEFINE> constants
  adjust the C<%defines_wanted> variable, for C<enums> modify
  C<%enums_wanted>.
  
  For example to import all C<DEFINE>s starting with C<APR_FLOCK_> add:
  
    my %defines_wanted = (
        ...
        APR => {
            ...
            flock     => [qw{APR_FLOCK_}],
            ...
        },
    );
  
  When deciding which constants are to be exported, the regular
  expression will be used, so in our example all matches
  C</^APR_FLOCK_/> will be imported into the Perl API.
  
  For example to import an I<read_type_e> C<enum> for APR, add:
  
    my %enums_wanted = (
        APR => { map { $_, 1 } qw(apr_read_type) },
    );
  
  Notice that I<_e> part at the end of the enum name has gone.
  
  After adding/modifying the datastructures make sure to run C<make
  source_scan> or C<perl build/source_scan.pl> and verify that the
  wanted constant or enum were picked by the source scanning
  process. Simply grep I<xs/tables/current> for the wanted string. For
  example after adding I<apr_read_type_e> enum we can check:
  
    % more xs/tables/current/Apache/ConstantsTable.pm
    ...
      'read_type' => [
        'APR_BLOCK_READ',
        'APR_NONBLOCK_READ'
      ],
  
  Of course the newly added constant or enum's typemap should be
  declared in the appropriate I<xs/maps/*_types.map> files, so the XS
  conversion of arguments will be performed correctly. For example
  I<apr_read_type> is an APR enum so it's declared in
  I<xs/maps/apr_types.map>:
  
    apr_read_type          | IV
  
  C<IV> is used as a typemap, Since enum is just an integer. In more
  complex cases the typemap can be different. (META: examples)
  
  
  =head1 Maintainers
  
  Maintainer is the person(s) you should contact with updates,
  corrections and patches.
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =head1 Authors
  
  =over 
  
  =item *
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =back
  
  Only the major authors are listed above. For contributors see the
  Changes file.
  
  =cut
  
  
  
  1.1                  modperl-docs/src/docs/2.0/devel/debug/c.pod
  
  Index: c.pod
  ===================================================================
  =head1 NAME
  
  Debugging mod_perl C Internals
  
  =head1 Description
  
  This document explains how to debug C code under mod_perl, including
  mod_perl core itself.
  
  =head1 Debug notes
  
  META: needs more organization
  
  =head2 Setting gdb breakpoints with mod_perl built as DSO
  
  If mod_perl is built as a DSO module, you cannot set the breakpoint in
  the mod_perl source files when the I<httpd> program gets loaded into
  the debugger. The reason is simple: At this moment I<httpd> has no
  idea about mod_perl module yet. After the configuration file is
  processed and the mod_perl DSO module is loaded then the breakpoints
  in the source of mod_perl itself can be set.
  
  The trick is to break at I<apr_dso_load>, let it load
  I<libmodperl.so>, then you can set breakpoints anywhere in the modperl
  code:
  
    % gdb httpd
    (gdb) b apr_dso_load
    (gdb) run -DONE_PROCESS
    [New Thread 1024 (LWP 1600)]
    [Switching to Thread 1024 (LWP 1600)]
  
    Breakpoint 1, apr_dso_load (res_handle=0xbfffb48c, path=0x811adcc
      "/home/stas/apache.org/modperl-perlmodule/src/modules/perl/libmodperl.so",
      pool=0x80e1a3c) at dso.c:138
    141         void *os_handle = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
    (gdb) finish
    ...
    Value returned is $1 = 0
    (gdb) b modperl_hook_init
    (gdb) continue
  
  This example shows how to set a breakpoint at I<modperl_hook_init>.
  
  To automate things you can put those in the I<.gdb-jump-to-init> file:
  
    b apr_dso_load
    run -DONE_PROCESS -d `pwd`/t -f `pwd`/t/conf/httpd.conf
    finish
    b modperl_hook_init
    continue
  
  and then start the debugger with:
  
    % gdb /home/stas/httpd-2.0/bin/httpd -command \
    `pwd`/t/.gdb-jump-to-init
  
  =head2 Starting the Server Fast under gdb
  
  When the server is started under gdb, it first loads the symbol tables
  of the dynamic libraries that it sees going to be used. Some versions
  of gdb may take ages to complete this task, which makes the debugging
  very irritating if you have to restart the server all the time and it
  doesn't happen immediately.
  
  The trick is to set the C<auto-solib-add> flag to 0:
  
    set auto-solib-add 0
  
  as early as possible in I<~/.gdbinit> file.
  
  With this setting in effect, you can load only the needed dynamic
  libraries with I<sharedlibrary> command. Remember that in order to set
  a breakpoint and step through the code inside a certain dynamic
  library you have to load it first. For example consider this gdb
  commands file:
  
    .gdb-commands
    ------------
    file ~/httpd/prefork/bin/httpd
    handle SIGPIPE pass
    handle SIGPIPE nostop
    set auto-solib-add 0
    b ap_run_pre_config
    run -d `pwd`/t -f `pwd`/t/conf/httpd.conf \
    -DONE_PROCESS -DAPACHE2 -DPERL_USEITHREADS
    sharedlibrary modperl
    b modperl_hook_init
    # start: modperl_hook_init
    continue
    # restart: ap_run_pre_config
    continue
    # restart: modperl_hook_init
    continue
    b apr_poll
    continue
    
    # load APR/PerlIO/PerlIO.so
    sharedlibrary PerlIO
    b PerlIOAPR_open
  
  which can be used as:
  
    % gdb -command=.gdb-commands
  
  This script stops in I<modperl_hook_init()>, so you can step through
  the mod_perl startup. We had to use the I<ap_run_pre_config> so we can
  load the I<libmodperl.so> library as explained earlier. Since httpd
  restarts on the start, we have to I<continue> until we hit
  I<modperl_hook_init> second time, where we can set the breakpoint at
  I<apr_poll>, the very point where httpd polls for new request and run
  again I<continue> so it'll stop at I<apr_poll>. This particular script
  passes over modperl_hook_init(), since we run the C<continue> command
  a few times to reach the I<apr_poll> breakpoint. See the L<Precooked
  gdb Startup Scripts|/Precooked_gdb_Startup_Scripts> section for
  standalone script examples.
  
  When gdb stops at the function I<apr_poll> it's a time to start the
  client, that will issue a request that will exercise the server
  execution path we want to debug. For example to debug the
  implementation of C<APR::Pool> we may run:
  
    % t/TEST -run apr/pool
  
  which will trigger the run of a handler in
  I<t/response/TestAPR/pool.pm> which in turn tests the C<APR::Pool>
  code.
  
  But before that if we want to debug the server response we need to set
  breakpoints in the libraries we want to debug. For example if we want
  to debug the function C<PerlIOAPR_open> which resides in
  I<APR/PerlIO/PerlIO.so> we first load it and then we can set a
  breakpoint in it. Notice that gdb may not be able to load a library if
  it wasn't referenced by any of the code. In this case we have to load
  this library at the server startup. In our example we load:
  
    PerlModule APR::PerlIO
  
  in I<httpd.conf>. To check which libraries' symbol tables can be
  loaded in gdb, run (when the server has been started):
  
    gdb> info sharedlibrary
  
  which also shows which libraries are loaded already.
  
  Also notice that you don't have to type the full path of the library
  when trying to load them, even a partial name will suffice. In our
  commands file example we have used C<sharedlibrary modperl> instead of
  saying C<sharedlibrary libmodperl.so>.
  
  If you want to set breakpoints and step through the code in the Perl
  and APR core libraries you should load their appropriate libraries:
  
    gdb> sharedlibrary libperl
    gdb> sharedlibrary libapr
    gdb> sharedlibrary libaprutil
  
  Setting I<auto-solib-add> to 0 makes the debugging process unusual,
  since originally gdb was loading the dynamic libraries automatically,
  whereas now it doesn't. This is the price one has to pay to get the
  debugger starting the program very fast. Hopefully the future versions
  of gdb will improve.
  
  Just remember that if you try to I<step-in> and debugger doesn't do
  anything, that means that the library the function is located in
  wasn't loaded. The solution is to create a commands file as explained
  in the beginning of this section and craft the startup script the way
  you need to avoid extra typing and mistakes when repeating the same
  debugging process again and again.
  
  Another important thing is that whenever you want to be able to see
  the source code for the code you are stepping through, the library or
  the executable you are in must have the debug symbols present. That
  means that the code has to be compiled with I<-g> option for the gcc
  compiler. For example if I want to set a breakpoint in /lib/libc.so, I
  can do that by loading:
  
   gdb> sharedlibrary /lib/libc.so
  
  But most likely that this library has the debug symbols stripped off,
  so while gdb will be able to break at the breakpoint set inside this
  library, you won't be able to step through the code. In order to do
  so, recompile the library to add the debug symbols.
  
  If debug code in response handler you usually start the client after
  the server was started, when doing this a lot you may find it annoying
  to need to wait before the client can be started. Therefore you can
  use a few tricks to do it in one command. If the server starts fast
  you can use sleep():
  
    % ddd -command=.debug-modperl-init & ; \
    sleep 2 ; t/TEST -verbose -run apr/pool
  
  or the C<Apache::Test> framework's C<-ping=block> option:
  
    % ddd -command=.debug-modperl-init & ; \
    t/TEST -verbose -run -ping=block apr/pool
  
  which will block till the server starts responding, and only then will
  try to run the test.
  
  =head2 Precooked gdb Startup Scripts
  
  Here are a few startup scripts you can use with gdb to accomplish one
  of the common debugging tasks. To execute the startup script, simply run:
  
   % gdb -command=.debug-script-filename
  
  They can be run under gdb and any of the gdb front-ends. For example
  to run the scripts under C<ddd> substitute C<gdb> with C<ddd>:
  
   % ddd -command=.debug-script-filename
  
  =over
  
  =item * Debugging mod_perl Initialization
  
  The F<code/.debug-modperl-init> startup script breaks at the
  C<modperl_hook_init()> function, which is useful for debugging code at
  the modperl's initialization phase.
  
  =item * Debugging mod_perl's Hooks Registeration With httpd
  
  Similar to the previous startup script, the
  F<code/.debug-modperl-register> startup script breaks at the
  C<modperl_register_hooks()>, which is the very first hook called in
  the mod_perl land. Therefore use this one if you need to start
  debugging at an even earlier entry point into mod_perl.
  
  Refer to the notes inside the script to adjust it for a specific
  I<httpd.conf> file.
  
  =item * Debugging mod_perl XS Extensions
  
  The F<code/.debug-modperl-xs> startup script breaks at the
  C<mpxs_Apache__Filter_print()> function implemented in
  I<xs/Apache/Filter/Apache__Filter.h>. This is an example of debugging
  code in XS Extensions. For this particular example the complete test
  case is:
  
    % ddd -command=.debug-modperl-xs & \
    t/TEST -v -run -ping=block filter/api
  
  When I<filter/api> test is running it calls
  mpxs_Apache__Filter_print() which is when the breakpoint is reached.
  
  =back
  
  
  =head1 Obtaining Core Files
  
  META: need to review (unfinished)
  
  =head2 ...
  
  
  =head1 Analyzing Dumped Core Files
  
  When your application dies with the I<Segmentation fault> error (which
  generates a C<SIGSEGV> signal) and optionally generates a I<core> file
  you can use C<gdb> or a similar debugger to find out what caused the
  I<Segmentation fault> (or I<segfault> as we often call it).
  
  =head2 Getting Ready to Debug
  
  In order to debug the I<core> file we may need to recompile Perl and
  mod_perl with debugging symbols inside. Usually you have to recompile
  only mod_perl, but if the I<core> dump happens in the I<libmodperl.so>
  library and you want to see the whole backtrace, you probably want to
  recompile Perl as well.
  
  Recompile Perl with I<-DDEBUGGING> during the ./Configure stage (or
  even better with I<-Doptimize="-g"> which in addition to adding the
  C<-DDEBUGGING> option, adds the I<-g> options which allows you to
  debug the Perl interpreter itself).
  
  After recompiling Perl, recompile mod_perl with C<MP_DEBUG=1> during
  the I<Makefile.PL> stage.
  
  Building mod_perl with C<PERL_DEBUG=1> will:
  
  =over
  
  =item 1 
  
  add `-g' to EXTRA_CFLAGS
  
  =item 1 
  
  turn on MP_TRACE (tracing)
  
  =item 1 
  
  Set PERL_DESTRUCT_LEVEL=2
  
  =item 1 
  
  Link against C<libperld> if -e 
$Config{archlibexp}/CORE/libperld$Config{lib_ext}
  
  =back
  
  If you build a static mod_perl, remember that during I<make install>
  Apache strips all the debugging symbols.  To prevent this you should
  use the Apache I<--without-execstrip> C<./configure> option. So if you
  configure Apache via mod_perl, you should do:
  
    panic% perl Makefile.PL USE_APACI=1 \
      APACI_ARGS='--without-execstrip' [other options]
  
  Alternatively you can copy the unstripped binary manually. For example
  we did this to give us an Apache binary called C<httpd_perl> which
  contains debugging symbols:
  
    panic# cp httpd-2.x/httpd /home/httpd/httpd_perl/bin/httpd_perl
  
  Now the software is ready for a proper debug.
  
  =head2 Creating a Faulty Package
  
  Next stage is to create a package that aborts abnormally with the
  I<Segmentation fault> error. We will write faulty code on purpose,
  so you will be able to reproduce the problem and exercise the
  debugging technique explained here. Of course in a real case you
  will have some real bug to debug, so in that case you may want to
  skip this stage of writing a program with a deliberate bug.
  
  We will use the C<Inline.pm> module to embed some code written in C
  into our Perl script. The faulty function that we will add is this:
  
    void segv() {
        int *p;
        p = NULL;
        printf("%d", *p); /* cause a segfault */
    }
  
  For those of you not familiar with C programming, I<p> is a pointer to
  a segment of memory.  Setting it to C<NULL> ensures that we try to
  read from a segment of memory to which the operating system does not
  allow us access, so of course dereferencing C<NULL> pointer causes a
  segmentation fault.  And that's what we want.
  
  So let's create the C<Bad::Segv> package. The name I<Segv> comes from
  the C<SIGSEGV> (segmentation violation signal) that is generated when
  the I<Segmentation fault> occurs.
  
  First we create the installation sources:
  
    panic% h2xs -n Bad::Segv -A -O -X
    Writing Bad/Segv/Segv.pm
    Writing Bad/Segv/Makefile.PL
    Writing Bad/Segv/test.pl
    Writing Bad/Segv/Changes
    Writing Bad/Segv/MANIFEST
  
  Now we modify the I<Segv.pm> file to include the C code. Afterwards
  it looks like this:
  
    package Bad::Segv;
    
    use strict;
    BEGIN {
        $Bad::Segv::VERSION = '0.01';
    }
    
    use Inline C => <<'END_OF_C_CODE';
      void segv() {
          int *p;
          p = NULL;
          printf("%d", *p); /* cause a segfault */
      }
    
    END_OF_C_CODE
    
    1;
  
  Finally we modify I<test.pl>:
  
    use Inline SITE_INSTALL;
    
    BEGIN { $| = 1; print "1..1\n"; }
    END {print "not ok 1\n" unless $loaded;}
    use Bad::Segv;
    
    $loaded = 1;
    print "ok 1\n";
  
  Note that we don't test Bad::Segv::segv() in I<test.pl>, since this
  will abort the I<make test> stage abnormally, and we don't want this.
  
  Now we build and install the package:
  
    panic% perl Makefile.PL
    panic% make && make test
    panic% su
    panic# make install
  
  Running I<make test> is essential for C<Inline.pm> to prepare the binary
  object for the installation during I<make install>.
  
  
  META: stopped here!
  
  Now we can test the package:
  
    panic% ulimit -c unlimited
    panic% perl -MBad::Segv -e 'Bad::Segv::segv()'
    Segmentation fault (core dumped)
    panic% ls -l core
    -rw-------  1  stas stas 1359872  Feb 6  14:08 core
  
  Indeed, we can see that the I<core> file was dumped, which will be used
  to present the debug techniques.
  
  =head2 Getting the core File Dumped
  
  Now let's get the I<core> file dumped from within the mod_perl
  server. Sometimes the program aborts abnormally via the SIGSEGV signal
  (I<Segmentation Fault>), but no I<core> file is dumped. And without
  the I<core> file it's hard to find the cause of the problem, unless
  you run the program inside C<gdb> or another debugger in first
  place. In order to get the I<core> file, the application has to:
  
  =over
  
  =item *
  
  have the effective UID the same as real UID (the same goes for
  GID). Which is the case of mod_perl unless you modify these settings
  in the program.
  
  =item *
  
  be running from a directory which at the moment of the
  I<Segmentation fault> is writable by the process. Notice that the
  program might change its current directory during its run, so it's
  possible that the I<core> file will need to be dumped in a different
  directory from the one the program was started from. For example when
  mod_perl runs an C<Apache::Registry> script it changes its directory
  to the one in which the script source is located.
  
  =item *
  
  be started from a shell process with sufficient resource allocations
  for the I<core> file to be dumped. You can override the default
  setting from within a shell script if the process is not started
  manually. In addition you can use C<BSD::Resource> to manipulate the
  setting from within the code as well.
  
  You can use C<ulimit> for C<bash> and C<limit> for C<csh> to check and
  adjust the resource allocation. For example inside C<bash>, you may
  set the core file size to unlimited:
  
    panic% ulimit -c unlimited
  
  or for C<csh>:
  
    panic% limit coredumpsize unlimited
  
  For example you can set an upper limit on the I<core> file size to 8MB
  with:
  
    panic% ulimit -c 8388608
  
  So if the core file is bigger than 8MB it will be not created.
  
  =item *
  
  Of course you have to make sure that you have enough disk space to
  create a big core file (mod_perl I<core> files tend to be of a few
  MB in size).
  
  =back
  
  Note that when you are running the program under a debugger like
  C<gdb>, which traps the C<SIGSEGV> signal, the I<core> file will not
  be dumped. Instead it allows you to examine the program stack and
  other things without having the I<core> file.
  
  So let's write a simple script that uses C<Bad::Segv>:
  
    core_dump.pl
    ------------
    use strict;
    use Bad::Segv ();
    use Cwd()
    
    my $r = shift;
    $r->content_type('text/plain');
    
    my $dir = getcwd;
    $r->print("The core should be found at $dir/core\n");
    Bad::Segv::segv();
  
  In this script we load the C<Bad::Segv> and C<Cwd> modules. After
  that we acquire the request object and send the HTTP header. Now we
  come to the real part--we get the current working directory, print out
  the location of the I<core> file that we are about to dump and finally
  we call Bad::Segv::segv() which dumps the I<core> file.
  
  Before we run the script we make sure that the shell sets the I<core>
  file size to be unlimited, start the server in single server mode as a
  non-root user and generate a request to the script:
  
    panic% cd /home/httpd/httpd_perl/bin
    panic% limit coredumpsize unlimited
    panic% ./httpd_perl -X
        # issue a request here
    Segmentation fault (core dumped)
  
  Our browser prints out:
  
    The core should be found at /home/httpd/perl/core
  
  And indeed the core file appears where we were told it will (remember
  that C<Apache::Registry> scripts change their directory to the
  location of the script source):
  
    panic% ls -l /home/httpd/perl/core
    -rw------- 1 stas httpd 3227648 Feb 7 18:53 /home/httpd/perl/core
  
  As you can see it's a 3MB I<core> file. Notice that mod_perl was
  started as user I<stas>, which had write permission for directory
  I</home/httpd/perl>.
  
  
  =head2 Analyzing the core File
  
  First we start C<gdb>:
  
    panic% gdb /home/httpd/httpd_perl/bin/httpd_perl /home/httpd/perl/core
  
  with the location of the mod_perl executable and the core file as the
  arguments.
  
  To see the backtrace you run the I<where> or the I<bt> command:
  
    (gdb) where
    #0  0x4025ea08 in XS_Apache__Segv_segv ()
       from 
/usr/lib/perl5/site_perl/5.6.0/i386-linux/auto/Bad/Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39/Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39.so
    #1  0x40136528 in PL_curcopdb ()
       from /usr/lib/perl5/5.6.0/i386-linux/CORE/libperl.so
  
  Well, you can see the last commands, but our perl and mod_perl are
  probably without the debug symbols. So we recompile Perl and mod_perl
  with debug symbols as explained earlier in this chapter.
  
  Now when we repeat the process of starting the server, issuing a
  request and getting the core file, after which we run C<gdb> again
  against the executable and the dumped I<core> file.
  
    panic% gdb /home/httpd/httpd_perl/bin/httpd_perl /home/httpd/perl/core
  
  Now we can see the whole backtrace:
  
    (gdb) bt
    #0  0x40323a30 in segv () at 
Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39.xs:9
    #1  0x40323af8 in XS_Apache__Segv_segv (cv=0x85f2b28)
        at Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39.xs:24
    #2  0x400fcbda in Perl_pp_entersub () at pp_hot.c:2615
    #3  0x400f2c56 in Perl_runops_debug () at run.c:53
    #4  0x4008b088 in S_call_body (myop=0xbffff788, is_eval=0) at perl.c:1796
    #5  0x4008ac4f in perl_call_sv (sv=0x82fc2e4, flags=4) at perl.c:1714
    #6  0x807350e in perl_call_handler ()
    #7  0x80729cd in perl_run_stacked_handlers ()
    #8  0x80701b4 in perl_handler ()
    #9  0x809f409 in ap_invoke_handler ()
    #10 0x80b3e8f in ap_some_auth_required ()
    #11 0x80b3efa in ap_process_request ()
    #12 0x80aae60 in ap_child_terminate ()
    #13 0x80ab021 in ap_child_terminate ()
    #14 0x80ab19c in ap_child_terminate ()
    #15 0x80ab80c in ap_child_terminate ()
    #16 0x80ac03c in main ()
    #17 0x401b8cbe in __libc_start_main () from /lib/libc.so.6
  
  Reading the trace from bottom to top, we can see that it starts with Apache
  calls, followed by Perl syscalls. At the top we can see the segv()
  call which was the one that caused the Segmentation fault, we can also
  see that the faulty code was at line 9 of I<Segv.xs> file (with MD5
  signature of the code in the name of the file, because of the way
  C<Inline.pm> works). It's a little bit tricky with C<Inline.pm> since
  we have never created any I<.xs> files ourselves, (C<Inline.pm> does
  it behind the scenes). The solution in this case is to tell
  C<Inline.pm> not to cleanup the build directory, so we can see the
  created I<.xs> file.
  
  We go back to the directory with the source of C<Bad::Segv> and
  force the recompilation, while telling C<Inline.pm> not to cleanup
  after the build and to print a lot of other useful info:
  
    panic# cd Bad/Segv
    panic# perl -MInline=FORCE,NOCLEAN,INFO Segv.pm
    Information about the processing of your Inline C code:
    
    Your module is already compiled. It is located at:
    
/home/httpd/perl/Bad/Segv/_Inline/lib/auto/Bad/Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39/Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39.so
    
    But the FORCE_BUILD option is set, so your code will be recompiled.
    I'll use this build directory:
    
/home/httpd/perl/Bad/Segv/_Inline/build/Bad/Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39/
    
    and I'll install the executable as:
    
/home/httpd/perl/Bad/Segv/_Inline/lib/auto/Bad/Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39/Segv_C_0_01_e6b5959d800f515de36a7e7eeab28b39.so
    
    The following Inline C function(s) have been successfully bound to Perl:
      void segv()
  
  It tells us that the code was already compiled, but since we have
  forced it to recompile we can look at the files after the build. So we
  go into the build directory reported by C<Inline.pm> and find the
  I<.xs> file there, where on line 9 we indeed find the faulty code:
  
    9: printf("%d",*p); // cause a segfault
  
  Notice that in our example we knew what script has caused the
  Segmentation fault. In a real world the chances are that you will find 
  the I<core> file without any clue to which of handler or script has
  triggered it. The special I<curinfo> C<gdb> macro comes to help:
  
    panic% gdb /home/httpd/httpd_perl/bin/httpd_perl /home/httpd/perl/core
    (gdb) source mod_perl-x.xx/.gdbinit
    (gdb) curinfo
    9:/home/httpd/perl/core_dump.pl
  
  We start the C<gdb> debugger as before.  I<.gdbinit>, the file with
  various useful C<gdb> macros is located in the source tree of
  mod_perl. We use the C<gdb> source() function to load these macros,
  and when we run the I<curinfo> macro we learn that the core was dumped
  when I</home/httpd/perl/core_dump.pl> was executing the code at line
  9.
  
  These are the bits of information that are important in order to
  reproduce and resolve a problem: the filename and line where the
  faulty function was called (the faulty function is Bad::Segv::segv()
  in our case) and the actual line where the Segementation fault occured
  (the printf("%d",*p) call in XS code). The former is important for
  problem reproducing, it's possible that if the same function was
  called from a different script the problem won't show up (not the case
  in our example, where the using of a value dereferenced from the NULL
  pointer will always cause the Segmentation fault).
  
  
  =head2 Obtaining core Files under Solaris
  
  On Solaris the following method can be used to generate a core file.
  
  =over
  
  =item 1
  
  Use truss(1) as I<root> to stop a process on a segfault:
  
    panic% truss -f -l -t \!all -s \!SIGALRM -S SIGSEGV -p <pid>
  
  or, to monitor all httpd processes (from bash):
  
    panic% for pid in `ps -eaf -o pid,comm | fgrep httpd | cut -d'/' -f1`;
    do truss -f -l -t \!all -s \!SIGALRM -S SIGSEGV -p $pid 2>&1 &
    done
  
  The used truss(1) options are:
  
  =over
  
  =item *
  
  C<-f> - follow forks.
  
  =item *
  
  C<-l> - (that's an el) includes the thread-id and the pid (the pid is
  what we want).
  
  =item *
  
  C<-t> - specifies the syscalls to trace,
  
  =item *
  
  !all - turns off the tracing of syscalls specified by C<-t>
  
  =item *
  
  C<-s> - specifies signals to trace and the C<!SIGALRM> turns off the
  numerous alarms Apache creates.
  
  =item *
  
  C<-S> - specifies signals that stop the process.
  
  =item *
  
  C<-p> - is used to specify the pid.
  
  =back
  
  Instead of attaching to the process, you can start it under truss(1):
  
    panic% truss -f -l -t \!all -s \!SIGALRM -S SIGSEGV \
           /usr/local/bin/httpd -f httpd.conf 2>&1 &
  
  =item 1
  
  Watch the I<error_log> file for reaped processes, as when they get
  SISSEGV signals. When the process is reaped it's stopped but not
  killed.
  
  =item 1
  
  Use gcore(1) to get a I<core> of stopped process or attach to it with
  gdb(1).  For example if the process id is 662:
  
    %panic gcore 662
    gcore: core.662 dumped
  
  Now you can load this I<core> file in gdb(1).
  
  =item 1
  
  C<kill -9> the stopped process. Kill the truss(1) processes as well,
  if you don't need to trap other segfaults.
  
  =back
  
  Obviously, this isn't great to be doing on a production system since
  truss(1) stops the process after it dumps core and prevents Apache
  from reaping it.  So, you could hit the clients/threads limit if you
  segfault a lot.
  
  =head1 Expanding C Macros
  
  Perl, mod_perl and httpd C code makes an extensive use of C macros,
  which sometimes use many other macros in their definitions, so it
  becomes quite a task to figure out how to figure out what a certain
  macro expands to, especially when the macro expands to different
  values in differnt environments. Luckily there are ways to automate
  the expansion process.
  
  =head2 Expanding C Macros with C<make>
  
  The mod_perl I<Makefile>'s include a rule for macro expansions which
  you can find by looking for the C<c.i.> rule. To expand all macros in
  a certain C file, you should run C<make filename.c>, which will create
  I<filename.i> with all macros expanded in it. For example to create
  I<apr_perlio.i> with all macros used in I<apr_perlio.c>:
  
    % cd modperl-2.0/xs/APR/PerlIO
    % make apr_perlio.i
  
  the I<apr_perlio.i> file now lists all the macros:
  
    % less apr_perlio.i
    # 1 "apr_perlio.c"
    # 1 "<built-in>"
    #define __VERSION__ "3.1.1 (Mandrake Linux 8.3 3.1.1-0.4mdk)"
    ...
  
  =head2 Expanding C Macros with C<gdb>
  
  With gcc-3.1 or higher and gdb-5.2-dev or higher you can expand macros
  in gdb, when you step through the code. e.g.:
  
    (gdb) macro expand pTHX_
    expands to:  PerlInterpreter *my_perl __attribute__((unused)),
    (gdb) macro expand PL_dirty
    expands to: (*Perl_Tdirty_ptr(my_perl))
  
  For each library that you want to use this feature with you have to
  compile it with:
  
    CFLAGS="-gdwarf-2 -g3"
  
  or whatever is appropriate for your system, refer to the gcc manpage
  for more info.
  
  To compile perl with this debug feature, pass C<-Doptimize='-gdwarf-2
  -g3'> to C<./Configure>. For Apache run:
  
    CFLAGS="-gdwarf-2 -g3" ./configure [...]
  
  for mod_perl you don't have to do anything, as it'll pick the
  C<$Config{optimize}> Perl flags automatically, if Perl is compiled
  with C<-DDEBUGGING> (which is implied on most systems, if you use
  C<-Doptimize='-g'> or similar.)
  
  Notice that this will make your libraries B<huge>! e.g. on Linux 2.4
  Perl 5.8.0's normal I<libperl.so> is about 0.8MB on linux, compiled
  with C<-Doptimize='-g'> about 2.7MB and with C<-Doptimize='-gdwarf-2
  -g3'> 12.5MB. C<httpd> is also becomes about 10 times bigger with this
  feature enabled. I<mod_perl.so> instead of 0.2k becomes 11MB. You get
  the idea. Of course since you may want this only during the
  development/debugging, that shouldn't be a problem.
  
  The complete details are at:
  http://sources.redhat.com/gdb/current/onlinedocs/gdb_10.html#SEC69
  
  =head1 Maintainers
  
  Maintainer is the person(s) you should contact with updates,
  corrections and patches.
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =head1 Authors
  
  =over
  
  =item *
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =back
  
  Only the major authors are listed above. For contributors see the
  Changes file.
  
  =cut
  
  
  
  
  1.1                  modperl-docs/src/docs/2.0/devel/debug/perl.pod
  
  Index: perl.pod
  ===================================================================
  =head1 NAME
  
  Debugging mod_perl Perl Internals
  
  =head1 Description
  
  This document explains how to debug Perl code under mod_perl.
  
  =head1 Maintainers
  
  Maintainer is the person(s) you should contact with updates,
  corrections and patches.
  
  =over
  
  =item *
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =back
  
  =head1 Authors
  
  =over
  
  =item *
  
  Stas Bekman E<lt>stas (at) stason.orgE<gt>
  
  =back
  
  Only the major authors are listed above. For contributors see the
  Changes file.
  
  =cut
  
  
  
  1.1                  
modperl-docs/src/docs/2.0/devel/debug/code/.debug-modperl-init
  
  Index: .debug-modperl-init
  ===================================================================
  # This gdb startup script breaks at the modperl_hook_init() function,
  # which is useful for debug things at the modperl init phase.
  #
  # Invoke as:
  # gdb -command=.debug-modperl-init
  #
  # see ADJUST notes for things that may need to be adjusted
  
  # ADJUST: the path to the httpd executable if needed
  file ~/httpd/worker/bin/httpd
  handle SIGPIPE nostop
  handle SIGPIPE pass
  set auto-solib-add 0
  
  define myrun
      tbreak main
      break ap_run_pre_config
      #  ADJUST: the httpd.conf file's path if needed
      #  ADJUST: add -DPERL_USEITHREADS to debug threaded mpms
      run -d `pwd`/t -f `pwd`/t/conf/httpd.conf -DONE_PROCESS -DAPACHE2
      continue
  end
  
  define modperl_init
      sharedlibrary modperl
      b modperl_hook_init
      continue
  end
  
  define sharedap
      sharedlibrary apr
      sharedlibrary aprutil
      #sharedlibrary mod_ssl.so
      continue
  end
  
  define sharedperl
      sharedlibrary libperl
  end
  
  # start the server and run till modperl_hook_init on start
  myrun
  modperl_init
  
  # ADJUST: uncomment to reach modperl_hook_init on restart
  #continue
  #continue
  
  # ADJUST: uncomment if you need to step through the code in apr libs
  #sharedap
  
  # ADJUST: uncomment if you need to step through the code in perlib
  #sharedperl
  
  
  
  1.1                  
modperl-docs/src/docs/2.0/devel/debug/code/.debug-modperl-register
  
  Index: .debug-modperl-register
  ===================================================================
  # This gdb startup script allows to break at the very first invocation
  # of mod_perl initialization, just after it was loaded. When the
  # perl_module is loaded, and its pointer struct is added via
  # ap_add_module(), the first hook that will be called is
  # modperl_register_hooks().
  #
  # Invoke as:
  # gdb -command=.debug-modperl-register
  #
  # see ADJUST notes for things that may need to be adjusted
  
  define sharedap
      sharedlibrary apr
      sharedlibrary aprutil
      #sharedlibrary mod_ssl.so
  end
  
  define sharedperl
      sharedlibrary libperl
  end
  
  ### Run ###
  
  # ADJUST: the path to the httpd executable if needed
  file ~/httpd/prefork/bin/httpd
  handle SIGPIPE nostop
  handle SIGPIPE pass
  set auto-solib-add 0
  
  tbreak main
  
  # assuming that mod_dso is compiled in
  b load_module 
  
  
  # ADJUST: the httpd.conf file's path if needed
  # ADJUST: add -DPERL_USEITHREADS to debug threaded mpms
  run -d `pwd`/t -f `pwd`/t/conf/httpd.conf \
  -DONE_PROCESS -DNO_DETATCH -DAPACHE2
  
  # skip over 'tbreak main'
  continue
  
  # In order to set the breakpoint in mod_perl.so, we need to get to
  # the point where it's loaded.
  #
  # With static mod_perl, the bp can be set right away
  #
  
  # With DSO mod_perl, mod_dso's load_module() loads the mod_perl.so
  # object and it immediately calls ap_add_module(), which calls
  # modperl_register_hooks(). So if we want to bp at the latter, we need
  # to stop at load_module(), set the 'bp modperl_register_hooks' and
  # then continue.
  
  # Assuming that 'LoadModule perl_module' is the first LoadModule
  # directive in httpd.conf, you need just one 'continue' after
  # 'ap_add_module'. If it's not the first one, you need to add as many
  # 'continue' commands as the number of 'LoadModule foo' before
  # perl_module, but before setting the 'ap_add_module' bp.
  #
  # If mod_perl is compiled statically, everything is already preloaded,
  # so you can set modperl_* the breakpoints right away
  
  b ap_add_module
  continue
  
  sharedlibrary modperl
  b modperl_register_hooks
  continue
  
  #b modperl_hook_init
  #b modperl_config_srv_create
  #b modperl_startup
  #b modperl_init_vhost
  #b modperl_dir_config
  #b modperl_cmd_load_module
  #modperl_config_apply_PerlModule
  
  # ADJUST: uncomment if you need to step through the code in apr libs
  #sharedap
  
  # ADJUST: uncomment if you need to step through the code in perlib
  #sharedperl
  
  
  
  
  
  
  
  
  1.1                  
modperl-docs/src/docs/2.0/devel/debug/code/.debug-modperl-xs
  
  Index: .debug-modperl-xs
  ===================================================================
  # This gdb startup script breaks at the mpxs_Apache__Filter_print()
  # function from the XS code, as an example how you can debug the code
  # in XS extensions.
  #
  # Invoke as:
  # gdb -command=.debug-modperl-xs
  # and then run: 
  # t/TEST -v -run -ping=block filter/api
  #
  # see ADJUST notes for things that may need to be adjusted
  
  # ADJUST: the path to the httpd executable if needed
  file /home/stas/httpd/worker/bin/httpd
  handle SIGPIPE nostop
  handle SIGPIPE pass
  set auto-solib-add 0
  
  define myrun
      tbreak main
      break ap_run_pre_config
      # ADJUST: the httpd.conf file's path if needed
      # ADJUST: add -DPERL_USEITHREADS to debug threaded mpms
      run -d `pwd`/t -f `pwd`/t/conf/httpd.conf \
      -DONE_PROCESS -DNO_DETATCH -DAPACHE2
      continue
  end
  
  define sharedap
      sharedlibrary apr
      sharedlibrary aprutil
      #sharedlibrary mod_ssl.so
      continue
  end
  
  define sharedperl
      sharedlibrary libperl
  end
  
  define gopoll
      b apr_poll
      continue
      continue
  end
  
  define mybp
      # load Apache/Filter.so
      sharedlibrary Filter
      b mpxs_Apache__Filter_print
      # no longer needed and they just make debugging harder under threads
      disable 2
      disable 3
      continue
  end
  
  myrun
  gopoll
  mybp
  
  # ADJUST: uncomment if you need to step through the code in apr libs
  #sharedap
  
  # ADJUST: uncomment if you need to step through the code in perlib
  #sharedperl
  
  
  
  1.1                  
modperl-docs/src/docs/2.0/devel/performance/size_matters.pod
  
  Index: size_matters.pod
  ===================================================================
  =head1 NAME
  
  Measure sizeof() of Perl's C Structures
  
  =head1 Description
  
  This document describes the I<sizeof> various structures, as
  determined by I<util/sizeof.pl>.  These measurements are mainly for
  research purposes into making Perl things smaller, or rather, how to
  use less Perl things.
  
  =head1 Perl Structures
  
  Structures diagrams are courtesy gdb (print pretty) and a bit of hand 
crafting.
  
  =over 4
  
  =item CV - 229 minimum, 254 minimum w/ symbol table entry
  
    cv = {
       sv_any = {        // XPVCV *
           xpv_pv = 0x0, // char *
           xpv_cur = 0,  // STRLEN
           xpv_len = 0,  // STRLEN
           xof_off = 0 , // IV
           xnv_nv = 0,   // NV
           xmg_magic = 0x0, // MAGIC *
           xmg_stash = 0x0, // HV *
           xcv_stash = 0x0, // HV *
           xcv_start = 0x0, // OP *
           xcv_root = 0x0,  // OP *
           xcv_xsub = 0x0,  // void (*)(register PerlInterpreter *, CV *)
           xcv_xsubany = {  // ANY
               any_ptr = 0x0,
               any_i32 = 0,
               any_iv = 0,
               any_long = 0,
               any_dptr = 0,
               any_dxptr = 0
           },
           xcv_gv = { // GV *
               sv_any = { // void *
                   xpv_pv = 0x0, // char *
                   xpv_cur = 0,  // STRLEN
                   xpv_len = 0,  // STRLEN
                   xiv_iv = 0,   // IV
                   xnv_nv = 0,   // NV
                   xmg_magic =  { // MAGIC *
                       mg_moremagic = 0x0, // MAGIC *
                       mg_virtual = 0x0,   // MGVTBL *
                       mg_private = 0,     // U16
                       mg_type = 0,        // char
                       mg_flags = 0,       // U8
                       mg_obj = 0x0,       // SV *
                       mg_ptr = 0x0,       // char *
                       mg_len = 0,         // I32
                   },
                   xmg_stash = 0x0, // HV *
                   xgv_gp = { // GP *
                       gp_sv = { // SV *
                           sv_any = 0x0,  // void *
                           sv_refcnt = 0, // U32
                           sv_flags = 0   // U32
                       },
                       gp_refcnt = 0, // U32
                       gp_io = 0x0,   // struct io *
                       gp_form = 0x0, // CV *
                       gp_av = 0x0,   // AV *
                       gp_hv = 0x0,   // HV *
                       gp_egv = 0x0,  // GV *
                       gp_cv = 0x0,   // CV *
                       gp_cvgen = 0,  // U32
                       gp_flags = 0,  // U32
                       gp_line = 0,   // line_t
                       gp_file = 0x0, // char *
                   },
                   xgv_name = 0x0,  // char *
                   xgv_namelen = 0, // STRLEN
                   xgv_stash = 0x0, // void *
                   xgv_flags = 0,   // U8
               },
               sv_refcnt = 0, // U32
               sv_flags = 0,  // U32
           },
           xcv_file = 0x0, // char *
           xcv_depth = 0, // long
           xcv_padlist = 0x0, // AV *
           xcv_outside = 0x0, // CV *
           xcv_flags = 0, // cv_flags_t
       }
       sv_refcnt = 0, // U32
       sv_flags = 0,  // U32
    };
  
  In addition to the minimum bytes:
  
  =over 4
  
  =item name of the subroutine: GvNAMELEN(CvGV(cv))+1
  
  =item symbol table entry: HvENTRY (25 + GvNAMELEN(CvGV(cv))+1)
  
  =item minimum sizeof(AV) * 3: xcv_padlist if !CvXSUB(cv)
  
  =item CvROOT(cv) optree
  
  =back
  
  =item HV - 60 minmum
  
    hv = {
       sv_any = { // SV *
           xhv_array = 0x0,  // char *
           xhv_fill = 0,     // STRLEN
           xhv_max = 0,      // STRLEN
           xhv_keys = 0,     // IV
           xnv_nv = 0,       // NV
           xmg_magic = 0x0,  // MAGIC *
           xmg_stash = 0x0,  // HV *
           xhv_riter = 0,    // I32
           xhv_eiter = 0x0,  // HE *
           xhv_pmroot = 0x0, // PMOP *
           xhv_name = 0x0    // char *
       },
       sv_refcnt = 0, // U32
       sv_flags = 0,  // U32
    };
  
  Each entry adds C<sizeof(HvENTRY)>, minimum of 7 (initial C<xhv_max>).
  Note that keys of the same value share C<sizeof(HEK)>, across all
  hashes.
  
  =item HvENTRY - 25 + HeKLEN+1
  
    sizeof(HE *) + sizeof(HE) + sizeof(HEK)
  
  =item HE - 12
  
    he = {
       hent_next = 0x0, // HE *
       hent_hek = 0x0,  // HEK *
       hent_val = 0x0   // SV *
    };
  
  =item HEK - 9 + hek_len
  
    hek = {
       hek_hash = 0, // U32
       hek_len = 0,  // I32
       hek_key = 0,  // char
    };
  
  =item AV - 53
  
    av = {
       sv_any =  { // SV *
           xav_array = 0x0,  // char *
           xav_fill = 0,     // size_t
           xav_max = 0,      // size_t
           xof_off = 0,      // IV
           xnv_nv = 0,       // NV
           xmg_magic = 0x0,  // MAGIC *
           xmg_stash = 0x0,  // HV *
           xav_alloc = 0x0,  // SV **
           xav_arylen = 0x0, // SV *
           xav_flags = 0,    // U8
       },
       sv_refcnt = 0, // U32
       sv_flags = 0   // U32
    };
  
  In addition to the minimum bytes:
  
  =over 4
  
  =item AvFILL(av) * sizeof(SV *)
  
  =back
  
  =back
  
  =head1 SEE ALSO
  
  perlguts(3), B::Size(3),
  
  http://gisle.aas.no/perl/illguts/
  
  =head1 Maintainers
  
  Maintainer is the person(s) you should contact with updates,
  corrections and patches.
  
  =over
  
  =item *
  
  Doug MacEachern E<lt>dougm (at) covalent.netE<gt>
  
  =back
  
  =head1 Authors
  
  =over
  
  =item *
  
  Doug MacEachern E<lt>dougm (at) covalent.netE<gt>
  
  =back
  
  =cut
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to