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

Hello all. I'm writing a new profiler for Perl called Devel::Profiler and I've run into a problem. Basically, my profiler works by instrumenting every subroutine it can find by enclosing it in a call of my crafting. Now, what I need to do is this (eliding the wantarray() stuff that's already working):

&$code; # call the wrapped sub if (CODE DIED) { # do something about that and let the die() happen } else { # do something else }

Now, the obvious way to do that is to wrap the call in an eval {} and check $@:

eval { &$code; }; # call the wrapped sub if ($@) { # do something about that and let the die() happen } else { # do something else }

The problem with that is that I don't want to mess up the die() string that's already there. If I catch it with eval{} then I have to re-throw with die() to let the die() happen. But then the die() will refer to my module instead of the actual source of the die() when it's printed.

I'm getting a tickle somewhere in my memory banks that I can could use an object with a DESTROY method somehow... But I'm just not putting 2 and 2 together here.

Devel::DProf uses SAVE_DESTRUCTOR_X() to handle this problem, which is also tickling my memory, but nothing specific is popping out.

Anyone want to step up to the blackboard and show me how it's done?

-sam

PS: I bet a lot of you are wondering why I would write another profiler when Devel::DProf is hahn rockin'. Well, unfortunately Devel::DProf does nothing but seg-fault on my application and I absolutely need a profiler. I spent a few days trying to fix Devel::DProf and I'm just not up to it. Neither, apparently, is anyone else on p5p and Ilya won't have time to look at it until the fall... So, here I am. Read the RATIONALE section in my POD for the full scoop.

PPS: The links to my code above are to the CVS version. It's not done yet so don't bother giving it a code review. When I release my first version I'll be happy to hear all about what a dumbass I am!

Replies are listed 'Best First'.
Re: How to detect a die() without catching it?
by belg4mit (Prior) on May 17, 2002 at 22:55 UTC
    It would seem you want the old standbys of %SIG and sigtrap. Of course, die actually has information on this...

    --
    perl -pew "s/\b;([mnst])/'$1/g"

      I do? You mean I should use $SIG{__DIE__} right? Won't that cause problems with evals in the code being called? And how does it avoid the need to re-die() to continue the error?

      UPDATE: More to the point, these profiler subs will be called recursively. There will be a stack of profiler subs equivalent to the normal Perl call stack. How can I use $SIG{__DIE__} in a case where multiple subs need to be ready to catch die()s?

      Of course, I may just be clinging irrationally to the idea that this is a hard problem just to save myself from realizing I'm a manual-ignoring moron...

      -sam

        A little experimentation and reading will get you a long ways. You don't die in a DIE handler, recursion is bad. You exit, or you don't, it's your call. But those are your two options, eval or $SIG{DIE}.

        >Won't that cause problems with evals in the code being called?
        Could you rephrase the question? It's not exactly clear what you mean there.

        --
        perl -pew "s/\b;([mnst])/'$1/g"

Re: How to detect a die() without catching it?
by jmcnamara (Monsignor) on May 17, 2002 at 23:03 UTC

    I may be missing something (or a lot) but can't you just call die() with $@ to reproduce the original error message:
    eval { &$code; }; # call the wrapped sub if ($@) { # do something about that die $@; } else { # do something else }

    --
    John.

      The problem is that when that die() gets printed it will say "at Devel::Profiler, line X" instead of the real source of the die().

      -sam

        For this part, you can just add a "\n" to the end of the message, right? e.g.
        sub blah { die "blah"; } eval {blah();}; if ($@) { die "$@\n"; } else { print "okay\n"; } # prints "blah at foo.pl line 4"
        /s