gmpassos has asked for the wisdom of the Perl Monks concerning the following question:

I need to be able to call the END blocks of packages without go to the global destruction process. So, how can I force the execution of that at runtime?

I was thinking in some perlhack for that, but I wan't to know if someone already did that.

Why I need that? Well, I really need. In the module Safe::World I simulate multiple Perl interpreters in a single Perl enverioment, and after execute and use a World I need to clean it from the memory, and to do things right I need to call END when this is done.

Graciliano M. P.
"Creativity is the expression of the liberty".

  • Comment on Is possible to force the execution of a END block at runtime, without need to start global destruction?

Replies are listed 'Best First'.
Re: Is possible to force the execution of a END block at runtime, without need to start global destruction?
by broquaint (Abbot) on May 21, 2004 at 03:06 UTC
    If you've got a recent enough version of perl (5.7+ IIRC) then you can use some B magic to access END blocks e.g
    use B; sub B::exec_ENDs { my $pkg = caller; $_->object_2svref->() for grep { $_->GV->STASH->NAME eq $pkg } B::end_av->ARRAY; } { package foo; sub pretend_to_leave { B->exec_ENDs(); print "I'll go get my coat ...\n"; } END { print "... another END block\n" } END { print "foo: this will be followed by " } } foo->pretend_to_leave(); END { print "main: Right, I'm outta here\n" } __output__ foo: this will be followed by ... another END block I'll go get my coat ... main: Right, I'm outta here foo: this will be followed by ... another END block
    So there I've created a subroutine (that I've snuck into B) that will execute the END blocks for the current package.
    HTH

    _________
    broquaint

      Wow, thanks, this is a nice point to start. But I need to avoid that the END blocks that I have called at runtime won't be called on global destruction. At least this B code have a way to find the right END block in the list for a package, than I can overwrite them with a null END block.

      Many thanks.

      Graciliano M. P.
      "Creativity is the expression of the liberty".

      Just to end the node, here's a XS function that I made that return a reference to the CODE of the END blocks:
      void get_end_sub( pkg ) char * pkg PREINIT: CV *cv_end ; PPCODE: if ( PL_endav ) { long i ; SV **svp = av_fetch(PL_endav , 0 , FALSE) ; long lng = av_len( PL_endav ) ; EXTEND(SP, lng + 1 ) ; for( i = 0 ; i <= lng ; ++i ) { cv_end = (CV *) svp[i] ; if ( !strcmp( HvNAME(CvSTASH(cv_end)) , pkg) ) { PUSHs( newRV_inc( cv_end ) ); } } }
      And you can use in this way:
      my @end_subs = get_end_sub( 'Package::Foo' ) ; my $sub = $end_subs[0] ; &$sub() ;

      Graciliano M. P.
      "Creativity is the expression of the liberty".

Re: Is possible to force the execution of a END block at runtime, without need to start global destruction?
by hv (Prior) on May 21, 2004 at 02:57 UTC

    I'm not aware of any easy way to do so, and in general I don't think this is something perl necessarily wants to (or can - see below) make too easy.

    Based on a quick look, the relevant code is in perl.c:Perl_destruct():

    if(PL_exit_flags & PERL_EXIT_DESTRUCT_END) { ... if (PL_endav && !PL_minus_c) call_list(PL_scopestack_ix, PL_endav); ... }
    and it should be possible to mock up something based on this. The tricky part is determining whether you should remove the entries after calling them so that they won't be called again, and depending on the nature of your application it is quite possible that you won't know whether or not to do that in each case without first determining the purpose of that particular END block. Which is likely to be a bit tricky.

    Hugo

Re: Is possible to force the execution of a END block at runtime, without need to start global destruction?
by duff (Parson) on May 21, 2004 at 02:20 UTC

    Surely you can put whatever actions you need done at END time into a subroutine and call that subroutine manually whenever you like (in addition to from within an END block)

    I'm not sure what you mean by "and to do things right I need to call END". If this thought occurs to you, it's a sign of design error on your part and you need to rethink your design IMHO

      We can't call END, since BEGIN, CHECK, INIT & END are not subroutine, are speciall blocks. We can declare them as subroutine just as a style, but in Perl the sub will doesn't exists in the symbol table, it will be in a speciall list inside Perl, that is called on destruction.

      What I wan't is to call this END blocks at runtime, END blocks defined by other modules, users, etc...

      Graciliano M. P.
      "Creativity is the expression of the liberty".

        sub end { # Put here what you'd normally put in END {...} } END {end}

        Abigail