File Coverage

blib/lib/Enbugger/OnError.pm
Criterion Covered Total %
statement 33 37 89.1
branch 7 8 87.5
condition 6 9 66.6
subroutine 7 7 100.0
pod 0 2 0.0
total 53 63 84.1


line stmt bran cond sub pod time code
1             package Enbugger::OnError;
2             $Enbugger::OnError::VERSION = '2.016';
3             # COPYRIGHT AND LICENCE
4             #
5             # Copyright (C) 2007,2008 WhitePages.com, Inc. with primary
6             # development by Joshua ben Jore.
7             #
8             # This program is distributed WITHOUT ANY WARRANTY, including but not
9             # limited to the implied warranties of merchantability or fitness for
10             # a particular purpose.
11             #
12             # The program is free software. You may distribute it and/or modify
13             # it under the terms of the GNU General Public License as published by
14             # the Free Software Foundation (either version 2 or any later version)
15             # and the Perl Artistic License as published by O’Reilly Media, Inc.
16             # Please open the files named gpl-2.0.txt and Artistic for a copy of
17             # these licenses.
18              
19 3     3   136163 use strict;
  3         10  
  3         107  
20 3     3   17 use warnings;
  3         8  
  3         85  
21 3     3   18 use Carp();
  3         8  
  3         132  
22              
23             use constant {
24 3         1799 'DEFAULT_SIGNALS' => [qw[ __DIE__ USR1 ]],
25             'DEFAULT_HOOK' => \&ExceptionHandler,
26 3     3   27 };
  3         6  
27              
28             sub import {
29 3     3   135 my ( $class, @signals ) = @_;
30            
31 3         27 my $hook = $class->DEFAULT_HOOK;
32 3 100       23 my $signals =
33             @signals
34             ? \ @signals
35             : $class->DEFAULT_SIGNALS;
36              
37 3         11 $class->hook_signals( $signals, $hook );
38            
39 3         5725 return;
40             }
41              
42             sub hook_signals {
43 3     3 0 5 my ( $self, $signals, $hook ) = @_;
44            
45 3         124 @SIG{@$signals} = ($hook) x @$signals;
46            
47 3         9 return;
48             }
49              
50             sub ExceptionHandler {
51              
52             # Find the list of things in %SIG that are trapped by this function.
53 3     3 0 4324 my ( @self_hooked_sigs, %self_hooked_sigs_lu );
54 3         20 keys %SIG;
55 3         44 while ( my ( $name, $handler ) = each %SIG ) {
56 206 100 66     1393 if ( ref $handler
57             and $handler == \ &ExceptionHandler ) {
58 5         11 push @self_hooked_sigs, $name;
59 5         44 $self_hooked_sigs_lu{$name} = undef;
60             }
61             }
62              
63             # When we are in a __DIE__ handler, do not accept when there is an
64             # outer eval scope. Perhaps this should be configurable policy.
65 3 100 66     40 if ( ( $_[0] eq '__DIE__'
      66        
66             or ( not exists $self_hooked_sigs_lu{$_[0]} ) )
67             and exists $self_hooked_sigs_lu{__DIE__} ) {
68 2         22 for (
69             my $cx = 1;
70             my ( undef, undef, undef, $function ) = caller $cx;
71             ++ $cx
72             ) {
73            
74            
75 1 50       53 if ($function =~ /^\(eval *\d*\)\z/ ) {
76 1         8 return 1;
77             }
78             }
79             }
80            
81            
82             # Do not re-enter this handler while in it. In theory I could work
83             # on this to make it safe for being reentrant but that's just not
84             # work I'm doing today. Feel free to do this and send patches.
85 2         36 local @SIG{ @self_hooked_sigs } = ('IGNORE') x @self_hooked_sigs;
86            
87            
88              
89             # Enable the debugger even if it wasn't used at compilation
90             # time. ->debugger points to whatever the locally preferred
91             # debugger is.
92 2         1308 require Enbugger;
93 2         41171 Enbugger->load_debugger;
94            
95             # Log the current exception.
96 0           Enbugger->write( Carp::longmess("Received signal $_[0]") );
97            
98            
99             # Trigger the debugger. I did some trial and error to get
100             # this. perl5db.pl pays attention to $DB::signal. $^P gets set (if
101             # it wasn't already) to statement level debugging and then enter
102             # the DB() function. I originally tried this as goto &DB::DB but
103             # found that I'd get popped out of the debugger. Whoops.
104 0           Enbugger->stop;
105              
106 0           $@ = $_[0];
107 0           DB::DB();
108             }
109              
110              
111             =begin emacs
112              
113             ## Local Variables:
114             ## mode: cperl
115             ## mode: auto-fill
116             ## cperl-indent-level: 4
117             ## End:
118              
119             =end emacs
120              
121             =cut
122              
123             () = -.0