File Coverage

blib/lib/Signals/XSIG.pm
Criterion Covered Total %
statement 345 382 90.3
branch 107 142 75.3
condition 47 65 72.3
subroutine 59 68 86.7
pod 0 3 0.0
total 558 660 84.5


line stmt bran cond sub pod time code
1             package Signals::XSIG;
2              
3             ## no critic (RequireLocalizedPunctuationVars, ProhibitAutomaticExport)
4              
5 12     12   21501 use Signals::XSIG::Default;
  12         32  
  12         64  
6 12     12   76 use Carp;
  12         26  
  12         588  
7 12     12   64 use Config;
  12         19  
  12         324  
8 12     12   60 use Exporter;
  12         27  
  12         290  
9 12     12   56 use POSIX ();
  12         20  
  12         207  
10 12     12   5159 use Symbol qw(qualify);
  12         7797  
  12         620  
11 12     12   5121 use Time::HiRes 'time';
  12         12646  
  12         50  
12 12     12   1857 use warnings;
  12         25  
  12         334  
13 12     12   59 use strict;
  12         21  
  12         2052  
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.15_04';
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     12 0 74 sub XLOG{no warnings"uninitialized";push @XLOG,($XN++)." @_"}
  12     1134   30  
  12         1550  
  1134         3374  
37 0     0 0 0 sub XLOG_DUMP{join"\n",@XLOG}
38             ###
39              
40              
41             BEGIN {
42             # how to detect global destruction. Idea from Devel::GlobalDestruction 0.13
43 12 50   12   71 if (defined ${^GLOBAL_PHASE}) {
44 12 50   325   892 eval 'sub __inGD() {${^GLOBAL_PHASE} eq "DESTRUCT" && __END()}; 1';
  325         2307  
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   44 return if $_INITIALIZED;
55 12         21 $_REFRESH = 0;
56 12 50       464 if ($Config{PERL_VERSION} <= 6) {
57 0         0 require Signals::XSIG::TieArray56;
58 0         0 $TIEARRAY_CLASS = 'Signals::XSIG::TieArray56';
59             }
60              
61 12         46 my @z = ();
62 12         190 my @num = split ' ', $Config{sig_num};
63 12         246 my @name = split ' ', $Config{sig_name};
64 12         59 for (my $i=0; $i<@name; $i++) {
65 828 100       1829 if (defined $z[$num[$i]]) {
66 48         120 $alias{$name[$i]} = $z[$num[$i]];
67 48         126 $alias{$z[$num[$i]]} = $name[$i];
68 48         126 $alias{"pk:$z[$num[$i]]"} = 1;
69             }
70 828         2112 $z[$num[$i]] = $name[$i];
71             }
72              
73 12         57 foreach my $sig (@name, '__WARN__', '__DIE__') {
74 852         2340 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         47 tie %SIG, 'Signals::XSIG::TieSIG';
81 12         38 $_REFRESH = 1;
82 12         49 foreach my $sig (@name, '__WARN__', '__DIE__') {
83 852 100       1850 next if $sig eq 'ZERO';
84 840 50       1275 unless (eval { (tied @{$_XSIG{$sig}})->_refresh_SIG; 1 }) {
  840         1161  
  840         1798  
  840         2135  
85 0         0 Carp::confess "Error initializing \@{\$XSIG{$sig}}!: $@\n";
86             }
87             }
88 12         54 tie %XSIG, 'Signals::XSIG::TieXSIG';
89              
90 12         246 my @signo = split ' ', $Config{sig_num};
91 12         195 my @signame = split ' ', $Config{sig_name};
92 12         86 for (my $i=0; $i<@signo; $i++) {
93 828         1274 my $signo = $signo[$i];
94 828         1124 my $signame = $signame[$i];
95 828   66     3453 $SIGTABLE{$signo} ||= $signame;
96 828         2957 $SIGTABLE{'SIG' . $signame} = $SIGTABLE{$signame} = $SIGTABLE{$signo};
97             }
98 12         33 $SIGTABLE{'__WARN__'} = '__WARN__';
99 12         27 $SIGTABLE{'__DIE__'} = '__DIE__';
100 12         213 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   27045441 END { &__END; }
111              
112             sub __END {
113 12     12   91 no warnings 'redefine';
  12         35  
  12         2756  
114 12     12   278 *__inGD = sub () { 1 };
115             }
116              
117             sub __shadow_signal_handler {
118 25     25   1152 my ($signal, @args) = @_;
119              
120             # %XSIG might be partially or completely untied during global destruction
121 25 50       586 return if __inGD();
122 25         47 my $seen_default = 0;
123              
124 25         49 my $h = tied @{$XSIG{$signal}};
  25         81  
125 25         73 my @handlers = $h->handlers;
126 25         57 my $start = $h->{start} - 1;
127 25         34 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         60 local @Signals::XSIG::HANDLER_SEQUENCE = ();
133 25         63 while (@handlers) {
134 186         280 my $subhandler = shift @handlers;
135 186         245 $start++;
136 186 100       395 next if !defined($subhandler);
137 155 100       338 next if $subhandler eq '';
138 149 100       287 if ($start != 0) {
139 125         169 $ignore_main_default = 1;
140             }
141 149 100       344 next if $subhandler eq 'IGNORE';
142 134 100       251 if ($subhandler eq 'DEFAULT') {
143 5 50       12 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       14 next if $seen_default++;
152 4         18 Signals::XSIG::Default::perform_default_behavior($signal, @args);
153 4         12 push @Signals::XSIG::HANDLER_SEQUENCE, 'DEFAULT';
154             } else {
155 129 100       270 next if !defined &$subhandler;
156 12     12   77 no strict 'refs'; ## no critic (NoStrict)
  12         24  
  12         7769  
157 123 50       224 if ($signal =~ /__\w+__/) {
158 0         0 $subhandler->(@args);
159             } else {
160 123         274 $subhandler->($signal, @args);
161             }
162 123         477 push @Signals::XSIG::HANDLER_SEQUENCE, $subhandler;
163             }
164             }
165 25         123 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 16251     16251   26546 my ($sig, $DISABLE_WARNINGS) = @_;
175 16251   66     58905 $DISABLE_WARNINGS ||= $_DISABLE_WARNINGS;
176 16251         28578 $sig = $SIGTABLE{uc $sig};
177 16251 100       32497 if (defined $sig) {
178 15373         21972 $_[0] = $sig; ## no critic (Unpacking)
179 15373         26633 return 1;
180             }
181 878 100       1830 return 1 if !$_INITIALIZED;
182              
183             # signal could not be resolved -- issue warning and return false
184 38 100       94 unless ($DISABLE_WARNINGS) {
185 10 50 33     655 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         74 return;
192             }
193              
194             # execute a block of code while %SIG is temporarily untied.
195              
196             sub untied (&) { ## no critic (SubroutinePrototypes)
197 6263     6263 0 9966 my $BLOCK = shift;
198              
199 6263         13157 untie %SIG;
200 6263 50       14394 my @r = wantarray ? $BLOCK->() : scalar $BLOCK->();
201 6263         16067 tie %SIG, 'Signals::XSIG::TieSIG';
202              
203 6263 50       18193 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 4550     4550   6661 my $handler = shift;
213              
214 4550 100 100     12905 if (!defined($handler)
      100        
      100        
215             || $handler eq ''
216             || $handler eq 'IGNORE'
217             || $handler eq 'DEFAULT') {
218 4323         7734 return $handler;
219             }
220              
221 227 100       684 if (substr($handler,0,1) eq '*') {
222 18         36 my $n = 0;
223 18         41 my $package = caller;
224 18   66     150 while (defined($package) && $package =~ /^Signals::XSIG/) {
225 35         162 $package = caller(++$n);
226             }
227              
228 18   50     92 $handler = qualify($handler, $package || 'main');
229             } else {
230 209         613 $handler = qualify($handler, 'main');
231             }
232 227         1880 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 6275 100   6275   13646 $XDEBUG && XLOG("TIE caller=",caller);
245 6275         11764 return $SIGTIE;
246             }
247              
248             sub Signals::XSIG::TieSIG::FETCH {
249 2134     2134   79421 my ($self,$key) = @_;
250              
251             # track function calls to diagnose test failures
252 2134 100 100     5666 $XDEBUG && $key ne '__DIE__'
253             && XLOG("FETCH key=$key caller=",caller);
254 2134 100       4299 if (_resolve_signal($key)) {
255 2127 100 100     5218 $XDEBUG && $key ne '__DIE__' && XLOG(" result(1)=",$_XSIG{$key}[0]);
256 2127         4921 return $_XSIG{$key}[0];
257             } else {
258 7     7   27 my $r = untied { $SIG{$key} };
  7         19  
259 7 50 33     27 $XDEBUG && $key ne '__DIE__' && XLOG(" result(2)=$r");
260 7         49 return $r;
261             }
262             }
263              
264             sub Signals::XSIG::TieSIG::STORE {
265 3399     3399   37834 my ($self,$key,$value) = @_;
266 3399 100 100     8385 $XDEBUG && $key ne '__DIE__'
267             && XLOG("STORE($key,$value) caller=",caller);
268 3399 100       6293 if (_resolve_signal($key)) {
269 3397         7102 my $old = $_XSIG{$key}[0];
270 3397         8076 $_XSIG{$key}[0] = $value;
271 3397         18853 return $old;
272             } else {
273 2         5 my $old;
274 2 50       6 $XDEBUG && XLOG(" key $key not resolved");
275             untied {
276 12     12   82 no warnings 'signal'; ## no critic (NoWarnings)
  12         27  
  12         11330  
277 2     2   4 $old = $SIG{$key};
278 2         11 $SIG{$key} = $value;
279 2         10 };
280 2         9 return $old;
281             }
282             }
283              
284             sub Signals::XSIG::TieSIG::DELETE {
285 4     4   18 my ($self,$key) = @_;
286 4 50 33     20 $XDEBUG && $key ne '__DIE__'
287             && XLOG("DELETE key=$key caller=",caller);
288 4 100       12 if (_resolve_signal($key)) {
289 3         8 my $old = $_XSIG{$key}[0];
290 3 50       12 $XDEBUG && XLOG(" DELETE result(1)=$old");
291 3         7 $_XSIG{$key}[0] = undef;
292 3         13 return $old;
293             } else {
294 1         5 my $old = $self->FETCH($key);
295 1 50       5 $XDEBUG && XLOG(" DELETE result(2)=$old");
296 1     1   4 untied { $SIG{$key} = undef; delete $SIG{$key} };
  1         91  
  1         10  
297 1         6 return $old;
298             }
299             }
300              
301             sub Signals::XSIG::TieSIG::CLEAR {
302 3     3   643 my ($self) = @_;
303 3 100       18 $XDEBUG && do {
304 2         10 XLOG("CLEAR caller=",caller);
305 2         6 XLOG(" CLEAR init USR1=",@{$_XSIG{USR1}});
  2         6  
306 2         5 XLOG(" CLEAR init USR2=",@{$_XSIG{USR2}});
  2         5  
307             };
308              
309             # this used to say
310             # $_XSIG{$_}[0] = undef for keys %_XSIG
311             # but on some platforms, for a reason I don't yet understand,
312             # the signal handler for the first value in the for loop
313             # would not get cleared properly. For another reason I don't
314             # yet understand, this is apparently not an issue for the
315             # __WARN__ and __DIE__ handlers, so we'll manipulate the signal
316             # list to make sure those handlers go first.
317            
318 3         114 my @sigs = reverse sort keys %_XSIG;
319 3 100       30 $XDEBUG && XLOG(" \@sigs = qw(@sigs);");
320 3         13 $_XSIG{$_}[0] = undef for @sigs;
321              
322 3 100       13 $XDEBUG && do {
323 2         4 XLOG(" CLEAR final USR1=",@{$_XSIG{USR1}});
  2         6  
324 2         5 XLOG(" CLEAR final USR2=",@{$_XSIG{USR2}});
  2         5  
325             };
326 3         23 return;
327             }
328              
329             sub Signals::XSIG::TieSIG::EXISTS {
330 1697     1697   175386215 my ($self,$key) = @_;
331 1697 50 66     4759 $XDEBUG && $key ne '__DIE__'
332             && XLOG("EXISTS key=$key caller=",caller);
333 1697     1697   5648 return untied { exists $SIG{$key} };
  1697         4583  
334             }
335              
336             sub Signals::XSIG::TieSIG::FIRSTKEY {
337 2     2   138 my ($self) = @_;
338 2 50       9 $XDEBUG && XLOG("FIRSTKEY caller=",caller);
339 2         8 my $a = keys %_XSIG;
340 2 50       12 $XDEBUG && XLOG(" FIRSTKEY result=$a");
341 2         13 return each %_XSIG;
342             }
343              
344             sub Signals::XSIG::TieSIG::NEXTKEY {
345 142     142   216 my ($self, $lastkey) = @_;
346 142 50       255 $XDEBUG && XLOG("NEXTKEY lastkey=$lastkey caller=",caller);
347 142         390 return each %_XSIG;
348             }
349              
350             sub Signals::XSIG::TieSIG::UNTIE {
351 6260 100 66 6260   19940 $XDEBUG && !__inGD() && XLOG("UNTIE caller=",caller);
352 6260         10945 return;
353             }
354              
355             ############################################################
356             #
357             # Signals::XSIG::TieArray
358             #
359             # Applied to @{$XSIG{signal}}.
360             # On update, refreshes the handler for the signal.
361             #
362              
363             sub Signals::XSIG::TieArray::TIEARRAY {
364 833     833   1954 my ($class, @list) = @_;
365 833         1541 my $obj = bless {}, 'Signals::XSIG::TieArray';
366 833         1711 $obj->{key} = shift @list;
367 833         1368 $obj->{start} = 0; # {start} refers to slot for first element of {handlers}
368 833         1431 $obj->{handlers} = [ map { _qualify_handler($_) } @list ];
  83         159  
369 833         1780 return $obj;
370             }
371              
372             # Wow. Those Perl guys thought of everything.
373             $Signals::XSIG::TieArray::NEGATIVE_INDICES = 1;
374              
375             sub Signals::XSIG::TieArray::FETCH {
376 5691     5691   10096 my ($self, $index) = @_;
377 5691         9219 $index -= $self->{start};
378 5691 100       11801 return if $index < 0;
379 5689         17157 return $self->{handlers}[$index];
380             }
381              
382             sub Signals::XSIG::TieArray::STORE {
383 4467     4467   8382 my ($self, $index, $handler) = @_;
384 4467         6990 $index -= $self->{start};
385              
386 4467         10006 while ($index < 0) {
387 10         16 unshift @{$self->{handlers}}, undef;
  10         16  
388 10         13 $index++;
389 10         19 $self->{start}--;
390             }
391              
392 4467         7363 my $old = $self->{handlers}[$index];
393              
394 4467         8183 $handler = _qualify_handler($handler);
395 4467         7691 $self->{handlers}[$index] = $handler;
396 4467 100       9719 $XDEBUG && XLOG("TA::STORE key=$self->{key} index=$index val=",$handler," caller=",caller);
397 4467         10253 $self->_refresh_SIG();
398 4467         9299 return $old;
399             }
400              
401             sub Signals::XSIG::TieArray::_refresh_SIG {
402 5359     5359   7660 my $self = shift;
403 5359 100       11288 return if $_REFRESH == 0;
404              
405 4555         7302 my $sig = $self->{key};
406 4555         7483 my @index_list = ();
407 4555         6331 my @handlers = @{$self->{handlers}};
  4555         8834  
408 4555         7942 my ($seen_default, $seen_ignore) = (0,0);
409 4555         10825 for (my $i=0; $i<@handlers; $i++) {
410 5484 100       16245 next if !defined $handlers[$i];
411 469 100 100     1300 next if $handlers[$i] eq 'DEFAULT' && $seen_default++;
412 468 100 100     1231 next if $handlers[$i] eq 'IGNORE' && $seen_ignore++;
413 465         1225 push @index_list, $i + $self->{start};
414             }
415              
416 4555         6743 my $handler_to_install;
417 4555 100 66     9124 if (@index_list == 0) {
    100 66        
418 4315         6484 $handler_to_install = undef;
419             }
420              
421             # XXX - if there is a single handler, and that handler is 'DEFAULT',
422             # do we want to install the shadow signal handler anyway?
423             # The caller may have overridden the DEFAULT behavior of the signal,
424             # so yeah, I think we do.
425              
426             elsif (@index_list == 1 &&
427             ($seen_default == 0 || ref($DEFAULT_BEHAVIOR{$sig}) eq '')) {
428             #!$seen_default) {
429 181         355 $handler_to_install = $handlers[$index_list[0]];
430             } else {
431 59 50       152 if ($sig eq '__WARN__') {
    50          
432 0         0 $handler_to_install = \&Signals::XSIG::__shadow__warn__handler;
433             } elsif ($sig eq '__DIE__') {
434 0         0 $handler_to_install = \&Signals::XSIG::__shadow__die__handler;
435             } else {
436 59         113 $handler_to_install = \&Signals::XSIG::__shadow_signal_handler;
437             }
438             }
439             untied {
440 12     12   88 no warnings qw(uninitialized signal); ## no critic (NoWarnings)
  12         25  
  12         13771  
441 4555 100   4555   9654 $XDEBUG && XLOG("_refresh_SIG key=$self->{key} handler=$handler_to_install");
442 4555         15413 $SIG{$sig} = $handler_to_install;
443 4555         19258 };
444 4555         13295 return;
445             }
446              
447             sub Signals::XSIG::TieArray::handlers {
448 25     25   37 my $self = shift;
449 25         32 return @{$self->{handlers}};
  25         88  
450             }
451              
452             sub Signals::XSIG::TieArray::FETCHSIZE {
453 21     21   57 my ($self) = @_;
454 21         34 return scalar @{$self->{handlers}};
  21         67  
455             }
456              
457       0     sub Signals::XSIG::TieArray::STORESIZE { }
458              
459       2     sub Signals::XSIG::TieArray::EXTEND { }
460              
461             sub Signals::XSIG::TieArray::EXISTS {
462 0     0   0 my ($self, $index) = @_;
463 0 0       0 return if $index < $self->{start};
464 0         0 return exists $self->{handlers}[$index - $self->{start}];
465             }
466              
467             sub Signals::XSIG::TieArray::DELETE {
468 4     4   13 my ($self, $index) = @_;
469 4         10 $index -= $self->{start};
470 4 50       16 return if $index < 0;
471 4         11 my $old = $self->{handlers}[$index];
472 4         9 $self->{handlers}[$index] = undef;
473 4         13 $self->_refresh_SIG;
474 4         12 return $old;
475             }
476              
477             sub Signals::XSIG::TieArray::CLEAR {
478 2     2   7 my ($self) = @_;
479 2         6 $self->{handlers} = [];
480 2         6 $self->{start} = 0;
481 2         8 $self->_refresh_SIG;
482 2         8 return;
483             }
484              
485             sub Signals::XSIG::TieArray::UNSHIFT {
486 4     4   16 my ($self, @list) = @_;
487 4         7 unshift @{$self->{handlers}}, @list;
  4         13  
488 4         10 $self->{start} -= @list;
489 4         12 $self->_refresh_SIG;
490 4         12 return $self->FETCHSIZE;
491             }
492              
493             sub Signals::XSIG::TieArray::POP {
494 5     5   11 my ($self) = @_;
495 5 100       9 if (@{$self->{handlers}} + $self->{start} <= 1) {
  5         19  
496 1         3 return;
497             }
498 4         9 my $val = pop @{$self->{handlers}};
  4         15  
499 4         12 $self->_refresh_SIG;
500 4         11 return $val;
501             }
502              
503             sub Signals::XSIG::TieArray::SHIFT {
504 4     4   10 my $self = shift;
505 4 100       14 if ($self->{start} >= 0) {
506 2         5 return;
507             }
508 2         4 my $val = shift @{$self->{handlers}};
  2         5  
509 2         5 $self->{start}++;
510 2         7 $self->_refresh_SIG;
511 2         7 return $val;
512             }
513              
514             sub Signals::XSIG::TieArray::PUSH {
515 7     7   30 my ($self, @list) = @_;
516 7 100       16 if (@{$self->{handlers}} + $self->{start} <= 0) {
  7         29  
517 2         8 unshift @list, undef;
518             }
519 7         16 my $val = push @{$self->{handlers}}, @list;
  7         21  
520 7         24 $self->_refresh_SIG;
521 7         22 return $val;
522             }
523              
524       0     sub Signals::XSIG::TieArray::SPLICE { }
525              
526             ##################################################################
527             #
528             # Signals::XSIG::TieScalar
529             #
530             # For tie-ing $XSIG{signal}.
531             # Handles expressions like $XSIG{signal} = [ ... ]
532             # and $XSIG{signal} = handler
533             # Main purpose is to assert that $XSIG{$sig} is always set
534             # to a reference to a Signals::XSIG::TieArray object.
535             #
536              
537             sub Signals::XSIG::TieScalar::TIESCALAR {
538 852     852   1873 my ($class, @list) = @_;
539 852         1414 my $key = $list[0];
540 852 100 100     2461 if (defined($alias{$key}) && !defined($alias{"pk:$key"})) {
541 48         187 return $TIEDSCALARS{$key} = $TIEDSCALARS{$alias{$key}};
542             }
543              
544 804         1995 my $self = bless { key => $key }, 'Signals::XSIG::TieScalar';
545 804         1611 $self->{val} = [];
546 804         1128 tie @{$self->{val}}, $TIEARRAY_CLASS, $key;
  804         1840  
547 804         3018 $self->{val}[0] = $SIG{$key};
548 804         1740 $TIEDSCALARS{$key} = $self;
549 804         1977 return $self;
550             }
551              
552             sub Signals::XSIG::TieScalar::FETCH {
553 10273     10273   15489 my $self = shift;
554 10273         16993 my $key = my $key2 = $self->{key};
555 10273         21011 Signals::XSIG::_resolve_signal($key);
556 10273 50 33     32492 if ($key ne $key2 && !$self->{copied}) {
    50          
557 0         0 $self->{val} = (tied $Signals::XSIG::_XSIG{$key})->FETCH;
558 0         0 $self->{copied} = $key;
559 0         0 push @{(tied $Signals::XSIG::_XSIG{$key})->{aliases}}, $key2;
  0         0  
560             } elsif ($self->{copied}) {
561 0         0 $self->{val} = $Signals::XSIG::_XSIG{ $self->{copied} };
562             }
563 10273         30123 return $self->{val};
564             }
565              
566             # $XSIG{key} = [ LIST ] ==> store LIST, tie LIST as TieArray
567             # $XSIG{key} = EXPR ==> treat as $SIG{key}=EXPR,$XSIG{key}[0]=EXPR
568             sub Signals::XSIG::TieScalar::STORE {
569 29     29   59 my ($self, $value) = @_;
570 29         56 my $old = $self->{val};
571              
572 29 50       77 if (ref $value ne 'ARRAY') {
573 0         0 $value = [ $value ];
574             }
575              
576 29         49 my $key = $self->{key};
577 29         53 $self->{val} = [];
578 29         55 tie @{$self->{val}}, $TIEARRAY_CLASS, $self->{key}, @$value;
  29         115  
579 29         54 (tied @{$self->{val}})->_refresh_SIG;
  29         84  
580 29         68 return $old;
581             }
582              
583             ##################################################################
584             #
585             # Signals::XSIG::TieXSIG
586             #
587             # Only for tie-ing %XSIG.
588             # adds behavior to %XSIG hash so we can make assignments to
589             # $XSIG{sig} so that @{$XSIG{$sig}} is always a
590             # Signals::XSIG::TieArray
591             #
592              
593             sub Signals::XSIG::TieXSIG::TIEHASH {
594 12     12   38 return $XSIGTIE;
595             }
596              
597             sub Signals::XSIG::TieXSIG::FETCH {
598 267     267   9546 my ($self,$key) = @_;
599 267         644 _resolve_signal($key,1);
600 267         670 return $_XSIG{$key};
601             }
602              
603             sub Signals::XSIG::TieXSIG::STORE {
604 27     27   1876 my ($self, $key, $value) = @_;
605 27         73 _resolve_signal($key,1);
606 27         67 my $old = $_XSIG{$key};
607             # (tied $_XSIG{$key})->STORE($key,$value); #
608 27         74 $_XSIG{$key} = $value;
609 27         121 return $old;
610             }
611              
612             sub Signals::XSIG::TieXSIG::DELETE {
613 0     0   0 my ($self, $key) = @_;
614 0         0 _resolve_signal($key,1);
615 0         0 my $old = $_XSIG{$key};
616 0         0 $XSIG{$key} = [];
617 0         0 return $old;
618             }
619              
620             sub Signals::XSIG::TieXSIG::CLEAR {
621 2     2   204 my ($self) = @_;
622              
623 2         5 my @aliases = ();
624 2         52 for my $xsig (keys %_XSIG) {
625 144         194 my $osig = $xsig;
626 144 100       223 if (_resolve_signal($xsig, 1)) {
627 142 100       229 if ($osig ne $xsig) {
628 8         20 push @aliases, [$xsig, $osig];
629             } else {
630 134         287 $XSIG{$xsig} = [];
631             }
632             } else {
633 2         5 delete $_XSIG{$xsig};
634             }
635             }
636 2         10 foreach my $pair (@aliases) {
637 8         16 my ($xsig, $alias) = @$pair;
638 8         34 $_XSIG{$alias} = $_XSIG{$xsig};
639             }
640 2         11 return;
641             }
642              
643             sub Signals::XSIG::TieXSIG::EXISTS {
644 3     3   14 my ($self,$key) = @_;
645 3         8 _resolve_signal($key,1);
646 3         10 return exists $_XSIG{$key};
647             }
648              
649             sub Signals::XSIG::TieXSIG::FIRSTKEY {
650 0     0     my ($self) = @_;
651 0           my $a = keys %_XSIG;
652 0           return each %_XSIG;
653             }
654              
655             sub Signals::XSIG::TieXSIG::NEXTKEY {
656 0     0     my ($self, $lastkey) = @_;
657 0           return each %_XSIG
658             }
659              
660             1;
661              
662             __END__