File Coverage

blib/lib/Signals/XSIG.pm
Criterion Covered Total %
statement 360 399 90.2
branch 108 144 75.0
condition 43 65 66.1
subroutine 62 71 87.3
pod 0 3 0.0
total 573 682 84.0


line stmt bran cond sub pod time code
1             package Signals::XSIG;
2              
3             ## no critic (RequireLocalizedPunctuationVars, ProhibitAutomaticExport)
4              
5 12     12   65439 use Signals::XSIG::Default;
  12         26  
  12         57  
6 12     12   63 use Carp;
  12         21  
  12         529  
7 12     12   57 use Config;
  12         16  
  12         267  
8 12     12   44 use Exporter;
  12         19  
  12         248  
9 12     12   44 use POSIX ();
  12         17  
  12         180  
10 12     12   4565 use Symbol qw(qualify);
  12         8159  
  12         570  
11 12     12   4890 use Time::HiRes 'time';
  12         13266  
  12         39  
12 12     12   1805 use warnings;
  12         21  
  12         265  
13 12     12   77 use strict;
  12         18  
  12         2253  
14              
15             our @ISA = qw(Exporter);
16             our @EXPORT = qw(%XSIG);
17             our @EXPORT_OK = qw(untied %DEFAULT_BEHAVIOR);
18              
19             our %DEFAULT_BEHAVIOR;
20             *DEFAULT_BEHAVIOR = \%Signals::XSIG::Default::DEFAULT_BEHAVIOR;
21              
22             our $VERSION = '0.16';
23             our (%XSIG, %_XSIG, %SIGTABLE, $_REFRESH, $_DISABLE_WARNINGS);
24             our $_INITIALIZED = 0;
25             our $SIGTIE = bless {}, 'Signals::XSIG::TieSIG';
26             our $XSIGTIE = bless {}, 'Signals::XSIG::TieXSIG';
27             our $TIEARRAY_CLASS = 'Signals::XSIG::TieArray';
28              
29             my %TIEDSCALARS = (); # map signal names to S::X::TiedScalar objs
30             my %alias = ();
31              
32              
33             ###
34             # to be removed when we get a handle on intermittent t/02 failures
35             our ($XDEBUG,$XN,@XLOG) = (0,1001);
36 12 50   12 0 102 sub XLOG{no warnings"uninitialized";push @XLOG,($XN++)." @_";XLOG_DUMP() if $XDEBUG>1}
  12     612   16  
  12         1874  
  612         1706  
  612         964  
37 0     0 0 0 sub XLOG_DUMP{my $r = join("\n",@XLOG); @XLOG=(); print "$r\n"}
  0         0  
  0         0  
38             ###
39              
40              
41             BEGIN {
42             # how to detect global destruction. Idea from Devel::GlobalDestruction 0.13
43 12 50   12   65 if (defined ${^GLOBAL_PHASE}) {
44 12 50   169   953 eval 'sub __inGD() {${^GLOBAL_PHASE} eq "DESTRUCT" && __END()}; 1';
  169         1002  
45             } else {
46 0         0 require B;
47 0         0 eval 'sub __inGD() { ${B::main_cv()}==0 && __END();}; 1';
48             }
49             }
50              
51             &_init;
52              
53             sub _init {
54 12 50   12   32 return if $_INITIALIZED;
55 12         14 $_REFRESH = 0;
56 12 50       390 if ($Config{PERL_VERSION} <= 6) {
57 0         0 require Signals::XSIG::TieArray56;
58 0         0 $TIEARRAY_CLASS = 'Signals::XSIG::TieArray56';
59             }
60              
61 12         35 my @z = ();
62 12         183 my @num = split ' ', $Config{sig_num};
63 12         220 my @name = split ' ', $Config{sig_name};
64 12         111 for (my $i=0; $i<@name; $i++) {
65 828 100       1257 if (defined $z[$num[$i]]) {
66 48         84 $alias{$name[$i]} = $z[$num[$i]];
67 48         87 $alias{$z[$num[$i]]} = $name[$i];
68 48         89 $alias{"pk:$z[$num[$i]]"} = 1;
69             }
70 828         1552 $z[$num[$i]] = $name[$i];
71             }
72              
73 12         85 foreach my $sig (@name, '__WARN__', '__DIE__') {
74 852         2140 tie $_XSIG{$sig}, 'Signals::XSIG::TieScalar', $sig;
75             #### this functionality all happens within S::X::TieScalar::TIESCALAR now
76             # $_XSIG{$sig} = [];
77             # tie @{$_XSIG{$sig}}, $TIEARRAY_CLASS, $sig;
78             # $_XSIG{$sig}[0] = $SIG{$sig};
79             }
80 12         40 tie %SIG, 'Signals::XSIG::TieSIG';
81 12         24 $_REFRESH = 1;
82 12         30 foreach my $sig (@name, '__WARN__', '__DIE__') {
83 852 100       1305 next if $sig eq 'ZERO';
84 840 50       917 unless (eval { (tied @{$_XSIG{$sig}})->_refresh_SIG; 1 }) {
  840         932  
  840         1602  
  840         1645  
85 0         0 Carp::confess "Error initializing \@{\$XSIG{$sig}}!: $@\n";
86             }
87             }
88 12         38 tie %XSIG, 'Signals::XSIG::TieXSIG';
89              
90 12         296 my @signo = split ' ', $Config{sig_num};
91 12         291 my @signame = split ' ', $Config{sig_name};
92 12         69 for (my $i=0; $i<@signo; $i++) {
93 828         952 my $signo = $signo[$i];
94 828         803 my $signame = $signame[$i];
95 828   66     2495 $SIGTABLE{$signo} ||= $signame;
96 828         2336 $SIGTABLE{'SIG' . $signame} = $SIGTABLE{$signame} = $SIGTABLE{$signo};
97             }
98 12         28 $SIGTABLE{'__WARN__'} = '__WARN__';
99 12         32 $SIGTABLE{'__DIE__'} = '__DIE__';
100 12         183 return ++$_INITIALIZED;
101             }
102              
103             sub __shadow__warn__handler { ## no critic (Unpacking)
104 0     0   0 return &__shadow_signal_handler('__WARN__',@_)
105             }
106             sub __shadow__die__handler { ## no critic (Unpacking)
107 0     0   0 return &__shadow_signal_handler('__DIE__',@_)
108             }
109              
110 12     12   37069469 END { &__END; }
111              
112             sub __END {
113 12     12   78 no warnings 'redefine';
  12         19  
  12         2870  
114 12     12   312 *__inGD = sub () { 1 };
115             }
116              
117             sub __shadow_signal_handler {
118 25     25   1898 my ($signal, @args) = @_;
119              
120             # %XSIG might be partially or completely untied during global destruction
121 25 50       578 return if __inGD();
122 25         38 my $seen_default = 0;
123              
124 25         30 my $h = tied @{$XSIG{$signal}};
  25         115  
125 25         58 my @handlers = $h->handlers;
126 25         41 my $start = $h->{start} - 1;
127 25         28 my $ignore_main_default = 0;
128              
129             # @HANDLER_SEQUENCE: the handlers that have already processed this signal
130             # will using 'local' be sufficient to distinguish handler count when
131             # signal handling is interrupted by another signal?
132 25         38 local @Signals::XSIG::HANDLER_SEQUENCE = ();
133 25         44 while (@handlers) {
134 186         211 my $subhandler = shift @handlers;
135 186         188 $start++;
136 186 100       268 next if !defined($subhandler);
137 155 100       247 next if $subhandler eq '';
138 149 100       193 if ($start != 0) {
139 125         125 $ignore_main_default = 1;
140             }
141 149 100       225 next if $subhandler eq 'IGNORE';
142 134 100       180 if ($subhandler eq 'DEFAULT') {
143 5 50       10 if ($start == 0) {
144 0 0       0 if ($ignore_main_default) {
145 0         0 next;
146             }
147 0 0       0 if (0 != grep { defined($_) && $_ ne '' } @handlers) {
  0 0       0  
148 0         0 next;
149             }
150             }
151 5 100       10 next if $seen_default++;
152 4         14 Signals::XSIG::Default::perform_default_behavior($signal, @args);
153 4         10 push @Signals::XSIG::HANDLER_SEQUENCE, 'DEFAULT';
154             } else {
155 129 100       199 next if !defined &$subhandler;
156 12     12   73 no strict 'refs'; ## no critic (NoStrict)
  12         15  
  12         6722  
157 123 50       151 if ($signal =~ /__\w+__/) {
158 0         0 $subhandler->(@args);
159             } else {
160 123         186 $subhandler->($signal, @args);
161             }
162 123         379 push @Signals::XSIG::HANDLER_SEQUENCE, $subhandler;
163             }
164             }
165 25         207 return;
166             }
167              
168             # convert a signal name to its canonical name. If not disabled,
169             # warn if the input is not a valid signal name.
170             # TERM => TERM
171             # CLD => CHLD
172             # OOK => warning
173             sub _resolve_signal {
174 7048     7048   8655 my ($sig, $DISABLE_WARNINGS) = @_;
175 7048   66     17696 $DISABLE_WARNINGS ||= $_DISABLE_WARNINGS;
176 7048         9520 $sig = $SIGTABLE{uc $sig};
177 7048 100       9681 if (defined $sig) {
178 6170         6997 $_[0] = $sig; ## no critic (Unpacking)
179 6170         8398 return 1;
180             }
181 878 100       1329 return 1 if !$_INITIALIZED;
182              
183             # signal could not be resolved -- issue warning and return false
184 38 100       61 unless ($DISABLE_WARNINGS) {
185 10 50 33     607 if (defined($sig) && $sig =~ /\d/ && $sig !~ /\D/) {
    50 33        
186 0         0 carp "Invalid signal number $sig.\n";
187             } elsif (warnings::enabled('signal')) {
188 0         0 Carp::cluck "Invalid signal name $sig.\n";
189             }
190             }
191 38         63 return;
192             }
193              
194             # execute a block of code while %SIG is temporarily untied.
195              
196             sub untied (&) { ## no critic (SubroutinePrototypes)
197 2582     2582 0 3377 my $BLOCK = shift;
198              
199 2582         4961 untie %SIG;
200 2582 50       4538 my @r = wantarray ? $BLOCK->() : scalar $BLOCK->();
201 2582         7692 tie %SIG, 'Signals::XSIG::TieSIG';
202              
203 2582 50       5803 return wantarray ? @r : $r[0];
204             }
205              
206              
207              
208             # in %SIG and %XSIG assignments, string values are qualified to the
209             # 'main' package, unqualified *glob values are qualified to the
210             # calling package.
211             sub _qualify_handler {
212 2096     2096   2358 my $handler = shift;
213              
214 2096 100 100     5432 if (!defined($handler)
      100        
      100        
215             || $handler eq ''
216             || $handler eq 'IGNORE'
217             || $handler eq 'DEFAULT') {
218 1596         2288 return $handler;
219             }
220              
221 500 100       1142 if (substr($handler,0,1) eq '*') {
222 18         23 my $n = 0;
223 18         36 my $package = caller;
224 18   66     130 while (defined($package) && $package =~ /^Signals::XSIG/) {
225 35         127 $package = caller(++$n);
226             }
227              
228 18   50     87 $handler = qualify($handler, $package || 'main');
229             } else {
230 482         1049 $handler = qualify($handler, 'main');
231             }
232 500         3100 return $handler;
233             }
234              
235             #####################################################
236             #
237             # Signals::XSIG::TieSIG
238             #
239             # Only for tie-ing %SIG.
240             # Associates $SIG{key} with $XSIG{$sig}[0]
241             #
242              
243             sub Signals::XSIG::TieSIG::TIEHASH {
244 2594 100   2594   4337 $XDEBUG && XLOG("TieSIG::TIE caller=",caller);
245 2594         3947 return $SIGTIE;
246             }
247              
248             sub Signals::XSIG::TieSIG::FETCH {
249 1214     1214   657982 my ($self,$key) = @_;
250              
251             # track function calls to diagnose test failures
252 1214 100 66     2321 $XDEBUG && $key ne '__DIE__'
253             && XLOG("FETCH key=$key caller=",caller);
254 1214 100       1715 if (_resolve_signal($key)) {
255 1207 100 66     1853 $XDEBUG && $key ne '__DIE__' && XLOG(" result(1)=",$_XSIG{$key}[0]);
256 1207         2298 return $_XSIG{$key}[0];
257             } else {
258 12     12   91 no warnings 'uninitialized';
  12         43  
  12         1633  
259 7     7   30 my $r = untied { $SIG{$key} };
  7         15  
260 7 50 33     25 $XDEBUG && $key ne '__DIE__' && XLOG(" result(2)=$r");
261 7         33 return $r;
262             }
263             }
264              
265             sub Signals::XSIG::TieSIG::STORE {
266 945     945   9760 my ($self,$key,$value) = @_;
267 12     12   128 no warnings 'uninitialized';
  12         18  
  12         1466  
268 945 100 66     1673 $XDEBUG && $key ne '__DIE__'
269             && XLOG("STORE($key,$value) caller=",caller);
270 945 100       1265 if (_resolve_signal($key)) {
271 943         1693 my $old = $_XSIG{$key}[0];
272 943         1959 $_XSIG{$key}[0] = $value;
273 943         34621 return $old;
274             } else {
275 2         2 my $old;
276 2 50       4 $XDEBUG && XLOG(" key $key not resolved");
277             untied {
278 12     12   69 no warnings 'signal'; ## no critic (NoWarnings)
  12         17  
  12         2369  
279 2     2   5 $old = $SIG{$key};
280 2         8 $SIG{$key} = $value;
281 2         10 };
282 2         9 return $old;
283             }
284             }
285              
286             sub Signals::XSIG::TieSIG::DELETE {
287 4     4   15 my ($self,$key) = @_;
288 4 50 33     10 $XDEBUG && $key ne '__DIE__'
289             && XLOG("DELETE key=$key caller=",caller);
290 4 100       9 if (_resolve_signal($key)) {
291 3         7 my $old = $_XSIG{$key}[0];
292 3 50       9 $XDEBUG && XLOG(" DELETE result(1)=$old");
293 3         5 $_XSIG{$key}[0] = undef;
294 3         13 return $old;
295             } else {
296 1         3 my $old = $self->FETCH($key);
297 12     12   72 no warnings 'uninitialized';
  12         18  
  12         11205  
298 1 50       3 $XDEBUG && XLOG(" DELETE result(2)=$old");
299             untied {
300 1     1   47 $SIG{$key} = undef;
301 1         6 delete $SIG{$key};
302 1         4 };
303 1         6 return $old;
304             }
305             }
306              
307             sub Signals::XSIG::TieSIG::CLEAR {
308 3     3   1311 my ($self) = @_;
309 3 100       12 $XDEBUG && do {
310 2         7 XLOG("CLEAR caller=",caller);
311 2         4 XLOG(" CLEAR init USR1=",@{$_XSIG{USR1}});
  2         5  
312 2         5 XLOG(" CLEAR init USR2=",@{$_XSIG{USR2}});
  2         4  
313             };
314              
315             # this used to say
316             # $_XSIG{$_}[0] = undef for keys %_XSIG
317             # but on some platforms, for a reason I don't yet understand,
318             # the signal handler for the first value in the for loop
319             # would not get cleared properly. For another reason I don't
320             # yet understand, this is apparently not an issue for the
321             # __WARN__ and __DIE__ handlers, so we'll manipulate the signal
322             # list to make sure those handlers go first.
323            
324 3         112 my @sigs = reverse sort keys %_XSIG;
325 3 100       35 $XDEBUG && XLOG(" \@sigs = qw(@sigs);");
326 3         8 for (@sigs) {
327 213         469 $_XSIG{$_}[0] = undef;
328             }
329              
330 3 100       8 $XDEBUG && do {
331 2         3 XLOG(" CLEAR final USR1=",@{$_XSIG{USR1}});
  2         5  
332 2         3 XLOG(" CLEAR final USR2=",@{$_XSIG{USR2}});
  2         4  
333             };
334 3         34 return;
335             }
336              
337             sub Signals::XSIG::TieSIG::EXISTS {
338 470     470   165337649 my ($self,$key) = @_;
339 470 50 33     1089 $XDEBUG && $key ne '__DIE__'
340             && XLOG("EXISTS key=$key caller=",caller);
341 470     470   2610 return untied { exists $SIG{$key} };
  470         1200  
342             }
343              
344             sub Signals::XSIG::TieSIG::FIRSTKEY {
345 2     2   670 my ($self) = @_;
346 2 50       5 $XDEBUG && XLOG("FIRSTKEY caller=",caller);
347 2         5 my $a = keys %_XSIG;
348 2 50       4 $XDEBUG && XLOG(" FIRSTKEY result=$a");
349 2         8 return each %_XSIG;
350             }
351              
352             sub Signals::XSIG::TieSIG::NEXTKEY {
353 142     142   175 my ($self, $lastkey) = @_;
354 142 50       178 $XDEBUG && XLOG("NEXTKEY lastkey=$lastkey caller=",caller);
355 142         345 return each %_XSIG;
356             }
357              
358             sub Signals::XSIG::TieSIG::UNTIE {
359 2579 100 66 2579   6892 $XDEBUG && !__inGD() && XLOG("UNTIE caller=",caller);
360 2579         3826 return;
361             }
362              
363             ############################################################
364             #
365             # Signals::XSIG::TieArray
366             #
367             # Applied to @{$XSIG{signal}}.
368             # On update, refreshes the handler for the signal.
369             #
370              
371             sub Signals::XSIG::TieArray::TIEARRAY {
372 833     833   1428 my ($class, @list) = @_;
373 833         1129 my $obj = bless {}, 'Signals::XSIG::TieArray';
374 833         1503 $obj->{key} = shift @list;
375 833         1034 $obj->{start} = 0; # {start} refers to slot for first element of {handlers}
376 833         1255 $obj->{handlers} = [ map { _qualify_handler($_) } @list ];
  83         108  
377 833         1387 return $obj;
378             }
379              
380             # Wow. Those Perl guys thought of everything.
381             $Signals::XSIG::TieArray::NEGATIVE_INDICES = 1;
382              
383             sub Signals::XSIG::TieArray::FETCH {
384 2316     2316   3187 my ($self, $index) = @_;
385 2316         2715 $index -= $self->{start};
386 2316 100       3304 return if $index < 0;
387 2314         7679 return $self->{handlers}[$index];
388             }
389              
390             sub Signals::XSIG::TieArray::STORE {
391 2013     2013   3352 my ($self, $index, $handler) = @_;
392 2013         2416 $index -= $self->{start};
393              
394 2013         3274 while ($index < 0) {
395 10         10 unshift @{$self->{handlers}}, undef;
  10         14  
396 10         10 $index++;
397 10         14 $self->{start}--;
398             }
399              
400 2013         2147 while ($index > $#{$self->{handlers}}) {
  2981         4982  
401 968         1081 push @{$self->{handlers}}, undef;
  968         1475  
402             }
403              
404 2013         2646 my $old = $self->{handlers}[$index];
405              
406 2013         2711 $handler = _qualify_handler($handler);
407 2013         2637 $self->{handlers}[$index] = $handler;
408 2013 100       3103 $XDEBUG
409             && XLOG("TA::STORE key=$self->{key} index=$index val=",$handler,
410             " caller=",caller);
411 2013         3493 $self->_refresh_SIG();
412 2013         3466 return $old;
413             }
414              
415             sub Signals::XSIG::TieArray::_refresh_SIG {
416 2905     2905   3132 my $self = shift;
417 2905 100       4316 return if $_REFRESH == 0;
418              
419 2101         2568 my $sig = $self->{key};
420 2101         2517 my @index_list = ();
421 2101         2081 my @handlers = @{$self->{handlers}};
  2101         3105  
422 2101         2936 my ($seen_default, $seen_ignore) = (0,0);
423 2101         3642 for (my $i=0; $i<@handlers; $i++) {
424 3030 100       5690 next if !defined $handlers[$i];
425 742 100 100     1413 next if $handlers[$i] eq 'DEFAULT' && $seen_default++;
426 741 100 100     1267 next if $handlers[$i] eq 'IGNORE' && $seen_ignore++;
427 738         1626 push @index_list, $i + $self->{start};
428             }
429              
430 2101         2575 my $handler_to_install;
431 2101 100 66     3716 if (@index_list == 0) {
    100 66        
432 1588         1801 $handler_to_install = undef;
433             }
434              
435             # XXX - if there is a single handler, and that handler is 'DEFAULT',
436             # do we want to install the shadow signal handler anyway?
437             # The caller may have overridden the DEFAULT behavior of the signal,
438             # so yeah, I think we do.
439              
440             elsif (@index_list == 1 &&
441             ($seen_default == 0 || ref($DEFAULT_BEHAVIOR{$sig}) eq '')) {
442 454         616 $handler_to_install = $handlers[$index_list[0]];
443             } else {
444 59 50       118 if ($sig eq '__WARN__') {
    50          
445 0         0 $handler_to_install = \&Signals::XSIG::__shadow__warn__handler;
446             } elsif ($sig eq '__DIE__') {
447 0         0 $handler_to_install = \&Signals::XSIG::__shadow__die__handler;
448             } else {
449 59         91 $handler_to_install = \&Signals::XSIG::__shadow_signal_handler;
450             }
451             }
452             untied {
453 12     12   75 no warnings qw(uninitialized signal); ## no critic (NoWarnings)
  12         20  
  12         15390  
454 2101 100   2101   3109 $XDEBUG
455             && XLOG("refresh_SIG key=$self->{key} handler=$handler_to_install");
456 2101         15517 $SIG{$sig} = $handler_to_install;
457 2101         7861 };
458 2101         5690 return;
459             }
460              
461             sub Signals::XSIG::TieArray::handlers {
462 25     25   29 my $self = shift;
463 25         26 return @{$self->{handlers}};
  25         72  
464             }
465              
466             sub Signals::XSIG::TieArray::FETCHSIZE {
467 21     21   31 my ($self) = @_;
468 21         24 return scalar @{$self->{handlers}};
  21         54  
469             }
470              
471       0     sub Signals::XSIG::TieArray::STORESIZE { }
472              
473       2     sub Signals::XSIG::TieArray::EXTEND { }
474              
475             sub Signals::XSIG::TieArray::EXISTS {
476 0     0   0 my ($self, $index) = @_;
477 0 0       0 return if $index < $self->{start};
478 0         0 return exists $self->{handlers}[$index - $self->{start}];
479             }
480              
481             sub Signals::XSIG::TieArray::DELETE {
482 4     4   11 my ($self, $index) = @_;
483 4         9 $index -= $self->{start};
484 4 50       11 return if $index < 0;
485 4         8 my $old = $self->{handlers}[$index];
486 4         19 $self->{handlers}[$index] = undef;
487 4         9 $self->_refresh_SIG;
488 4         12 return $old;
489             }
490              
491             sub Signals::XSIG::TieArray::CLEAR {
492 2     2   5 my ($self) = @_;
493 2         7 $self->{handlers} = [];
494 2         3 $self->{start} = 0;
495 2         24 $self->_refresh_SIG;
496 2         7 return;
497             }
498              
499             sub Signals::XSIG::TieArray::UNSHIFT {
500 4     4   17 my ($self, @list) = @_;
501 4         6 unshift @{$self->{handlers}}, @list;
  4         11  
502 4         8 $self->{start} -= @list;
503 4         8 $self->_refresh_SIG;
504 4         16 return $self->FETCHSIZE;
505             }
506              
507             sub Signals::XSIG::TieArray::POP {
508 5     5   11 my ($self) = @_;
509 5 100       7 if (@{$self->{handlers}} + $self->{start} <= 1) {
  5         14  
510 1         4 return;
511             }
512 4         6 my $val = pop @{$self->{handlers}};
  4         7  
513 4         9 $self->_refresh_SIG;
514 4         12 return $val;
515             }
516              
517             sub Signals::XSIG::TieArray::SHIFT {
518 4     4   6 my $self = shift;
519 4 100       11 if ($self->{start} >= 0) {
520 2         5 return;
521             }
522 2         2 my $val = shift @{$self->{handlers}};
  2         6  
523 2         3 $self->{start}++;
524 2         5 $self->_refresh_SIG;
525 2         12 return $val;
526             }
527              
528             sub Signals::XSIG::TieArray::PUSH {
529 7     7   17 my ($self, @list) = @_;
530 7 100       10 if (@{$self->{handlers}} + $self->{start} <= 0) {
  7         22  
531 2         6 unshift @list, undef;
532             }
533 7         10 my $val = push @{$self->{handlers}}, @list;
  7         23  
534 7         17 $self->_refresh_SIG;
535 7         18 return $val;
536             }
537              
538       0     sub Signals::XSIG::TieArray::SPLICE { }
539              
540             ##################################################################
541             #
542             # Signals::XSIG::TieScalar
543             #
544             # For tie-ing $XSIG{signal}.
545             # Handles expressions like $XSIG{signal} = [ ... ]
546             # and $XSIG{signal} = handler
547             # Main purpose is to assert that $XSIG{$sig} is always set
548             # to a reference to a Signals::XSIG::TieArray object.
549             #
550              
551             sub Signals::XSIG::TieScalar::TIESCALAR {
552 852     852   1527 my ($class, @list) = @_;
553 852         954 my $key = $list[0];
554 852 100 100     1597 if (defined($alias{$key}) && !defined($alias{"pk:$key"})) {
555 48         126 return $TIEDSCALARS{$key} = $TIEDSCALARS{$alias{$key}};
556             }
557              
558 804         1767 my $self = bless { key => $key }, 'Signals::XSIG::TieScalar';
559 804         1417 $self->{val} = [];
560 804         877 tie @{$self->{val}}, $TIEARRAY_CLASS, $key;
  804         1507  
561 804         5707 $self->{val}[0] = $SIG{$key};
562 804         1511 $TIEDSCALARS{$key} = $self;
563 804         1668 return $self;
564             }
565              
566             sub Signals::XSIG::TieScalar::FETCH {
567 4444     4444   5227 my $self = shift;
568 4444         5863 my $key = my $key2 = $self->{key};
569 4444         6723 Signals::XSIG::_resolve_signal($key);
570 4444 50 33     9619 if ($key ne $key2 && !$self->{copied}) {
    50          
571 0         0 $self->{val} = (tied $Signals::XSIG::_XSIG{$key})->FETCH;
572 0         0 $self->{copied} = $key;
573 0         0 push @{(tied $Signals::XSIG::_XSIG{$key})->{aliases}}, $key2;
  0         0  
574             } elsif ($self->{copied}) {
575 0         0 $self->{val} = $Signals::XSIG::_XSIG{ $self->{copied} };
576             }
577 4444         11667 return $self->{val};
578             }
579              
580             # $XSIG{key} = [ LIST ] ==> store LIST, tie LIST as TieArray
581             # $XSIG{key} = EXPR ==> treat as $SIG{key}=EXPR,$XSIG{key}[0]=EXPR
582             sub Signals::XSIG::TieScalar::STORE {
583 29     29   43 my ($self, $value) = @_;
584 29         39 my $old = $self->{val};
585              
586 29 50       59 if (ref $value ne 'ARRAY') {
587 0         0 $value = [ $value ];
588             }
589              
590 29         36 my $key = $self->{key};
591 29         45 $self->{val} = [];
592 29         36 tie @{$self->{val}}, $TIEARRAY_CLASS, $self->{key}, @$value;
  29         94  
593 29         40 (tied @{$self->{val}})->_refresh_SIG;
  29         72  
594 29         64 return $old;
595             }
596              
597             ##################################################################
598             #
599             # Signals::XSIG::TieXSIG
600             #
601             # Only for tie-ing %XSIG.
602             # adds behavior to %XSIG hash so we can make assignments to
603             # $XSIG{sig} so that @{$XSIG{$sig}} is always a
604             # Signals::XSIG::TieArray
605             #
606              
607             sub Signals::XSIG::TieXSIG::TIEHASH {
608 12     12   39 return $XSIGTIE;
609             }
610              
611             sub Signals::XSIG::TieXSIG::FETCH {
612 267     267   10630 my ($self,$key) = @_;
613 267         516 _resolve_signal($key,1);
614 267         565 return $_XSIG{$key};
615             }
616              
617             sub Signals::XSIG::TieXSIG::STORE {
618 27     27   3312 my ($self, $key, $value) = @_;
619 27         60 _resolve_signal($key,1);
620 27         57 my $old = $_XSIG{$key};
621             # (tied $_XSIG{$key})->STORE($key,$value); #
622 27         54 $_XSIG{$key} = $value;
623 27         109 return $old;
624             }
625              
626             sub Signals::XSIG::TieXSIG::DELETE {
627 0     0   0 my ($self, $key) = @_;
628 0         0 _resolve_signal($key,1);
629 0         0 my $old = $_XSIG{$key};
630 0         0 $XSIG{$key} = [];
631 0         0 return $old;
632             }
633              
634             sub Signals::XSIG::TieXSIG::CLEAR {
635 2     2   169 my ($self) = @_;
636              
637 2         3 my @aliases = ();
638 2         25 for my $xsig (keys %_XSIG) {
639 144         156 my $osig = $xsig;
640 144 100       170 if (_resolve_signal($xsig, 1)) {
641 142 100       179 if ($osig ne $xsig) {
642 8         16 push @aliases, [$xsig, $osig];
643             } else {
644 134         249 $XSIG{$xsig} = [];
645             }
646             } else {
647 2         5 delete $_XSIG{$xsig};
648             }
649             }
650 2         10 foreach my $pair (@aliases) {
651 8         15 my ($xsig, $alias) = @$pair;
652 8         22 $_XSIG{$alias} = $_XSIG{$xsig};
653             }
654 2         9 return;
655             }
656              
657             sub Signals::XSIG::TieXSIG::EXISTS {
658 3     3   12 my ($self,$key) = @_;
659 3         6 _resolve_signal($key,1);
660 3         11 return exists $_XSIG{$key};
661             }
662              
663             sub Signals::XSIG::TieXSIG::FIRSTKEY {
664 0     0     my ($self) = @_;
665 0           my $a = keys %_XSIG;
666 0           return each %_XSIG;
667             }
668              
669             sub Signals::XSIG::TieXSIG::NEXTKEY {
670 0     0     my ($self, $lastkey) = @_;
671 0           return each %_XSIG
672             }
673              
674             1;
675              
676             __END__