File Coverage

blib/lib/Mojo/IOLoop/Signal.pm
Criterion Covered Total %
statement 18 77 23.3
branch 0 28 0.0
condition 0 8 0.0
subroutine 6 19 31.5
pod 5 6 83.3
total 29 138 21.0


line stmt bran cond sub pod time code
1             package Mojo::IOLoop::Signal;
2 1     1   73332 use Mojo::Base 'Mojo::EventEmitter';
  1         204470  
  1         13  
3              
4 1     1   1889 use Config;
  1         2  
  1         40  
5 1     1   515 use Mojo::IOLoop::Stream;
  1         183210  
  1         9  
6 1     1   43 use Mojo::IOLoop;
  1         2  
  1         5  
7 1     1   26 use Mojo::Util ();
  1         2  
  1         20  
8 1     1   5 use Scalar::Util 'weaken';
  1         2  
  1         1464  
9              
10             our $VERSION = '0.002';
11             my %SIGNAME = map { $_ => 1 } split /\s+/, $Config{sig_name};
12             our %EXCLUDE = map { $_ => 1 } qw(PIPE KILL);
13              
14             sub _instance {
15 0     0     state $SELF = __PACKAGE__->_new;
16 0 0         ref $_[0] ? $_[0] : $SELF
17             }
18              
19 0     0 0   sub singleton { _instance(shift) }
20              
21 0     0 1   sub new { die "Cannot construct Mojo::IOLoop::Signal objects. It's a singleton.\n" }
22              
23             sub _new {
24 0     0     my $class = shift;
25 0           my $reactor = Mojo::IOLoop->singleton->reactor;
26 0           my $is_ev;
27 0 0         if ($reactor->isa('Mojo::Reactor::EV')) {
    0          
28 0           $is_ev = 1;
29             } elsif ($reactor->isa('Mojo::Reactor::Poll')) {
30 0           $is_ev = 0;
31             } else {
32 0           die "Unsupported reactor: " . ref($reactor);
33             }
34 0           bless { keep => {}, is_ev => $is_ev }, $class;
35             }
36              
37             sub DESTROY {
38 0 0   0     Mojo::Util::_global_destruction() or shift->stop;
39             }
40              
41             sub stop {
42 0     0 1   my $self = _instance(shift);
43 0 0         if (!$self->{is_ev}) {
44 0 0         if ($self->{write}) {
45 0           $self->{write}->close;
46 0           $self->{read}->stop;
47 0           $self->{read}->close_gracefully;
48 0           delete $self->{$_} for qw(write read);
49             }
50 0           for my $name (keys %{$self->{keep}}) {
  0            
51 0           $SIG{$name} = $self->{keep}{$name};
52             }
53             }
54 0           $self->{keep} = {};
55 0           $self;
56             }
57              
58             sub _is_signame {
59 0     0     my ($class, $name) = @_;
60 0 0         $SIGNAME{$name} and !$EXCLUDE{$name};
61             }
62              
63             sub once {
64 0     0 1   my ($self, $name, $cb) = (_instance(shift), @_);
65 0           $self->SUPER::once($name, $cb);
66             }
67              
68             sub on {
69 0     0 1   my ($self, $name, $cb) = (_instance(shift), @_);
70 0 0 0       if ($self->_is_signame($name) and !exists $self->{keep}{$name}) {
71 0 0         if ($self->{is_ev}) {
72 0     0     $self->{keep}{$name} = EV::signal($name => sub { $self->emit($name, $name) });
  0            
73             } else {
74 0 0         if (!$self->{write}) {
75 0           pipe my $read, my $write;
76 0           $write->autoflush(1);
77             $self->{read} = Mojo::IOLoop::Stream->new($read),
78 0           $self->{read}->timeout(0);
79 0           $self->{write} = $write;
80 0           weaken $self;
81             $self->{read}->on(read => sub {
82 0     0     my (undef, $bytes) = @_;
83 0           $self->emit($_, $_) for split /\n/, $bytes;
84 0           });
85 0           $self->{read}->start;
86             }
87 0   0       $self->{keep}{$name} = $SIG{$name} || 'DEFAULT';
88             $SIG{$name} = sub {
89             Mojo::IOLoop->timer(0 => sub {
90 0 0         syswrite $self->{write}, "$name\n" or warn "pipe write: $!";
91 0     0     });
92 0           };
93             }
94             }
95 0           $self->SUPER::on($name, $cb);
96             }
97              
98             sub unsubscribe {
99 0     0 1   my ($self, $name, @arg) = (_instance(shift), @_);
100 0           $self->SUPER::unsubscribe($name, @arg);
101 0 0 0       if ($self->_is_signame($name) and !$self->has_subscribers($name)) {
102 0 0         if ($self->{is_ev}) {
103 0           delete $self->{keep}{$name};
104             } else {
105 0           $SIG{$name} = delete $self->{keep}{$name};
106             }
107             }
108 0 0         if (!%{$self->{keep}}) {
  0            
109 0           $self->stop;
110             }
111 0           $self;
112             }
113              
114             1;
115             __END__