1#  You may distribute under the terms of either the GNU General Public License
2#  or the Artistic License (the same terms as Perl itself)
3#
4#  (C) Paul Evans, 2009-2011 -- leonerd@leonerd.org.uk
5
6package IO::Async::Signal;
7
8use strict;
9use warnings;
10use base qw( IO::Async::Notifier );
11
12our $VERSION = '0.800';
13
14use Carp;
15
16=head1 NAME
17
18C<IO::Async::Signal> - event callback on receipt of a POSIX signal
19
20=head1 SYNOPSIS
21
22   use IO::Async::Signal;
23
24   use IO::Async::Loop;
25   my $loop = IO::Async::Loop->new;
26
27   my $signal = IO::Async::Signal->new(
28      name => "HUP",
29
30      on_receipt => sub {
31          print "I caught SIGHUP\n";
32      },
33   );
34
35   $loop->add( $signal );
36
37   $loop->run;
38
39=head1 DESCRIPTION
40
41This subclass of L<IO::Async::Notifier> invokes its callback when a particular
42POSIX signal is received.
43
44Multiple objects can be added to a C<Loop> that all watch for the same signal.
45The callback functions will all be invoked, in no particular order.
46
47=cut
48
49=head1 EVENTS
50
51The following events are invoked, either using subclass methods or CODE
52references in parameters:
53
54=head2 on_receipt
55
56Invoked when the signal is received.
57
58=cut
59
60=head1 PARAMETERS
61
62The following named parameters may be passed to C<new> or C<configure>:
63
64=head2 name => STRING
65
66The name of the signal to watch. This should be a bare name like C<TERM>. Can
67only be given at construction time.
68
69=head2 on_receipt => CODE
70
71CODE reference for the C<on_receipt> event.
72
73Once constructed, the C<Signal> will need to be added to the C<Loop> before it
74will work.
75
76=cut
77
78sub _init
79{
80   my $self = shift;
81   my ( $params ) = @_;
82
83   my $name = delete $params->{name} or croak "Expected 'name'";
84
85   $name =~ s/^SIG//; # Trim a leading "SIG"
86
87   $self->{name} = $name;
88
89   $self->SUPER::_init( $params );
90}
91
92sub configure
93{
94   my $self = shift;
95   my %params = @_;
96
97   if( exists $params{on_receipt} ) {
98      $self->{on_receipt} = delete $params{on_receipt};
99
100      undef $self->{cb}; # Will be lazily constructed when needed
101
102      if( my $loop = $self->loop ) {
103         $self->_remove_from_loop( $loop );
104         $self->_add_to_loop( $loop );
105      }
106   }
107
108   unless( $self->can_event( 'on_receipt' ) ) {
109      croak 'Expected either a on_receipt callback or an ->on_receipt method';
110   }
111
112   $self->SUPER::configure( %params );
113}
114
115sub _add_to_loop
116{
117   my $self = shift;
118   my ( $loop ) = @_;
119
120   $self->{cb} ||= $self->make_event_cb( 'on_receipt' );
121
122   $self->{id} = $loop->attach_signal( $self->{name}, $self->{cb} );
123}
124
125sub _remove_from_loop
126{
127   my $self = shift;
128   my ( $loop ) = @_;
129
130   $loop->detach_signal( $self->{name}, $self->{id} );
131   undef $self->{id};
132}
133
134sub notifier_name
135{
136   my $self = shift;
137   if( length( my $name = $self->SUPER::notifier_name ) ) {
138      return $name;
139   }
140
141   return $self->{name};
142}
143
144=head1 AUTHOR
145
146Paul Evans <leonerd@leonerd.org.uk>
147
148=cut
149
1500x55AA;
151