File Coverage

blib/lib/Mojo/IOLoop/Signal.pm
Criterion Covered Total %
statement 18 78 23.0
branch 0 26 0.0
condition 0 8 0.0
subroutine 6 19 31.5
pod 5 6 83.3
total 29 137 21.1


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