stas        2004/04/01 18:17:46

  Modified:    ModPerl-Registry/lib/ModPerl RegistryCooker.pm
               ModPerl-Registry/t perlrun_extload.t special_blocks.t
               ModPerl-Registry/t/cgi-bin perlrun_decl.pm
                        perlrun_extload.pl perlrun_nondecl.pl
                        special_blocks.pl
               ModPerl-Registry/t/conf modperl_extra_startup.pl
               src/modules/perl mod_perl.c modperl_handler.c modperl_perl.c
                        modperl_perl.h modperl_perl_global.c
                        modperl_perl_global.h modperl_util.c modperl_util.h
               t/response/TestModperl endav.pm
               xs/ModPerl/Global ModPerl__Global.h
               xs/maps  modperl_functions.map
               xs/tables/current/ModPerl FunctionTable.pm
               .        Changes
               todo     release
  Log:
  'SetHandler perl-script' no longer grabs any newly encountered END
  blocks, and removes them from PL_endav, but only if they are
  explicitly registered via ModPerl::Global::special_list_register(END
  => $package_name) (this is a new function). It's now possible to have
  a complete control of when END blocks are run from the user space, not
  only in the registry handlers [Stas]
  
  END blocks encountered by child processes and not hijacked by
  ModPerl::Global::special_list_register() are now executed at the
  server shutdown (previously they weren't executed at all). [Stas]
  
  and a few other assorted re-shufflings, too intervowen to commit
  separately
  
  Revision  Changes    Path
  1.46      +2 -1      modperl-2.0/ModPerl-Registry/lib/ModPerl/RegistryCooker.pm
  
  Index: RegistryCooker.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/lib/ModPerl/RegistryCooker.pm,v
  retrieving revision 1.45
  retrieving revision 1.46
  diff -u -u -r1.45 -r1.46
  --- RegistryCooker.pm 10 Mar 2004 23:19:44 -0000      1.45
  +++ RegistryCooker.pm 2 Apr 2004 02:17:45 -0000       1.46
  @@ -690,7 +690,8 @@
   
       $self->debug("compiling $self->{FILENAME}") if DEBUG && D_COMPILE;
   
  -    ModPerl::Global::special_list_clear(END => $self->{PACKAGE});
  +    ModPerl::Global::special_list_register(END => $self->{PACKAGE});
  +    ModPerl::Global::special_list_clear(   END => $self->{PACKAGE});
   
       {
           # let the code define its own warn and strict level 
  
  
  
  1.2       +1 -1      modperl-2.0/ModPerl-Registry/t/perlrun_extload.t
  
  Index: perlrun_extload.t
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/t/perlrun_extload.t,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -u -r1.1 -r1.2
  --- perlrun_extload.t 9 Mar 2004 06:35:34 -0000       1.1
  +++ perlrun_extload.t 2 Apr 2004 02:17:45 -0000       1.2
  @@ -15,7 +15,7 @@
       my $res = get_body($same_interp, $url);
       skip_not_same_interp(
           !defined($res),
  -        "01234",
  +        "d1nd1234",
           $res,
           "PerlRun requiring an external lib with subs",
       );
  
  
  
  1.9       +3 -0      modperl-2.0/ModPerl-Registry/t/special_blocks.t
  
  Index: special_blocks.t
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/t/special_blocks.t,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -u -r1.8 -r1.9
  --- special_blocks.t  22 Nov 2003 07:38:48 -0000      1.8
  +++ special_blocks.t  2 Apr 2004 02:17:45 -0000       1.9
  @@ -20,6 +20,9 @@
   {
       # PerlRun always run BEGIN/END since it's never cached
   
  +    # see also t/perlrun_extload.t which exercises BEGIN/END blocks
  +    # from external modules loaded from PerlRun scripts
  +
       my $alias = "perlrun";
       my $url = "/same_interp/$alias/special_blocks.pl";
       my $same_interp = Apache::TestRequest::same_interp_tie($url);
  
  
  
  1.2       +13 -1     modperl-2.0/ModPerl-Registry/t/cgi-bin/perlrun_decl.pm
  
  Index: perlrun_decl.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/t/cgi-bin/perlrun_decl.pm,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -u -r1.1 -r1.2
  --- perlrun_decl.pm   9 Mar 2004 06:35:34 -0000       1.1
  +++ perlrun_decl.pm   2 Apr 2004 02:17:45 -0000       1.2
  @@ -6,6 +6,18 @@
   use base qw(Exporter);
   our @EXPORT = qw(decl_proto);
   
  -sub decl_proto ($;$) { my $x = shift; $x*"0"; }
  +# this BEGIN block is called only once, since this module doesn't get
  +# removed from %INC after it was loaded
  +BEGIN {
  +    # use an external package which will persist across requests
  +    $MyData::blocks{perlrun_decl}++;
  +}
  +
  +sub decl_proto ($;$) { shift }
  +
  +# this END block won't be executed until the server shutdown
  +END {
  +    $MyData::blocks{perlrun_decl}--;
  +}
   
   1;
  
  
  
  1.3       +50 -27    modperl-2.0/ModPerl-Registry/t/cgi-bin/perlrun_extload.pl
  
  Index: perlrun_extload.pl
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/t/cgi-bin/perlrun_extload.pl,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -u -r1.2 -r1.3
  --- perlrun_extload.pl        9 Mar 2004 06:54:14 -0000       1.2
  +++ perlrun_extload.pl        2 Apr 2004 02:17:45 -0000       1.3
  @@ -6,33 +6,56 @@
   use File::Spec::Functions qw(catfile catdir);
   
   use lib catdir Apache::Test::vars('serverroot'), 'cgi-bin';
  -my $require = catfile Apache::Test::vars('serverroot'), 'cgi-bin', 
  -    'perlrun_nondecl.pl';
  -
  -# require a module w/ package declaration (it doesn't get reloaded
  -# because it declares the package). But we still have a problem with
  -# subs declaring prototypes. When perlrun_decl->import is called, the
  -# original function's prototype doesn't match the aliases prototype.
  -# see decl_proto()
  -BEGIN { t_server_log_warn_is_expected() if perlrun_decl->can("decl_proto"); }
  -use perlrun_decl;
  -
  -# require a lib w/o package declaration. Functions in that lib get
  -# automatically aliased to the functions in the current package.
  -require "$require";
  +my $require = catfile Apache::Test::vars('serverroot'),
  +    qw(cgi-bin perlrun_nondecl.pl);
   
   print "Content-type: text/plain\n\n";
   
  -### declared package module
  -print decl_proto(0);
  -
  -### non-declared package module
  -# they all get redefined warning inside perlrun_nondecl.pl, since that
  -# lib loads it into main::, vs. PerlRun undefs the current __PACKAGE__
  -print nondecl_no_proto();
  -print nondecl_proto(2);
  -print nondecl_proto_empty("whatever");
  -print nondecl_const();
  -
  -
  -
  +### declared package module ###
  +{
  +    # require a module w/ package declaration (it doesn't get reloaded
  +    # because it declares the package). But we still have a problem with
  +    # subs declaring prototypes. When perlrun_decl->import is called, the
  +    # original function's prototype doesn't match the aliases prototype.
  +    # see decl_proto()
  +    BEGIN { t_server_log_warn_is_expected()
  +                if perlrun_decl->can("decl_proto"); 
  +    }
  +    use perlrun_decl;
  +
  +    die "perlrun_decl BEGIN block was run more than once"
  +        if $MyData::blocks{perlrun_decl} > 1;
  +
  +    print "d";
  +    print decl_proto(1);
  +}
  +
  +### non-declared package module ###
  +{
  +    # how many times were were called from the same interpreter
  +    $MyData::blocks{cycle}{perlrun_nondecl}++;
  +    $MyData::blocks{BEGIN}{perlrun_nondecl} ||= 0;
  +    $MyData::blocks{END}  {perlrun_nondecl} ||= 0;
  +
  +    # require a lib w/o package declaration. Functions in that lib get
  +    # automatically aliased to the functions in the current package.
  +    require "$require";
  +
  +    die "perlrun_nondecl's BEGIN block wasn't run"
  +        if $MyData::blocks{BEGIN}{perlrun_nondecl} !=
  +           $MyData::blocks{cycle}{perlrun_nondecl};
  +
  +    # the END block for this cycle didn't run yet, but we can test the
  +    # previous cycle's one
  +    die "perlrun_nondecl's END block wasn't run"
  +        if $MyData::blocks{END}{perlrun_nondecl} + 1 !=
  +           $MyData::blocks{cycle}{perlrun_nondecl};
  +
  +    # they all get redefined warning inside perlrun_nondecl.pl, since that
  +    # lib loads it into main::, vs. PerlRun undefs the current __PACKAGE__
  +    print "nd";
  +    print nondecl_no_proto();
  +    print nondecl_proto(2);
  +    print nondecl_proto_empty("whatever");
  +    print nondecl_const();
  +}
  
  
  
  1.2       +11 -2     modperl-2.0/ModPerl-Registry/t/cgi-bin/perlrun_nondecl.pl
  
  Index: perlrun_nondecl.pl
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/t/cgi-bin/perlrun_nondecl.pl,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -u -r1.1 -r1.2
  --- perlrun_nondecl.pl        9 Mar 2004 06:35:34 -0000       1.1
  +++ perlrun_nondecl.pl        2 Apr 2004 02:17:45 -0000       1.2
  @@ -5,9 +5,16 @@
   
   my $num;
   
  +# this BEGIN block is called on every request, since this file gets
  +# removed from %INC after it was loaded
  +BEGIN {
  +    # use an external package which will persist across requests
  +    $MyData::blocks{BEGIN}{perlrun_nondecl}++;
  +}
  +
   use subs qw(warn_exp);
   
  -# all subs in tis file get 'redefined' warning because they are
  +# all subs in this file get 'redefined' warning because they are
   # reloaded in the main:: package, which is not under PerlRun's
   # control.
   
  @@ -41,6 +48,8 @@
   # a constant.
   sub nondecl_const       ()  { 4 }
   
  -
  +END {
  +    $MyData::blocks{END}{perlrun_nondecl}++;
  +}
   
   1;
  
  
  
  1.6       +1 -1      modperl-2.0/ModPerl-Registry/t/cgi-bin/special_blocks.pl
  
  Index: special_blocks.pl
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/t/cgi-bin/special_blocks.pl,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -u -r1.5 -r1.6
  --- special_blocks.pl 16 Aug 2002 10:11:39 -0000      1.5
  +++ special_blocks.pl 2 Apr 2004 02:17:45 -0000       1.6
  @@ -1,6 +1,7 @@
   #!perl -w
   
   # test BEGIN/END blocks
  +
   use Apache::RequestRec ();
   
   use vars qw($query);
  @@ -31,4 +32,3 @@
           print "end ok";
       }
   }
  -
  
  
  
  1.15      +1 -1      modperl-2.0/ModPerl-Registry/t/conf/modperl_extra_startup.pl
  
  Index: modperl_extra_startup.pl
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/t/conf/modperl_extra_startup.pl,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -u -r1.14 -r1.15
  --- modperl_extra_startup.pl  19 Jan 2004 19:59:58 -0000      1.14
  +++ modperl_extra_startup.pl  2 Apr 2004 02:17:45 -0000       1.15
  @@ -35,7 +35,7 @@
       );
   
       my @preload = qw(basic.pl env.pl require.pl special_blocks.pl
  -        redirect.pl 206.pl content_type.pl);
  +                     redirect.pl 206.pl content_type.pl);
   
       for my $file (@preload) {
           $rl->handler("/registry_bb/$file");
  
  
  
  1.212     +27 -3     modperl-2.0/src/modules/perl/mod_perl.c
  
  Index: mod_perl.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/mod_perl.c,v
  retrieving revision 1.211
  retrieving revision 1.212
  diff -u -u -r1.211 -r1.212
  --- mod_perl.c        4 Mar 2004 06:01:06 -0000       1.211
  +++ mod_perl.c        2 Apr 2004 02:17:45 -0000       1.212
  @@ -645,13 +645,26 @@
       return modperl_destruct_level;
   }
   
  +#ifdef USE_ITHREADS
  +
  +static apr_status_t
  +modperl_perl_call_endav_mip(pTHX_ modperl_interp_pool_t *mip,
  +                            void *data)
  +{
  +    modperl_perl_call_endav(aTHX);
  +    return APR_SUCCESS;
  +}
  +
  +#endif /* USE_ITHREADS */
  +
   static apr_status_t modperl_child_exit(void *data)
   {
       char *level = NULL;
       server_rec *s = (server_rec *)data;
  -    
  -    modperl_callback_process(MP_CHILD_EXIT_HANDLER, server_pool, s, MP_HOOK_VOID);
  -    
  +
  +    modperl_callback_process(MP_CHILD_EXIT_HANDLER, server_pool, s,
  +                             MP_HOOK_VOID);
  +
       if ((level = getenv("PERL_DESTRUCT_LEVEL"))) {
           modperl_destruct_level = atoi(level);
       }
  @@ -662,6 +675,17 @@
   
       if (modperl_destruct_level) {
           apr_pool_clear(server_pool);
  +    }
  +    else {
  +        /* run the END blocks of this child process if
  +         * modperl_perl_destruct is not called for this process */
  +#ifdef USE_ITHREADS
  +        modperl_interp_mip_walk_servers(NULL, s,
  +                                        modperl_perl_call_endav_mip,
  +                                        (void*)NULL);
  +#else
  +        modperl_perl_call_endav(aTHX);
  +#endif
       }
   
       server_pool = NULL;
  
  
  
  1.27      +0 -63     modperl-2.0/src/modules/perl/modperl_handler.c
  
  Index: modperl_handler.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_handler.c,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -u -r1.26 -r1.27
  --- modperl_handler.c 4 Mar 2004 06:01:07 -0000       1.26
  +++ modperl_handler.c 2 Apr 2004 02:17:45 -0000       1.27
  @@ -15,69 +15,6 @@
   
   #include "mod_perl.h"
   
  -#ifdef USE_ITHREADS
  -static
  -char *modperl_coderef2text(pTHX_ apr_pool_t *p, CV *cv)
  -{
  -    dSP;
  -    int count;
  -    SV *bdeparse;
  -    char *text;
  -    
  -    /* B::Deparse >= 0.61 needed for blessed code references.
  -     * 0.6 works fine for non-blessed code refs.
  -     * notice that B::Deparse is not CPAN-updatable.
  -     * 0.61 is available starting from 5.8.0
  -     */
  -    load_module(PERL_LOADMOD_NOIMPORT,
  -                newSVpvn("B::Deparse", 10),
  -                newSVnv(SvOBJECT((SV*)cv) ? 0.61 : 0.60));
  -
  -    ENTER;
  -    SAVETMPS;
  -
  -    /* create the B::Deparse object */
  -    PUSHMARK(sp);
  -    XPUSHs(sv_2mortal(newSVpvn("B::Deparse", 10)));
  -    PUTBACK;
  -    count = call_method("new", G_SCALAR);
  -    SPAGAIN;
  -    if (count != 1) {
  -        Perl_croak(aTHX_ "Unexpected return value from B::Deparse::new\n");
  -    }
  -    if (SvTRUE(ERRSV)) {
  -        Perl_croak(aTHX_ "error: %s", SvPVX(ERRSV));
  -    }
  -    bdeparse = POPs;
  -
  -    PUSHMARK(sp);
  -    XPUSHs(bdeparse);
  -    XPUSHs(sv_2mortal(newRV_inc((SV*)cv)));
  -    PUTBACK;
  -    count = call_method("coderef2text", G_SCALAR);
  -    SPAGAIN;
  -    if (count != 1) {
  -        Perl_croak(aTHX_ "Unexpected return value from "
  -                   "B::Deparse::coderef2text\n");
  -    }
  -    if (SvTRUE(ERRSV)) {
  -        Perl_croak(aTHX_ "error: %s", SvPVX(ERRSV));
  -    }
  -    
  -    {
  -        STRLEN n_a;
  -        text = apr_pstrcat(p, "sub ", POPpx, NULL);
  -    }
  -    
  -    PUTBACK;
  -    
  -    FREETMPS;
  -    LEAVE;
  -
  -    return text;
  -}
  -#endif
  -
   modperl_handler_t *modperl_handler_new(apr_pool_t *p, const char *name)
   {
       modperl_handler_t *handler = 
  
  
  
  1.22      +10 -5     modperl-2.0/src/modules/perl/modperl_perl.c
  
  Index: modperl_perl.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_perl.c,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -u -r1.21 -r1.22
  --- modperl_perl.c    4 Mar 2004 06:01:07 -0000       1.21
  +++ modperl_perl.c    2 Apr 2004 02:17:45 -0000       1.22
  @@ -57,7 +57,7 @@
       ids->gid  = getgid(); 
       ids->gid  = getegid(); 
   
  -    MP_TRACE_g(MP_FUNC, 
  +    MP_TRACE_r(MP_FUNC, 
                  "pid=%d, "
   #ifdef MP_MAINTAIN_PPID
                  "ppid=%d, "
  @@ -120,6 +120,8 @@
   
       PERL_SET_CONTEXT(perl);
   
  +    modperl_perl_call_endav(aTHX);
  +
       PL_perl_destruct_level = modperl_perl_destruct_level();
   
   #ifdef USE_ENVIRON_ARRAY
  @@ -144,10 +146,6 @@
   #   endif
   #endif
   
  -    if (PL_endav) {
  -        modperl_perl_call_list(aTHX_ PL_endav, "END");
  -    }
  -
       {
           dTHXa(perl);
   
  @@ -174,6 +172,13 @@
           environ = orig_environ;
       }
   #endif
  +}
  +
  +void modperl_perl_call_endav(pTHX)
  +{
  +     if (PL_endav) {
  +         modperl_perl_call_list(aTHX_ PL_endav, "END");
  +     }
   }
   
   #if !(PERL_REVISION == 5 && ( PERL_VERSION < 8 ||    \
  
  
  
  1.16      +2 -0      modperl-2.0/src/modules/perl/modperl_perl.h
  
  Index: modperl_perl.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_perl.h,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -u -r1.15 -r1.16
  --- modperl_perl.h    4 Mar 2004 06:01:07 -0000       1.15
  +++ modperl_perl.h    2 Apr 2004 02:17:45 -0000       1.16
  @@ -40,6 +40,8 @@
   
   void modperl_perl_destruct(PerlInterpreter *perl);
   
  +void modperl_perl_call_endav(pTHX);
  +
   void modperl_hash_seed_init(apr_pool_t *p);
   
   void modperl_hash_seed_set(pTHX);
  
  
  
  1.21      +102 -45   modperl-2.0/src/modules/perl/modperl_perl_global.c
  
  Index: modperl_perl_global.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_perl_global.c,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -u -r1.20 -r1.21
  --- modperl_perl_global.c     18 Mar 2004 22:53:31 -0000      1.20
  +++ modperl_perl_global.c     2 Apr 2004 02:17:45 -0000       1.21
  @@ -21,7 +21,7 @@
       globals->inc.gv    = PL_incgv;
       globals->defout.gv = PL_defoutgv;
       globals->rs.sv     = &PL_rs;
  -    globals->end.av    = &PL_endav;
  +    globals->end.av    = PL_endav;
       globals->end.key   = MP_MODGLOBAL_END;
   }
   
  @@ -65,78 +65,142 @@
       return NULL;
   }
   
  +/*
  + * if (exists $PL_modglobal{$key}{$package}) {
  + *      return $PL_modglobal{$key}{$package};
  + * }
  + * elsif ($autovivify) {
  + *     return $PL_modglobal{$key}{$package} = [];
  + * }
  + * else {
  + *     return $Nullav; # a null pointer in C of course :)
  + * }
  + */
   static AV *modperl_perl_global_avcv_fetch(pTHX_ modperl_modglobal_key_t *gkey,
  -                                          const char *package, I32 packlen)
  +                                          const char *package, I32 packlen,
  +                                          I32 autovivify)
   {
       HE *he = MP_MODGLOBAL_FETCH(gkey);
       HV *hv;
   
       if (!(he && (hv = (HV*)HeVAL(he)))) {
  -        return Nullav;
  +        if (autovivify) {
  +            hv = MP_MODGLOBAL_STORE_HV(gkey);
  +        }
  +        else {
  +            return Nullav;
  +        }
       }
   
  -    if (!(he = hv_fetch_he(hv, (char *)package, packlen, 0))) {
  -        return Nullav;
  +    if ((he = hv_fetch_he(hv, (char *)package, packlen, 0))) {
  +        return (AV*)HeVAL(he);
  +    }
  +    else {
  +        if (autovivify) {
  +            return (AV*)*hv_store(hv, package, packlen, (SV*)newAV(), 0);
  +        }
  +        else {
  +            return Nullav;
  +        }
       }
  +}
  +
  +/* autovivify $PL_modglobal{$key}{$package} if it doesn't exist yet,
  + * so that in modperl_perl_global_avcv_set we will know whether to
  + * store blocks in it or keep them in the original list.
  + *
  + * For example in the case of END blocks, if
  + * $PL_modglobal{END}{$package} exists, modperl_perl_global_avcv_set
  + * will push newly encountered END blocks to it, otherwise it'll keep
  + * them in PL_endav.
  + */
  +void modperl_perl_global_avcv_register(pTHX_ modperl_modglobal_key_t *gkey,
  +                                       const char *package, I32 packlen)
  +{
  +    AV *av = modperl_perl_global_avcv_fetch(aTHX_ gkey,
  +                                            package, packlen, TRUE);
   
  -    return (AV*)HeVAL(he);
  +    MP_TRACE_g(MP_FUNC, "register PL_modglobal %s::%s (has %d entries)",
  +               package, (char*)gkey->name, av ? 1+av_len(av) : 0);
   }
   
  +/* if (exists $PL_modglobal{$key}{$package}) {
  + *     for my $cv (@{ $PL_modglobal{$key}{$package} }) {
  + *         $cv->();
  + *     }
  + * }
  + */
   void modperl_perl_global_avcv_call(pTHX_ modperl_modglobal_key_t *gkey,
                                      const char *package, I32 packlen)
   {
  -    AV *av = modperl_perl_global_avcv_fetch(aTHX_ gkey, package, packlen);
  +    AV *av = modperl_perl_global_avcv_fetch(aTHX_ gkey, package, packlen,
  +                                            FALSE);
   
  -    if (!av) {
  -        return;
  -    }
  +    MP_TRACE_g(MP_FUNC, "run PL_modglobal %s::%s (has %d entries)",
  +               package, (char*)gkey->name, av ? 1+av_len(av) : 0);
   
  -    modperl_perl_call_list(aTHX_ av, gkey->name);
  +    if (av) {
  +        modperl_perl_call_list(aTHX_ av, gkey->name);
  +    }
   }
   
  +
  +/* if (exists $PL_modglobal{$key}{$package}) {
  + *     @{ $PL_modglobal{$key}{$package} } = ();
  + * }
  + */
   void modperl_perl_global_avcv_clear(pTHX_ modperl_modglobal_key_t *gkey,
                                       const char *package, I32 packlen)
   {
  -    AV *av = modperl_perl_global_avcv_fetch(aTHX_ gkey, package, packlen);
  +    AV *av = modperl_perl_global_avcv_fetch(aTHX_ gkey,
  +                                            package, packlen, FALSE);
   
  -    if (!av) {
  -        return;
  +    MP_TRACE_g(MP_FUNC, "clear PL_modglobal %s::%s (has %d entries)",
  +               package, (char*)gkey->name, av ? 1+av_len(av) : 0);
  +    
  +    if (av) {
  +        av_clear(av);
       }
  -
  -    av_clear(av);
   }
   
   static int modperl_perl_global_avcv_set(pTHX_ SV *sv, MAGIC *mg)
   {
  -    HE *he;
  -    HV *hv;
       AV *mav, *av = (AV*)sv;
       const char *package = HvNAME(PL_curstash);
       I32 packlen = strlen(package);
       modperl_modglobal_key_t *gkey =
           (modperl_modglobal_key_t *)mg->mg_ptr;
   
  -    if ((he = MP_MODGLOBAL_FETCH(gkey))) {
  -        hv = (HV*)HeVAL(he);
  -    }
  -    else {
  -        hv = MP_MODGLOBAL_STORE_HV(gkey);
  -    }
  -
  -    if ((he = hv_fetch_he(hv, (char *)package, packlen, 0))) {
  -        mav = (AV*)HeVAL(he);
  -    }
  -    else {
  -        mav = (AV*)*hv_store(hv, package, packlen, (SV*)newAV(), 0);
  -    }
  -
  -    /* $cv = pop @av */
  -    sv = AvARRAY(av)[AvFILLp(av)];
  -    AvARRAY(av)[AvFILLp(av)--] = &PL_sv_undef;
  -
  +    /* the argument sv, is the original list perl was operating on.
  +     * (e.g. PL_endav). So now if we find that we have package/cv name
  +     * (e.g. Foo/END) registered for set-aside, we remove the cv that
  +     * was just unshifted in and push it into
  +     * $PL_modglobal{$key}{$package}. Otherwise we do nothing, which
  +     * keeps the unshifted cv (e.g. END block) in its original av
  +     * (e.g. PL_endav)
  +     */
  +     
  +    mav = modperl_perl_global_avcv_fetch(aTHX_ gkey, package, packlen, FALSE);
  +    
  +    if (!mav) {
  +        MP_TRACE_g(MP_FUNC, "%s::%s is not going to PL_modglobal",
  +                   package, (char*)gkey->name);
  +        /* keep it in the tied list (e.g. PL_endav) */
  +        return 1;
  +    }
  +
  +    MP_TRACE_g(MP_FUNC, "%s::%s is going into PL_modglobal",
  +               package, (char*)gkey->name);
  +        
  +    sv = av_shift(av);
  +    
       /* push @{ $PL_modglobal{$key}{$package} }, $cv */
       av_store(mav, AvFILLp(mav)+1, sv);
   
  +    /* print scalar @{ $PL_modglobal{$key}{$package} } */
  +    MP_TRACE_g(MP_FUNC, "%s::%s av now has %d entries\n",
  +               package, (char*)gkey->name, 1+av_len(mav));
  +    
       return 1;
   }
   
  @@ -146,9 +210,6 @@
       0, 0, 0,
   };
   
  -/* XXX: Apache::RegistryLoader type things need access to this
  - * for compiling scripts at startup
  - */
   static void modperl_perl_global_avcv_tie(pTHX_ modperl_modglobal_key_e key,
                                            AV *av)
   {
  @@ -172,17 +233,13 @@
   static void
   modperl_perl_global_avcv_save(pTHX_ modperl_perl_global_avcv_t *avcv)
   {
  -    avcv->origav = *avcv->av;
  -    *avcv->av = newAV(); /* XXX: only need 1 of these AVs per-interpreter */
  -    modperl_perl_global_avcv_tie(aTHX_ avcv->key, *avcv->av);
  +    modperl_perl_global_avcv_tie(aTHX_ avcv->key, avcv->av);
   }
   
   static void
   modperl_perl_global_avcv_restore(pTHX_ modperl_perl_global_avcv_t *avcv)
   {
  -    modperl_perl_global_avcv_untie(aTHX_ *avcv->av);
  -    SvREFCNT_dec(*avcv->av); /* XXX: see XXX above */
  -    *avcv->av = avcv->origav;
  +    modperl_perl_global_avcv_untie(aTHX_ avcv->av);
   }
   
   /*
  
  
  
  1.13      +4 -2      modperl-2.0/src/modules/perl/modperl_perl_global.h
  
  Index: modperl_perl_global.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_perl_global.h,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -u -r1.12 -r1.13
  --- modperl_perl_global.h     4 Mar 2004 06:01:07 -0000       1.12
  +++ modperl_perl_global.h     2 Apr 2004 02:17:45 -0000       1.13
  @@ -28,8 +28,7 @@
   } modperl_modglobal_key_e;
   
   typedef struct {
  -    AV **av;
  -    AV *origav;
  +    AV *av;
       modperl_modglobal_key_e key;
   } modperl_perl_global_avcv_t;
   
  @@ -71,6 +70,9 @@
   void modperl_perl_global_request_save(pTHX_ request_rec *r);
   
   void modperl_perl_global_request_restore(pTHX_ request_rec *r);
  +
  +void modperl_perl_global_avcv_register(pTHX_ modperl_modglobal_key_t *gkey,
  +                                       const char *package, I32 packlen);
   
   void modperl_perl_global_avcv_call(pTHX_ modperl_modglobal_key_t *gkey,
                                      const char *package, I32 packlen);
  
  
  
  1.65      +116 -25   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.64
  retrieving revision 1.65
  diff -u -u -r1.64 -r1.65
  --- modperl_util.c    5 Mar 2004 18:19:15 -0000       1.64
  +++ modperl_util.c    2 Apr 2004 02:17:45 -0000       1.65
  @@ -338,7 +338,7 @@
       void **handles;
   
       if (!librefs) {
  -     MP_TRACE_g(MP_FUNC,
  +     MP_TRACE_r(MP_FUNC,
                      "Could not get @%s for unloading.\n",
                      dl_librefs);
        return NULL;
  @@ -357,14 +357,14 @@
        SV *module_sv = *av_fetch(modules, i, FALSE);
   
        if(!handle_sv) {
  -         MP_TRACE_g(MP_FUNC,
  +         MP_TRACE_r(MP_FUNC,
                          "Could not fetch $%s[%d]!\n",
                          dl_librefs, (int)i);
            continue;
        }
        handle = (void *)SvIV(handle_sv);
   
  -     MP_TRACE_g(MP_FUNC, "%s dl handle == 0x%lx\n",
  +     MP_TRACE_r(MP_FUNC, "%s dl handle == 0x%lx\n",
                      SvPVX(module_sv), (unsigned long)handle);
        if (handle) {
            handles[i] = handle;
  @@ -388,7 +388,7 @@
       }
   
       for (i=0; handles[i]; i++) {
  -        MP_TRACE_g(MP_FUNC, "close 0x%lx\n", (unsigned long)handles[i]);
  +        MP_TRACE_r(MP_FUNC, "close 0x%lx\n", (unsigned long)handles[i]);
           modperl_sys_dlclose(handles[i]);
       }
   
  @@ -544,6 +544,13 @@
   {
       I32 i, oldscope = PL_scopestack_ix;
       SV **ary = AvARRAY(subs);
  +
  +    /* XXX: why this trace doesn't get printed to error_log when this
  +     * method is called from modperl_perl_destruct. Perl_warn works
  +     * just fine. may be we need to switch to perl_warn when apache
  +     * closes the logging api (when?) */
  +    MP_TRACE_g(MP_FUNC, "pid %lu running %d %s subs",
  +               (unsigned long)getpid(), AvFILLp(subs)+1, name);
       
       for (i=0; i<=AvFILLp(subs); i++) {
        CV *cv = (CV*)ary[i];
  @@ -764,27 +771,6 @@
       return newRV_noinc(sv);
   }
   
  -#ifdef MP_TRACE
  -/* XXX: internal debug function */
  -/* any non-false value for MOD_PERL_TRACE/PerlTrace enables this function */
  -void modperl_apr_table_dump(pTHX_ apr_table_t *table, char *name)
  -{
  -    int i;
  -    const apr_array_header_t *array;
  -    apr_table_entry_t *elts;
  -
  -    array = apr_table_elts(table);
  -    elts  = (apr_table_entry_t *)array->elts;
  -    modperl_trace(MP_FUNC, "Contents of table %s", name);
  -    for (i = 0; i < array->nelts; i++) {
  -        if (!elts[i].key || !elts[i].val) {
  -            continue;
  -        }
  -        modperl_trace(MP_FUNC, "%s => %s", elts[i].key, elts[i].val);
  -    }    
  -}
  -#endif
  -
   #define MP_VALID_PKG_CHAR(c) (isalnum(c) ||(c) == '_')
   #define MP_VALID_PATH_DELIM(c) ((c) == '/' || (c) =='\\')
   char *modperl_file2package(apr_pool_t *p, const char *file)
  @@ -858,3 +844,108 @@
       /* copy the SV in case the pool goes out of scope before the perl scalar */
       return newSVpv(ap_server_root_relative(p, fname), 0);
   }
  +
  +char *modperl_coderef2text(pTHX_ apr_pool_t *p, CV *cv)
  +{
  +    dSP;
  +    int count;
  +    SV *bdeparse;
  +    char *text;
  +    
  +    /* B::Deparse >= 0.61 needed for blessed code references.
  +     * 0.6 works fine for non-blessed code refs.
  +     * notice that B::Deparse is not CPAN-updatable.
  +     * 0.61 is available starting from 5.8.0
  +     */
  +    load_module(PERL_LOADMOD_NOIMPORT,
  +                newSVpvn("B::Deparse", 10),
  +                newSVnv(SvOBJECT((SV*)cv) ? 0.61 : 0.60));
  +
  +    ENTER;
  +    SAVETMPS;
  +
  +    /* create the B::Deparse object */
  +    PUSHMARK(sp);
  +    XPUSHs(sv_2mortal(newSVpvn("B::Deparse", 10)));
  +    PUTBACK;
  +    count = call_method("new", G_SCALAR);
  +    SPAGAIN;
  +    if (count != 1) {
  +        Perl_croak(aTHX_ "Unexpected return value from B::Deparse::new\n");
  +    }
  +    if (SvTRUE(ERRSV)) {
  +        Perl_croak(aTHX_ "error: %s", SvPVX(ERRSV));
  +    }
  +    bdeparse = POPs;
  +
  +    PUSHMARK(sp);
  +    XPUSHs(bdeparse);
  +    XPUSHs(sv_2mortal(newRV_inc((SV*)cv)));
  +    PUTBACK;
  +    count = call_method("coderef2text", G_SCALAR);
  +    SPAGAIN;
  +    if (count != 1) {
  +        Perl_croak(aTHX_ "Unexpected return value from "
  +                   "B::Deparse::coderef2text\n");
  +    }
  +    if (SvTRUE(ERRSV)) {
  +        Perl_croak(aTHX_ "error: %s", SvPVX(ERRSV));
  +    }
  +    
  +    {
  +        STRLEN n_a;
  +        text = apr_pstrcat(p, "sub ", POPpx, NULL);
  +    }
  +    
  +    PUTBACK;
  +    
  +    FREETMPS;
  +    LEAVE;
  +
  +    return text;
  +}
  +
  +#ifdef MP_TRACE
  +
  +/* XXX: internal debug function, a candidate for modperl_debug.c */
  +/* any non-false value for MOD_PERL_TRACE/PerlTrace enables this function */
  +void modperl_apr_table_dump(pTHX_ apr_table_t *table, char *name)
  +{
  +    int i;
  +    const apr_array_header_t *array;
  +    apr_table_entry_t *elts;
  +
  +    array = apr_table_elts(table);
  +    elts  = (apr_table_entry_t *)array->elts;
  +    modperl_trace(MP_FUNC, "Contents of table %s", name);
  +    for (i = 0; i < array->nelts; i++) {
  +        if (!elts[i].key || !elts[i].val) {
  +            continue;
  +        }
  +        modperl_trace(MP_FUNC, "%s => %s", elts[i].key, elts[i].val);
  +    }    
  +}
  +
  +/* XXX: internal debug function, a candidate for modperl_debug.c */
  +void modperl_perl_modglobal_dump(pTHX)
  +{
  +    HV *hv = PL_modglobal;
  +    AV *val;
  +    char *key;
  +    I32 klen;
  +    hv_iterinit(hv);
  +
  +    MP_TRACE_g(MP_FUNC, "|-------- PL_modglobal --------");
  +    MP_TRACE_g(MP_FUNC, "| perl 0x%lx PL_modglobal 0x%lx",
  +               (unsigned long)aTHX, (unsigned long)PL_modglobal);
  +    
  +    while ((val = (AV*)hv_iternextsv(hv, &key, &klen))) {
  +        MP_TRACE_g(MP_FUNC, "| %s => 0x%lx", key, val);
  +    }
  +    
  +    MP_TRACE_g(MP_FUNC, "|-------- PL_modglobal --------\n");
  +        
  +}
  +
  +
  +#endif
  
  
  
  1.53      +16 -3     modperl-2.0/src/modules/perl/modperl_util.h
  
  Index: modperl_util.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_util.h,v
  retrieving revision 1.52
  retrieving revision 1.53
  diff -u -u -r1.52 -r1.53
  --- modperl_util.h    4 Mar 2004 06:01:07 -0000       1.52
  +++ modperl_util.h    2 Apr 2004 02:17:45 -0000       1.53
  @@ -169,12 +169,25 @@
   
   void modperl_clear_symtab(pTHX_ HV *symtab);
   
  +char *modperl_file2package(apr_pool_t *p, const char *file);
  +
  +SV *modperl_server_root_relative(pTHX_ SV *sv, const char *fname);
  +
  +/**
  + * convert a compiled *CV ref to its original source code
  + * @param p       pool object (with a shortest possible life scope)
  + * @param cv      compiled *CV
  + * @return string of original source code
  + */
  +char *modperl_coderef2text(pTHX_ apr_pool_t *p, CV *cv);
  +
   #ifdef MP_TRACE
  +
   void modperl_apr_table_dump(pTHX_ apr_table_t *table, char *name);
  -#endif
   
  -char *modperl_file2package(apr_pool_t *p, const char *file);
  +/* dump the contents of PL_modglobal */
  +void modperl_perl_modglobal_dump(pTHX);
   
  -SV *modperl_server_root_relative(pTHX_ SV *sv, const char *fname);
  +#endif
   
   #endif /* MODPERL_UTIL_H */
  
  
  
  1.3       +14 -4     modperl-2.0/t/response/TestModperl/endav.pm
  
  Index: endav.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/t/response/TestModperl/endav.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -u -r1.2 -r1.3
  --- endav.pm  11 Apr 2002 11:08:44 -0000      1.2
  +++ endav.pm  2 Apr 2004 02:17:46 -0000       1.3
  @@ -17,27 +17,37 @@
       #just to make sure we dont segv with bogus values
       my $not = 'NoSuchPackage';
       for my $name ('END', $not) {
  -        ModPerl::Global::special_list_call($name => $not);
  +        ModPerl::Global::special_list_call( $name => $not);
           ModPerl::Global::special_list_clear($name => $not);
       }
   
  +    # register the current package to set its END blocks aside
  +    ModPerl::Global::special_list_register(END => __PACKAGE__);
  +    # clear anything that was previously set
  +    ModPerl::Global::special_list_clear(END => __PACKAGE__);
       eval 'END { ok 1 }';
   
  +    # now run them twice:ok 1 (1), ok 1 (2)
       ModPerl::Global::special_list_call(END => __PACKAGE__);
       ModPerl::Global::special_list_call(END => __PACKAGE__);
   
       ModPerl::Global::special_list_clear(END => __PACKAGE__);
       #should do nothing
  -    ModPerl::Global::special_list_call(END => __PACKAGE__);
  +    ModPerl::Global::special_list_call( END => __PACKAGE__);
   
  +    # this we've already registered this package's END blocks, adding
  +    # new ones will set them aside
       eval 'END { ok 1 }';
  -    ModPerl::Global::special_list_call(END => __PACKAGE__);
  +
  +    # so this will run ok 1 (3)
  +    ModPerl::Global::special_list_call( END => __PACKAGE__);
       ModPerl::Global::special_list_clear(END => __PACKAGE__);
   
       ModPerl::Global::special_list_clear(END => __PACKAGE__);
       #should do nothing
  -    ModPerl::Global::special_list_call(END => __PACKAGE__);
  +    ModPerl::Global::special_list_call( END => __PACKAGE__);
   
  +    # one plain ok 1 (4)
       ok 1;
   
       Apache::OK;
  
  
  
  1.5       +9 -0      modperl-2.0/xs/ModPerl/Global/ModPerl__Global.h
  
  Index: ModPerl__Global.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/ModPerl/Global/ModPerl__Global.h,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -u -r1.4 -r1.5
  --- ModPerl__Global.h 4 Mar 2004 06:01:13 -0000       1.4
  +++ ModPerl__Global.h 2 Apr 2004 02:17:46 -0000       1.5
  @@ -50,3 +50,12 @@
       return mpxs_special_list_do(aTHX_ name, package,
                                   modperl_perl_global_avcv_clear);
   }
  +
  +static
  +MP_INLINE int mpxs_ModPerl__Global_special_list_register(pTHX_
  +                                                         const char *name,
  +                                                         SV *package)
  +{
  +    return mpxs_special_list_do(aTHX_ name, package,
  +                                modperl_perl_global_avcv_register);
  +}
  
  
  
  1.71      +1 -0      modperl-2.0/xs/maps/modperl_functions.map
  
  Index: modperl_functions.map
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/maps/modperl_functions.map,v
  retrieving revision 1.70
  retrieving revision 1.71
  diff -u -u -r1.70 -r1.71
  --- modperl_functions.map     5 Mar 2004 18:19:15 -0000       1.70
  +++ modperl_functions.map     2 Apr 2004 02:17:46 -0000       1.71
  @@ -10,6 +10,7 @@
   MODULE=ModPerl::Global
    mpxs_ModPerl__Global_special_list_call
    mpxs_ModPerl__Global_special_list_clear
  + mpxs_ModPerl__Global_special_list_register
   
   MODULE=Apache::RequestRec   PACKAGE=Apache::RequestRec
    mpxs_Apache__RequestRec_content_type   | | r, type=Nullsv
  
  
  
  1.149     +61 -0     modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm
  
  Index: FunctionTable.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v
  retrieving revision 1.148
  retrieving revision 1.149
  diff -u -u -r1.148 -r1.149
  --- FunctionTable.pm  3 Mar 2004 06:29:33 -0000       1.148
  +++ FunctionTable.pm  2 Apr 2004 02:17:46 -0000       1.149
  @@ -3839,6 +3839,28 @@
     },
     {
       'return_type' => 'void',
  +    'name' => 'modperl_perl_global_avcv_register',
  +    'args' => [
  +      {
  +        'type' => 'PerlInterpreter *',
  +        'name' => 'my_perl'
  +      },
  +      {
  +        'type' => 'modperl_modglobal_key_t *',
  +        'name' => 'gkey'
  +      },
  +      {
  +        'type' => 'const char *',
  +        'name' => 'package'
  +      },
  +      {
  +        'type' => 'I32',
  +        'name' => 'packlen'
  +      }
  +    ]
  +  },
  +  {
  +    'return_type' => 'void',
       'name' => 'modperl_perl_global_request_restore',
       'args' => [
         {
  @@ -6191,6 +6213,27 @@
       ]
     },
     {
  +    'return_type' => 'int',
  +    'name' => 'mpxs_ModPerl__Global_special_list_register',
  +    'attr' => [
  +      '__inline__'
  +    ],
  +    'args' => [
  +      {
  +        'type' => 'PerlInterpreter *',
  +        'name' => 'my_perl'
  +      },
  +      {
  +        'type' => 'const char *',
  +        'name' => 'name'
  +      },
  +      {
  +        'type' => 'SV *',
  +        'name' => 'package'
  +      }
  +    ]
  +  },
  +  {
       'return_type' => 'void',
       'name' => 'mpxs_ModPerl__Util_untaint',
       'attr' => [
  @@ -6414,6 +6457,24 @@
         {
           'type' => 'const char *',
           'name' => 'fname'
  +      }
  +    ]
  +  },
  +  {
  +    'return_type' => 'char *',
  +    'name' => 'modperl_coderef2text',
  +    'args' => [
  +      {
  +        'type' => 'PerlInterpreter *',
  +        'name' => 'my_perl'
  +      },
  +      {
  +        'type' => 'apr_pool_t *',
  +        'name' => 'p'
  +      },
  +      {
  +        'type' => 'CV *',
  +        'name' => 'cv'
         }
       ]
     },
  
  
  
  1.355     +11 -0     modperl-2.0/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/Changes,v
  retrieving revision 1.354
  retrieving revision 1.355
  diff -u -u -r1.354 -r1.355
  --- Changes   26 Mar 2004 22:17:07 -0000      1.354
  +++ Changes   2 Apr 2004 02:17:46 -0000       1.355
  @@ -12,6 +12,17 @@
   
   =item 1.99_14-dev
   
  +'SetHandler perl-script' no longer grabs any newly encountered END
  +blocks, and removes them from PL_endav, but only if they are
  +explicitly registered via ModPerl::Global::special_list_register(END
  +=> $package_name) (this is a new function). It's now possible to have
  +a complete control of when END blocks are run from the user space, not
  +only in the registry handlers [Stas]
  +
  +END blocks encountered by child processes and not hijacked by
  +ModPerl::Global::special_list_register() are now executed at the
  +server shutdown (previously they weren't executed at all). [Stas]
  +
   Added test to ensure <Perl> sections can have things like %Location
   tied [Gozer]
   
  
  
  
  1.20      +0 -13     modperl-2.0/todo/release
  
  Index: release
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/todo/release,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -u -r1.19 -r1.20
  --- release   4 Mar 2004 01:09:50 -0000       1.19
  +++ release   2 Apr 2004 02:17:46 -0000       1.20
  @@ -52,19 +52,6 @@
       Apache->server->process->pconf->cleanup_register(sub { ...  });
     Report: geoff
   
  -* child processes never run END blocks. a good example is
  -  Apache::TestUtil, which doesn't cleanup files and dirs it has
  -  created, because the END block is not run.
  -  also: see the next item
  -  owner: stas
  -
  -* ModPerl::Registry END {} block woes , described in details at the
  -  forwarded message from Jim Schueler
  -  http://marc.theaimsgroup.com/?l=apache-modperl&m=103720834717981&w=2
  -  the whole thread is here:
  -  http://marc.theaimsgroup.com/?t=103713532800003&r=1&w=2
  -  owner: stas
  -
   - PerlModule, PerlRequire, <Perl> in .htaccess is missing
     http://marc.theaimsgroup.com/?t=105370088700001&r=1&w=2
     Owner: geoff
  
  
  

Reply via email to