File Coverage

blib/lib/Net/Server/SIG.pm
Criterion Covered Total %
statement 38 43 88.3
branch 11 14 78.5
condition n/a
subroutine 7 9 77.7
pod 4 4 100.0
total 60 70 85.7


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Net::Server::SIG - Safer signals
4             #
5             # Copyright (C) 2001-2022
6             #
7             # Paul Seamons
8             #
9             # This package may be distributed under the terms of either the
10             # GNU General Public License
11             # or the
12             # Perl Artistic License
13             #
14             # All rights reserved.
15             #
16             ################################################################
17              
18             package Net::Server::SIG;
19              
20 7     7   52 use strict;
  7         17  
  7         327  
21 7     7   48 use Carp qw(croak);
  7         16  
  7         686  
22 7         696 use vars qw($VERSION @ISA @EXPORT_OK
23 7     7   51 %_SIG %_SIG_SUB);
  7         19  
24 7     7   43 use Exporter ();
  7         14  
  7         3766  
25              
26             $VERSION = '0.03';
27             @ISA = qw(Exporter);
28             @EXPORT_OK = qw(register_sig unregister_sig check_sigs);
29              
30             sub register_sig {
31 54 50   54 1 196 croak 'Usage: register_sig( SIGNAME => \&code_ref )' if @_ % 2;
32 54 100       216 if (@_ > 2) {
33 6         161 register_sig(shift(),shift()) while @_;
34 6         28 return;
35             }
36 48         234 my $sig = shift;
37 48         305 my $code_ref = shift;
38 48         109 my $ref = ref($code_ref);
39              
40 48 100       131 if (! $ref) {
    50          
41 27 100       81 if ($code_ref eq 'DEFAULT') {
    50          
42 24         53 delete $_SIG{$sig};
43 24         367 delete $_SIG_SUB{$sig};
44 24         360 $SIG{$sig} = 'DEFAULT';
45             } elsif ($code_ref eq 'IGNORE') {
46 3         10 delete $_SIG{$sig};
47 3         8 delete $_SIG_SUB{$sig};
48 3         106 $SIG{$sig} = 'IGNORE';
49             } else {
50 0         0 croak 'Scalar argument limited to "DEFAULT" and "IGNORE"';
51             }
52             } elsif ($ref eq 'CODE') {
53 21         171 $_SIG{$sig} = 0;
54 21         81 $_SIG_SUB{$sig} = $code_ref;
55 21     3   445 $SIG{$sig} = sub{ $Net::Server::SIG::_SIG{$sig} = 1 };
  3         9720  
56             } else {
57 0         0 croak "Unsupported sig type -- must be 'DEFAULT' or a code ref.";
58             }
59             }
60              
61 0     0 1 0 sub unregister_sig { register_sig(shift(), 'DEFAULT') }
62              
63             sub check_sigs {
64 8     8 1 23 my @found;
65 8         196 foreach my $sig (keys %_SIG){
66 43 100       146 next if ! $_SIG{$sig};
67 3         18 $_SIG{$sig} = 0;
68 3         27 push @found, $sig;
69 3         26 $_SIG_SUB{$sig}->($sig);
70             }
71 5         33 return @found;
72             }
73              
74             sub sig_is_registered {
75 0     0 1   my $sig = shift;
76 0           return $_SIG_SUB{$sig};
77             }
78              
79             1;
80              
81             =head1 NAME
82              
83             Net::Server::SIG - adpf - Safer signal handling
84              
85             =head1 SYNOPSIS
86              
87             use Net::Server::SIG qw(register_sig check_sigs);
88             use IO::Select ();
89             use POSIX qw(WNOHANG);
90              
91             my $select = IO::Select->new();
92              
93             register_sig(PIPE => 'IGNORE',
94             HUP => 'DEFAULT',
95             USR1 => sub { print "I got a SIG $_[0]\n"; },
96             USR2 => sub { print "I got a SIG $_[0]\n"; },
97             CHLD => sub { 1 while waitpid(-1, WNOHANG) > 0; },
98             );
99              
100             # add some handles to the select
101             $select->add(\*STDIN);
102              
103             # loop forever trying to stay alive
104             while (1) {
105              
106             # do a timeout to see if any signals got passed us
107             # while we were processing another signal
108             my @fh = $select->can_read(10);
109              
110             my $key;
111             my $val;
112              
113             # this is the handler for safe (fine under unsafe also)
114             if (check_sigs()) {
115             # or my @sigs = check_sigs();
116             next unless @fh;
117             }
118              
119             my $handle = $fh[@fh];
120              
121             # do something with the handle
122              
123             }
124              
125             =head1 DESCRIPTION
126              
127             Signals prior in Perl prior to 5.7 were unsafe. Since then signals
128             have been implemented in a more safe algorithm. Net::Server::SIG
129             provides backwards compatibility, while still working reliably with
130             newer releases.
131              
132             Using a property of the select() function, Net::Server::SIG attempts
133             to fix the unsafe problem. If a process is blocking on select() any
134             signal will short circuit the select. Using this concept,
135             Net::Server::SIG does the least work possible (changing one bit from 0
136             to 1). And depends upon the actual processing of the signals to take
137             place immediately after the select call via the "check_sigs"
138             function. See the example shown above and also see the sigtest.pl
139             script located in the examples directory of this distribution.
140              
141             =head1 FUNCTIONS
142              
143             =over 4
144              
145             =item C \&code_ref)>
146              
147             Takes key/value pairs where the key is the signal name, and the
148             argument is either a code ref, or the words 'DEFAULT' or 'IGNORE'.
149             The function register_sig must be used in conjunction with check_sigs,
150             and with a blocking select() function call -- otherwise, you will
151             observe the registered signal mysteriously vanish.
152              
153             =item C
154              
155             Takes the name of a signal as an argument. Calls register_sig with a
156             this signal name and 'DEFAULT' as arguments (same as
157             register_sig(SIG,'DEFAULT')
158              
159             =item C
160              
161             Checks to see if any registered signals have occurred. If so, it will
162             play the registered code ref for that signal. Return value is array
163             containing any SIGNAL names that had occurred.
164              
165             =item C
166              
167             Takes a signal name and returns any registered code_ref for that signal.
168              
169             =back
170              
171             =head1 AUTHORS
172              
173             Paul Seamons (paul@seamons.com)
174              
175             Rob B Brown (rob@roobik.com) - Provided a sounding board and feedback
176             in creating Net::Server::SIG and sigtest.pl.
177              
178             =head1 LICENSE
179              
180             This package may be distributed under the terms of either the
181             GNU General Public License
182             or the
183             Perl Artistic License
184              
185             All rights reserved.
186              
187             =cut