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   82156 use Mojo::Base 'Mojo::EventEmitter';
  1         197943  
  1         7  
3              
4 1     1   1605 use Config;
  1         3  
  1         36  
5 1     1   403 use Mojo::IOLoop::Stream;
  1         185695  
  1         9  
6 1     1   43 use Mojo::IOLoop;
  1         2  
  1         3  
7 1     1   22 use Mojo::Util ();
  1         2  
  1         16  
8 1     1   4 use Scalar::Util 'weaken';
  1         2  
  1         1236  
9              
10             our $VERSION = '0.003';
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 0 0   0     sub DESTROY { shift->stop unless ${^GLOBAL_PHASE} eq 'DESTRUCT' }
38              
39             sub stop {
40 0     0 1   my $self = _instance(shift);
41 0 0         if (!$self->{is_ev}) {
42 0 0         if ($self->{write}) {
43 0           $self->{write}->close;
44 0           $self->{read}->stop;
45 0           $self->{read}->close_gracefully;
46 0           delete $self->{$_} for qw(write read);
47             }
48 0           for my $name (keys %{$self->{keep}}) {
  0            
49 0           $SIG{$name} = $self->{keep}{$name};
50             }
51             }
52 0           $self->{keep} = {};
53 0           $self;
54             }
55              
56             sub _is_signame {
57 0     0     my ($class, $name) = @_;
58 0 0         $SIGNAME{$name} and !$EXCLUDE{$name};
59             }
60              
61             sub once {
62 0     0 1   my ($self, $name, $cb) = (_instance(shift), @_);
63 0           $self->SUPER::once($name, $cb);
64             }
65              
66             sub on {
67 0     0 1   my ($self, $name, $cb) = (_instance(shift), @_);
68 0 0 0       if ($self->_is_signame($name) and !exists $self->{keep}{$name}) {
69 0 0         if ($self->{is_ev}) {
70 0     0     $self->{keep}{$name} = EV::signal($name => sub { $self->emit($name, $name) });
  0            
71             } else {
72 0 0         if (!$self->{write}) {
73 0           pipe my $read, my $write;
74 0           $write->autoflush(1);
75             $self->{read} = Mojo::IOLoop::Stream->new($read),
76 0           $self->{read}->timeout(0);
77 0           $self->{write} = $write;
78 0           weaken $self;
79             $self->{read}->on(read => sub {
80 0     0     my (undef, $bytes) = @_;
81 0           $self->emit($_, $_) for split /\n/, $bytes;
82 0           });
83 0           $self->{read}->start;
84             }
85 0   0       $self->{keep}{$name} = $SIG{$name} || 'DEFAULT';
86             $SIG{$name} = sub {
87             Mojo::IOLoop->timer(0 => sub {
88 0 0         syswrite $self->{write}, "$name\n" or warn "pipe write: $!";
89 0     0     });
90 0           };
91             }
92             }
93 0           $self->SUPER::on($name, $cb);
94             }
95              
96             sub unsubscribe {
97 0     0 1   my ($self, $name, @arg) = (_instance(shift), @_);
98 0           $self->SUPER::unsubscribe($name, @arg);
99 0 0 0       if ($self->_is_signame($name) and !$self->has_subscribers($name)) {
100 0 0         if ($self->{is_ev}) {
101 0           delete $self->{keep}{$name};
102             } else {
103 0           $SIG{$name} = delete $self->{keep}{$name};
104             }
105             }
106 0 0         if (!%{$self->{keep}}) {
  0            
107 0           $self->stop;
108             }
109 0           $self;
110             }
111              
112             1;
113             __END__