geoff       2004/02/11 18:05:29

  Modified:    .        Changes
               src/modules/perl modperl_cmd.c modperl_config.c
                        modperl_types.h modperl_util.c
               todo     release
  Added:       t/htdocs/merge2 htaccess
               t/modperl merge.t merge2.t merge3.t
               t/response/TestModperl merge.pm
  Log:
  fix PerlAddVar configuration merging
  (short explanation, lots of work)
  
  Revision  Changes    Path
  1.327     +2 -0      modperl-2.0/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/Changes,v
  retrieving revision 1.326
  retrieving revision 1.327
  diff -u -r1.326 -r1.327
  --- Changes   9 Feb 2004 19:44:41 -0000       1.326
  +++ Changes   12 Feb 2004 02:05:28 -0000      1.327
  @@ -12,6 +12,8 @@
   
   =item 1.99_13-dev
   
  +fix PerlAddVar configuration merging [Geoffrey Young]
  +
   Anonymous subs are now supported in push_handlers, set_handlers,
   add_input_filter, etc. A fast cached cv is used with non-ithreaded
   perl. A slower deparse/eval approach (via B::Deparse) is used with
  
  
  
  1.55      +27 -2     modperl-2.0/src/modules/perl/modperl_cmd.c
  
  Index: modperl_cmd.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_cmd.c,v
  retrieving revision 1.54
  retrieving revision 1.55
  diff -u -r1.54 -r1.55
  --- modperl_cmd.c     9 Feb 2004 18:18:16 -0000       1.54
  +++ modperl_cmd.c     12 Feb 2004 02:05:28 -0000      1.55
  @@ -241,17 +241,42 @@
       modperl_config_dir_t *dcfg = (modperl_config_dir_t *)mconfig;
       const char *name = parms->cmd->name;
   
  +    /* PerlSetVar and PerlAddVar logic.  here's the deal...
  +     *
  +     * cfg->configvars holds the final PerlSetVar/PerlAddVar configuration
  +     * for a given server or directory.  however, getting to that point
  +     * is kind of tricky, due to the add-style nature of PerlAddVar.
  +     *
  +     * the solution is to use cfg->setvars to hold PerlSetVar entries
  +     * and cfg->addvars to hold PerlAddVar entries, each serving as a
  +     * placeholder for when we need to know what's what in the merge routines.
  +     *
  +     * however, for the initial pass, apr_table_setn and apr_table_addn
  +     * will properly build the configvars table, which will be visible to
  +     * startup scripts trying to access per-server configurations.
  +     *
  +     * the end result is that we need to populate all three tables in order
  +     * to keep things straight later on see merge_table_config_vars in
  +     * modperl_config.c
  +     */
       modperl_table_modify_t func =
           strEQ(name, "PerlSetVar") ? apr_table_setn : apr_table_addn;
   
  -    func(dcfg->vars, arg1, arg2);
  +    apr_table_t *table =
  +        strEQ(name, "PerlSetVar") ? dcfg->setvars : dcfg->addvars;
  +
  +    func(table, arg1, arg2);
  +    func(dcfg->configvars, arg1, arg2);
   
       MP_TRACE_d(MP_FUNC, "%s DIR: arg1 = %s, arg2 = %s\n",
                  name, arg1, arg2);
   
       /* make available via Apache->server->dir_config */
       if (!parms->path) {
  -        func(scfg->vars, arg1, arg2);
  +        table = strEQ(name, "PerlSetVar") ? scfg->setvars : scfg->addvars;
  +
  +        func(table, arg1, arg2);
  +        func(scfg->configvars, arg1, arg2);
   
           MP_TRACE_d(MP_FUNC, "%s SRV: arg1 = %s, arg2 = %s\n",
                      name, arg1, arg2);
  
  
  
  1.75      +97 -20    modperl-2.0/src/modules/perl/modperl_config.c
  
  Index: modperl_config.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_config.c,v
  retrieving revision 1.74
  retrieving revision 1.75
  diff -u -r1.74 -r1.75
  --- modperl_config.c  10 Jan 2004 02:52:20 -0000      1.74
  +++ modperl_config.c  12 Feb 2004 02:05:28 -0000      1.75
  @@ -17,24 +17,26 @@
   #define merge_item(item) \
       mrg->item = add->item ? add->item : base->item
   
  -/* take the 'base' values, and override with 'add' values if any */
   static apr_table_t *modperl_table_overlap(apr_pool_t *p,
                                             apr_table_t *base,
                                             apr_table_t *add)
   {
  -    int i;
  -    const apr_array_header_t *arr = apr_table_elts(base);
  -    apr_table_entry_t *entries  = (apr_table_entry_t *)arr->elts;
  -    apr_table_t *merge = apr_table_copy(p, add);
  -
  -    for (i = 0; i < arr->nelts; i++) {
  -        if (apr_table_get(add, entries[i].key)) {
  -            continue;
  -        }
  -        else {
  -            apr_table_addn(merge, entries[i].key, entries[i].val);
  -        }
  -    }
  +    /* take the base (parent) values, and override with add (child) values,
  +     * generating a new table.  entries in add but not in base will be
  +     * added to the new table.  all using core apr table routines.
  +     *
  +     * note that this is equivalent to apr_table_overlap except a new
  +     * table is generated, which is required (otherwise we would clobber
  +     * the existing parent or child configurations)
  +     */
  +    apr_table_t *merge = apr_table_overlay(p, base, add);
  +
  +    /* compress will squash each key to the last value in the table.  this
  +     * is acceptable for all tables that expect only a single value per key
  +     * such as PerlPassEnv and PerlSetEnv.  PerlSetVar/PerlAddVar get their
  +     * own, non-standard, merge routines in merge_table_config_vars.
  +     */
  +    apr_table_compress(merge, APR_OVERLAP_TABLES_SET);
   
       return merge;
   }
  @@ -42,6 +44,53 @@
   #define merge_table_overlap_item(item) \
       mrg->item = modperl_table_overlap(p, base->item, add->item)
   
  +static apr_table_t *merge_table_config_vars(apr_pool_t *p,
  +                                            apr_table_t *configvars,
  +                                            apr_table_t *set,
  +                                            apr_table_t *add)
  +{
  +    apr_table_t *base = apr_table_copy(p, configvars);
  +    apr_table_t *merged_config_vars;
  +
  +    const apr_array_header_t *arr;
  +    apr_table_entry_t *entries;
  +    int i;
  +
  +    /* configvars already contains a properly merged PerlSetVar/PerlAddVar
  +     * configuration for the base (parent), so all we need to do is merge
  +     * the add (child) configuration into it properly.
  +     *
  +     * any PerlSetVar settings in the add (child) config need to reset
  +     * existing entries in the base (parent) config, or generate a
  +     * new entry where none existed previously.  PerlAddVar settings
  +     * are merged into that.
  +     *
  +     * unfortunately, there is no set of apr functions to do this for us - 
  +     * apr_compress_table would be ok, except it always merges mulit-valued
  +     * keys into one, regardless of the merge flag, which is no good - we
  +     * need separate entries, not a single comma-delimted entry.
  +     *
  +     * fortunately, the logic here is simple - first, (re)set the base (parent)
  +     * table where a PerlSetVar entry exists in the child (add) configuration.
  +     * then, just overlay the PerlAddVar configuration into it.
  +     */
  +
  +    arr = apr_table_elts(set);
  +    entries  = (apr_table_entry_t *)arr->elts;
  +
  +    /* hopefully this is faster than using apr_table_do  */
  +    for (i = 0; i < arr->nelts; i++) {
  +        apr_table_setn(base, entries[i].key, entries[i].val);
  +    }
  +
  +    /* at this point, all the PerlSetVar merging has happened.  add in the 
  +     * add (child) PerlAddVar entries and we're done
  +     */
  +    merged_config_vars = apr_table_overlay(p, base, add);
  +      
  +    return merged_config_vars;
  +}
  +
   #define merge_handlers(merge_flag, array) \
       if (merge_flag(mrg)) { \
           mrg->array = modperl_handler_array_merge(p, \
  @@ -71,10 +120,22 @@
   
       merge_item(location);
       
  -    merge_table_overlap_item(vars);
  -    
       merge_table_overlap_item(SetEnv);
   
  +    /* this is where we merge PerlSetVar and PerlAddVar together */
  +    mrg->configvars = merge_table_config_vars(p,
  +                                              base->configvars,
  +                                              add->setvars, add->addvars);
  +
  +    /* note we don't care about merging dcfg->setvars or dcfg->addvars
  +     * specifically - what is important to merge is dfcg->configvars.
  +     * but we need to keep track of the entries for this config, so
  +     * the merged values are simply the values for the add (current)
  +     * configuration.
  +     */
  +    mrg->setvars = add->setvars;
  +    mrg->addvars = add->addvars;
  +
       /* XXX: check if Perl*Handler is disabled */
       for (i=0; i < MP_HANDLER_NUM_PER_DIR; i++) {
           merge_handlers(MpDirMERGE_HANDLERS, handlers_per_dir[i]);
  @@ -107,7 +168,9 @@
   
       scfg->argv = apr_array_make(p, 2, sizeof(char *));
   
  -    scfg->vars = apr_table_make(p, 2);
  +    scfg->setvars = apr_table_make(p, 2);
  +    scfg->addvars = apr_table_make(p, 2);
  +    scfg->configvars = apr_table_make(p, 2);
   
       scfg->PassEnv = apr_table_make(p, 2);
       scfg->SetEnv = apr_table_make(p, 2);
  @@ -130,7 +193,9 @@
   
       dcfg->flags = modperl_options_new(p, MpDirType);
   
  -    dcfg->vars = apr_table_make(p, 2);
  +    dcfg->setvars = apr_table_make(p, 2);
  +    dcfg->addvars = apr_table_make(p, 2);
  +    dcfg->configvars = apr_table_make(p, 2);
   
       dcfg->SetEnv = apr_table_make(p, 2);
       
  @@ -224,11 +289,23 @@
       merge_item(PerlModule);
       merge_item(PerlRequire);
   
  -    merge_table_overlap_item(vars);
  -
       merge_table_overlap_item(SetEnv);
       merge_table_overlap_item(PassEnv);
    
  +    /* this is where we merge PerlSetVar and PerlAddVar together */
  +    mrg->configvars = merge_table_config_vars(p,
  +                                              base->configvars,
  +                                              add->setvars, add->addvars);
  +
  +    /* note we don't care about merging dcfg->setvars or dcfg->addvars
  +     * specifically - what is important to merge is dfcg->configvars.
  +     * but we need to keep track of the entries for this config, so
  +     * the merged values are simply the values for the add (current)
  +     * configuration.
  +     */
  +    mrg->setvars = add->setvars;
  +    mrg->addvars = add->addvars;
  +
       merge_item(threaded_mpm);
       merge_item(server);
   
  
  
  
  1.73      +6 -2      modperl-2.0/src/modules/perl/modperl_types.h
  
  Index: modperl_types.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_types.h,v
  retrieving revision 1.72
  retrieving revision 1.73
  diff -u -r1.72 -r1.73
  --- modperl_types.h   9 Feb 2004 19:37:38 -0000       1.72
  +++ modperl_types.h   12 Feb 2004 02:05:28 -0000      1.73
  @@ -111,7 +111,9 @@
   } modperl_interp_scope_e;
   
   typedef struct {
  -    MpHV *vars;
  +    MpHV *setvars;
  +    MpHV *addvars;
  +    MpHV *configvars;
       MpHV *SetEnv;
       MpHV *PassEnv;
       MpAV *PerlRequire, *PerlModule;
  @@ -142,7 +144,9 @@
       char *PerlDispatchHandler;
       MpAV *handlers_per_dir[MP_HANDLER_NUM_PER_DIR];
       MpHV *SetEnv;
  -    MpHV *vars;
  +    MpHV *setvars;
  +    MpHV *addvars;
  +    MpHV *configvars;
       modperl_options_t *flags;
   #ifdef USE_ITHREADS
       modperl_interp_scope_e interp_scope;
  
  
  
  1.62      +2 -2      modperl-2.0/src/modules/perl/modperl_util.c
  
  Index: modperl_util.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_util.c,v
  retrieving revision 1.61
  retrieving revision 1.62
  diff -u -r1.61 -r1.62
  --- modperl_util.c    19 Jan 2004 19:59:58 -0000      1.61
  +++ modperl_util.c    12 Feb 2004 02:05:28 -0000      1.62
  @@ -568,7 +568,7 @@
   
       if (r && r->per_dir_config) {                               
           MP_dDCFG;
  -        retval = modperl_table_get_set(aTHX_ dcfg->vars,
  +        retval = modperl_table_get_set(aTHX_ dcfg->configvars,
                                          key, sv_val, FALSE);
       }
   
  @@ -576,7 +576,7 @@
           if (s && s->module_config) {
               MP_dSCFG(s);
               SvREFCNT_dec(retval); /* in case above did newSV(0) */
  -            retval = modperl_table_get_set(aTHX_ scfg->vars,
  +            retval = modperl_table_get_set(aTHX_ scfg->configvars,
                                              key, sv_val, FALSE);
           }
           else {
  
  
  
  1.1                  modperl-2.0/t/htdocs/merge2/htaccess
  
  Index: htaccess
  ===================================================================
  # htaccess file for t/response/TestModperl/merge.pm
  
  PerlSetEnv   MergeSetEnv3  SetEnv3Merge3Val
  PerlSetVar   MergeSetVar3  SetVar3Merge3Val
  PerlSetVar   MergeAddVar3  AddVar3Merge3Val1
  PerlAddVar   MergeAddVar3  AddVar3Merge3Val2
  
  
  
  1.1                  modperl-2.0/t/modperl/merge.t
  
  Index: merge.t
  ===================================================================
  use strict;
  use warnings FATAL => 'all';
  
  use Apache::TestRequest qw(GET_BODY_ASSERT);
  use Apache::Test;
  use Apache::TestUtil;
  
  my $module   = 'TestModperl::merge';
  Apache::TestRequest::module($module);
  
  my $config   = Apache::Test::config();
  my $hostport = Apache::TestRequest::hostport($config);
  
  my $base = "http://$hostport";;
  
  # test server-to-container merging (without overrides) for:
  #   PerlSetEnv
  #   PerlPassEnv
  #   PerlSetVar
  #   PerlAddVar
  
  my $uri = "$base/merge";
  t_debug("connecting to $uri");
  print GET_BODY_ASSERT $uri;
  
  
  
  1.1                  modperl-2.0/t/modperl/merge2.t
  
  Index: merge2.t
  ===================================================================
  use strict;
  use warnings FATAL => 'all';
  
  use Apache::TestRequest qw(GET_BODY_ASSERT);
  use Apache::Test;
  use Apache::TestUtil;
  
  my $module   = 'TestModperl::merge';
  Apache::TestRequest::module($module);
  
  my $config   = Apache::Test::config();
  my $hostport = Apache::TestRequest::hostport($config);
  
  my $base = "http://$hostport";;
  
  # test server-to-container merging (with overrides) for:
  #   PerlSetEnv
  #   PerlPassEnv
  #   PerlSetVar
  #   PerlAddVar
  
  my $uri = "$base/merge2/";
  t_debug("connecting to $uri");
  print GET_BODY_ASSERT $uri;
  
  
  
  1.1                  modperl-2.0/t/modperl/merge3.t
  
  Index: merge3.t
  ===================================================================
  use strict;
  use warnings FATAL => 'all';
  
  use Apache::TestRequest qw(GET_BODY_ASSERT);
  use Apache::Test;
  use Apache::TestUtil;
  
  my $module   = 'TestModperl::merge';
  Apache::TestRequest::module($module);
  
  my $config   = Apache::Test::config();
  my $hostport = Apache::TestRequest::hostport($config);
  
  my $base = "http://$hostport";;
  
  # test multi-level merging (server-to-container-to-htaccess) for:
  #   PerlSetEnv
  #   PerlPassEnv
  #   PerlSetVar
  #   PerlAddVar
  
  my $uri = "$base/merge2/merge3.html";
  t_debug("connecting to $uri");
  print GET_BODY_ASSERT $uri;
  
  
  
  1.1                  modperl-2.0/t/response/TestModperl/merge.pm
  
  Index: merge.pm
  ===================================================================
  package TestModperl::merge;
  
  use strict;
  use warnings FATAL => 'all';
  
  use Apache::Server ();
  use Apache::ServerUtil ();
  use Apache::RequestUtil ();
  use APR::Table ();
  
  use Apache::Test;
  use Apache::TestUtil;
  
  use Apache::Const -compile => 'OK';
  
  # this is the configuration and handler for t/modperl/merge.t,
  # t/modperl/merge2.t, and t/modperl/merge3.t.  see any of those
  # tests and/or the below configuration for more details
  
  
  # result tables for the below tests (trying to make the code more simple...)
  # the hash itself represents a request
  # the keys to the main hash represent merge levels - 1 for the non-overriding
  # merge, 2 for an overriding merge, and 3 for a two-level merge
  # the rest should be self-explanatory - settings and expected values.
  our %merge1 = ( 1 =>
                    { PerlPassEnv => [APACHE_TEST_HOSTTYPE => 'z80'],
                      PerlSetEnv  => [MergeSetEnv1 => 'SetEnv1Val'],
                      PerlSetVar  => [MergeSetVar1 => 'SetVar1Val'],
                      PerlAddVar  => [MergeAddVar1 => ['AddVar1Val1', 
                                                       'AddVar1Val2']],
                    },
                  2 =>
                    { PerlSetEnv  => [MergeSetEnv2 => 'SetEnv2Val'],
                      PerlSetVar  => [MergeSetVar2 => 'SetVar2Val'],
                      PerlAddVar  => [MergeAddVar2 => ['AddVar2Val1', 
                                                       'AddVar2Val2']],
                    },
                  3 =>
                    { PerlSetEnv  => [MergeSetEnv3 => 'SetEnv3Val'],
                      PerlSetVar  => [MergeSetVar3 => 'SetVar3Val'],
                      PerlAddVar  => [MergeAddVar3 => ['AddVar3Val1',
                                                       'AddVar3Val2']],
                    },
               );
  
  our %merge2 = ( 1 => 
                    { PerlPassEnv => [APACHE_TEST_HOSTTYPE => 'z80'],
                      PerlSetEnv  => [MergeSetEnv1 => 'SetEnv1Val'],
                      PerlSetVar  => [MergeSetVar1 => 'SetVar1Val'],
                      PerlAddVar  => [MergeAddVar1 => ['AddVar1Val1', 
                                                       'AddVar1Val2']],
                    },
                  2 =>
                    { PerlSetEnv  => [MergeSetEnv2 => 'SetEnv2Merge2Val'],
                      PerlSetVar  => [MergeSetVar2 => 'SetVar2Merge2Val'],
                      PerlAddVar  => [MergeAddVar2 => ['AddVar2Merge2Val1',
                                                       'AddVar2Merge2Val2']],
                    },
                  3 =>
                    { PerlSetEnv  => [MergeSetEnv3 => 'SetEnv3Val'],
                      PerlSetVar  => [MergeSetVar3 => 'SetVar3Val'],
                      PerlAddVar  => [MergeAddVar3 => ['AddVar3Val1',
                                                       'AddVar3Val2']],
                    },
               );
  
  our %merge3 = ( 1 => 
                    { PerlPassEnv => [APACHE_TEST_HOSTTYPE => 'z80'],
                      PerlSetEnv  => [MergeSetEnv1 => 'SetEnv1Val'],
                      PerlSetVar  => [MergeSetVar1 => 'SetVar1Val'],
                      PerlAddVar  => [MergeAddVar1 => ['AddVar1Val1', 
                                                       'AddVar1Val2']],
                    },
                  2 =>
                    { PerlSetEnv  => [MergeSetEnv2 => 'SetEnv2Merge2Val'],
                      PerlSetVar  => [MergeSetVar2 => 'SetVar2Merge2Val'],
                      PerlAddVar  => [MergeAddVar2 => ['AddVar2Merge2Val1',
                                                       'AddVar2Merge2Val2']],
                    },
                  3 =>
                    { PerlSetEnv  => [MergeSetEnv3 => 'SetEnv3Merge3Val'],
                      PerlSetVar  => [MergeSetVar3 => 'SetVar3Merge3Val'],
                      PerlAddVar  => [MergeAddVar3 => ['AddVar3Merge3Val1',
                                                       'AddVar3Merge3Val2']],
                    },
               );
  
  sub handler {
  
      my $r = shift;
  
      plan $r, tests => 10;
  
      no strict qw(refs);
  
      my $location = $r->location;
      my $hash;
  
      if ($location =~ m/(merge3)/) {
        $hash = $1;
      } elsif ($location =~ m/(merge2)/) {
        $hash = $1;
      } else {
        $hash = 'merge1'; 
      }
  
      t_debug("testing against results in $hash");
  
      foreach my $level (sort keys %$hash) {
          foreach my $directive (sort keys %{$hash->{$level}}) {
  
              my $key   = $hash->{$level}->{$directive}->[0];
              my $value = $hash->{$level}->{$directive}->[1];
  
              my @expected = ref $value ? @$value : $value;
  
              my $comment = join ' ', $directive, $key, @expected;
  
              if ($directive =~ m/Env/) {
                  my $received = $ENV{$key};
                  ok t_cmp($expected[0], $received, $comment);
              }
              elsif ($directive =~ m/Set/) {
                  my $received = $r->dir_config->get($key);
                  ok t_cmp($expected[0], $received, $comment);
              }
              else {
                  my @received = $r->dir_config->get($key);
                  ok t_cmp([EMAIL PROTECTED], [EMAIL PROTECTED], $comment);
              }
          }
      }
  
      Apache::OK;
  }
  
  1;
  __END__
  <NoAutoConfig>
      PerlModule TestModperl::merge
  
      <VirtualHost TestModperl::merge>
          # these should pass through all merges untouched
          PerlPassEnv  APACHE_TEST_HOSTTYPE
          PerlSetEnv   MergeSetEnv1  SetEnv1Val
          PerlSetVar   MergeSetVar1  SetVar1Val
          PerlSetVar   MergeAddVar1  AddVar1Val1
          PerlAddVar   MergeAddVar1  AddVar1Val2
  
          # these are overridden in /merge1 and /merge1/merge2
          PerlSetEnv   MergeSetEnv2  SetEnv2Val
          PerlSetVar   MergeSetVar2  SetVar2Val
          PerlSetVar   MergeAddVar2  AddVar2Val1
          PerlAddVar   MergeAddVar2  AddVar2Val2
  
          # these are overridden in /merge1/merge2 via htaccess
          PerlSetEnv   MergeSetEnv3  SetEnv3Val
          PerlSetVar   MergeSetVar3  SetVar3Val
          PerlSetVar   MergeAddVar3  AddVar3Val1
          PerlAddVar   MergeAddVar3  AddVar3Val2
  
          <Location /merge>
              # same as per-server level
              SetHandler perl-script
              PerlResponseHandler TestModperl::merge
          </Location>
  
          AccessFileName htaccess
          <Directory @DocumentRoot@/merge2>
              # overrides "2" values - "1" and "3" values left untouched
              PerlSetEnv   MergeSetEnv2  SetEnv2Merge2Val
              PerlSetVar   MergeSetVar2  SetVar2Merge2Val
              PerlSetVar   MergeAddVar2  AddVar2Merge2Val1
              PerlAddVar   MergeAddVar2  AddVar2Merge2Val2
  
              SetHandler perl-script
              PerlResponseHandler TestModperl::merge
  
              # don't trigger htaccess files automatically
              AllowOverride none
  
              <Files merge3.html>
                  # initiate a double merge with htaccess file
                  AllowOverride all
              </Files>
          </Directory>
  
      </VirtualHost>
  </NoAutoConfig>
  
  
  
  1.17      +0 -4      modperl-2.0/todo/release
  
  Index: release
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/todo/release,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- release   10 Feb 2004 15:02:00 -0000      1.16
  +++ release   12 Feb 2004 02:05:29 -0000      1.17
  @@ -84,10 +84,6 @@
     release it any dependency on mod_perl will be resolved as mod_perl
     2.0, when mod_perl 1.0 may be required instead.
   
  -* Set/Add overlapping in config which is not doing the right thing. See:
  -  http://marc.theaimsgroup.com/?l=apache-modperl-dev&m=100622977803237&w=2
  -  http://marc.theaimsgroup.com/?t=97984528900002&r=1&w=2
  -
   * Apache::{Server,Process} classes:
     require mutex lock for writing (e.g. $s->(error_fname|error_log)
     Status: most likely some server/process datastructures aren't
  
  
  

Reply via email to