File Coverage

blib/lib/MCE/Signal.pm
Criterion Covered Total %
statement 89 173 51.4
branch 43 146 29.4
condition 27 122 22.1
subroutine 17 25 68.0
pod 3 3 100.0
total 179 469 38.1


line stmt bran cond sub pod time code
1             ###############################################################################
2             ## ----------------------------------------------------------------------------
3             ## Temporary directory creation/cleanup and signal handling.
4             ##
5             ###############################################################################
6              
7             package MCE::Signal;
8              
9 103     103   467625 use strict;
  103         181  
  103         4455  
10 103     103   528 use warnings;
  103         174  
  103         6818  
11              
12 103     103   548 no warnings qw( threads recursion uninitialized once );
  103         184  
  103         12924  
13              
14             our $VERSION = '1.902';
15              
16             ## no critic (BuiltinFunctions::ProhibitStringyEval)
17              
18             our ($display_die_with_localtime, $display_warn_with_localtime);
19             our ($main_proc_id, $prog_name, $tmp_dir);
20              
21             tie $tmp_dir, 'MCE::Signal::_tmpdir';
22              
23 103     103   908 use Carp ();
  103         188  
  103         14561  
24              
25             BEGIN {
26 103     103   922 $main_proc_id = $$;
27 103         295 $prog_name = $0;
28 103         773 $prog_name =~ s{^.*[\\/]}{}g;
29 103 50 33     1584 $prog_name = 'perl' if ($prog_name eq '-e' || $prog_name eq '-');
30              
31 103         3562 return;
32             }
33              
34 103     103   687 use base qw( Exporter );
  103         231  
  103         14146  
35 103     103   963 use Time::HiRes ();
  103         788  
  103         141811  
36              
37             our @EXPORT_OK = qw( $tmp_dir sys_cmd stop_and_exit );
38             our %EXPORT_TAGS = (
39             all => \@EXPORT_OK,
40             tmp_dir => [ qw( $tmp_dir ) ]
41             );
42              
43             END {
44 103 50 66 103   14015 MCE::Signal->stop_and_exit($?)
      66        
45             if ($$ == $main_proc_id && !$MCE::Signal::KILLED && !$MCE::Signal::STOPPED);
46             }
47              
48             ###############################################################################
49             ## ----------------------------------------------------------------------------
50             ## Process import, export, & module arguments.
51             ##
52             ###############################################################################
53              
54 0     0   0 sub _croak { $\ = undef; goto &Carp::croak }
  0         0  
55 0     0   0 sub _usage { _croak "MCE::Signal error: ($_[0]) is not a valid option" }
56 1     1   5 sub _flag { 1 }
57              
58             my $_is_MSWin32 = ($^O eq 'MSWin32') ? 1 : 0;
59             my $_keep_tmp_dir = 0;
60             my $_use_dev_shm = 0;
61             my $_no_kill9 = 0;
62             my $_imported;
63              
64             sub import {
65 4     4   37 my $_class = shift;
66 4 50       16 return if $_imported++;
67              
68 4         12 my ($_no_setpgrp, $_no_sigmsg, $_setpgrp, @_export_args) = (0, 0, 0);
69              
70 4         13 while (my $_arg = shift) {
71 7 50 0     16 $_setpgrp = _flag() and next if ($_arg eq '-setpgrp');
72 7 50 0     12 $_keep_tmp_dir = _flag() and next if ($_arg eq '-keep_tmp_dir');
73 7 100 50     21 $_use_dev_shm = _flag() and next if ($_arg eq '-use_dev_shm');
74 6 50 0     12 $_no_kill9 = _flag() and next if ($_arg eq '-no_kill9');
75              
76             # deprecated options for backwards compatibility
77 6 50 0     11 $_no_setpgrp = _flag() and next if ($_arg eq '-no_setpgrp');
78 6 50 0     15 $_no_sigmsg = _flag() and next if ($_arg eq '-no_sigmsg');
79              
80 6 50       22 _usage($_arg) if ($_arg =~ /^-/);
81              
82 6         16 push @_export_args, $_arg;
83             }
84              
85 4         8 local $Exporter::ExportLevel = 1;
86 4         371 Exporter::import($_class, @_export_args);
87              
88             ## Sets the current process group for the current process.
89 4 50 33     18 setpgrp(0,0) if ($_setpgrp == 1 && !$_is_MSWin32);
90              
91             ## Make tmp_dir if caller requested it.
92 4 100 100     38 _make_tmpdir() if ($_use_dev_shm || grep /tmp_dir/, @_export_args);
93              
94 4         97 return;
95             }
96              
97             ###############################################################################
98             ## ----------------------------------------------------------------------------
99             ## Configure signal handling.
100             ##
101             ###############################################################################
102              
103             ## Set traps to catch signals.
104             if ( !$_is_MSWin32 ) {
105             $SIG{ABRT} = \&stop_and_exit; # UNIX SIG 6
106             $SIG{HUP} = \&stop_and_exit; # UNIX SIG 1
107             $SIG{INT} = \&stop_and_exit; # UNIX SIG 2
108             $SIG{PIPE} = \&stop_and_exit; # UNIX SIG 13
109             $SIG{QUIT} = \&stop_and_exit; # UNIX SIG 3
110             $SIG{TERM} = \&stop_and_exit; # UNIX SIG 15
111              
112             ## MCE handles the reaping of its children.
113             $SIG{CHLD} = 'DEFAULT';
114             }
115              
116             my $_safe_clean = 0;
117              
118             sub _make_tmpdir {
119 34     34   83 my ($_count, $_tmp_base_dir) = (0);
120              
121 34 0 33     344 return $tmp_dir if (defined $tmp_dir && -d $tmp_dir && -w _);
      33        
122              
123 34 50 33     2162 if ($ENV{TEMP} && -d $ENV{TEMP} && -w _) {
    50 33        
      33        
      33        
      0        
124 0 0       0 if ($^O =~ /mswin|mingw|msys|cygwin/i) {
125 0         0 $_tmp_base_dir = $ENV{TEMP} . '/Perl-MCE';
126 0 0       0 mkdir $_tmp_base_dir unless -d $_tmp_base_dir;
127             } else {
128 0         0 $_tmp_base_dir = $ENV{TEMP};
129             }
130             }
131             elsif (! -w '/tmp' && -e $ENV{TMPDIR} && -d $ENV{TMPDIR} && -w _) {
132 0         0 $_tmp_base_dir = $ENV{TMPDIR};
133             }
134             else {
135 34 100 66     287 $_tmp_base_dir = ($_use_dev_shm && -d '/dev/shm' && -w _)
136             ? '/dev/shm' : '/tmp';
137             }
138              
139             _croak("Error: MCE::Signal: ($_tmp_base_dir) is not writeable")
140 34 50 33     529 if (! exists $ENV{'MOBASTARTUPDIR'} && ! -w $_tmp_base_dir);
141              
142             ## Remove tainted'ness from $tmp_dir.
143 34         729 ($tmp_dir) = "$_tmp_base_dir/$prog_name.$$.$_count" =~ /(.*)/;
144              
145 34         128 while ( !(mkdir $tmp_dir, 0770) ) {
146 0         0 ($tmp_dir) = ("$_tmp_base_dir/$prog_name.$$.".(++$_count)) =~ /(.*)/;
147             }
148              
149 34         164 $_safe_clean = 1;
150              
151 34         149 return $tmp_dir;
152             }
153              
154             sub _remove_tmpdir {
155 9 50 33 9   23 return if (!defined $tmp_dir || $tmp_dir eq '' || ! -d $tmp_dir);
      33        
156              
157 9 50       71 if ($_keep_tmp_dir == 1) {
    50          
158 0         0 print {*STDERR} "$prog_name: saved tmp_dir = $tmp_dir\n";
  0         0  
159             }
160             elsif ($_safe_clean) {
161 9 50 33     53 if ($ENV{'TEMP'} && $^O =~ /mswin|mingw|msys|cygwin/i) {
162             ## remove tainted'ness
163 0         0 my ($_dir) = $ENV{'TEMP'} =~ /(.*)/;
164 0 0       0 chdir $_dir if -d $_dir;
165             }
166 9         34 rmdir $tmp_dir;
167 9 50       70 if (-d $tmp_dir) {
168 0         0 local $@; local $SIG{__DIE__};
  0         0  
169 0         0 eval 'require File::Path; File::Path::rmtree($tmp_dir)';
170             }
171             }
172              
173 9         89 $tmp_dir = undef;
174             }
175              
176             ###############################################################################
177             ## ----------------------------------------------------------------------------
178             ## Stops execution, removes temp directory and exits cleanly.
179             ##
180             ## Provides safe reentrant logic for parent and child processes.
181             ## The $main_proc_id variable is defined above.
182             ##
183             ###############################################################################
184              
185             BEGIN {
186 103     103   432 $MCE::Signal::IPC = 0; # 1 = defer signal_handling until completed IPC
187 103         222588 $MCE::Signal::SIG = ''; # signal received during IPC in MCE::Shared 1.863
188             }
189              
190             sub defer {
191 0 0   0 1 0 $MCE::Signal::SIG = $_[0] if $_[0];
192 0         0 return;
193             }
194              
195             my %_sig_name_lkup = map { $_ => 1 } qw(
196             __DIE__ ABRT HUP INT PIPE QUIT TERM __WARN__
197             );
198              
199             my $_count = 0;
200              
201             my $_handler_count = $INC{'threads/shared.pm'}
202             ? threads::shared::share($_count)
203             : \$_count;
204              
205             sub stop_and_exit {
206 23 50 33 23 1 277 shift @_ if (defined $_[0] && $_[0] eq 'MCE::Signal');
207 23 50       98 return MCE::Signal::defer($_[0]) if $MCE::Signal::IPC;
208              
209 23   50     192 my ($_exit_status, $_is_sig, $_sig_name) = ($?, 0, $_[0] || 0);
210 23     0   385 $SIG{__DIE__} = $SIG{__WARN__} = sub {};
211              
212 23 50       151 if (exists $_sig_name_lkup{$_sig_name}) {
213 0         0 $_exit_status = $MCE::Signal::KILLED = $_is_sig = 1;
214 0 0       0 $_exit_status = 255, $_sig_name = 'TERM' if ($_sig_name eq '__DIE__');
215 0 0       0 $_exit_status = 0 if ($_sig_name eq 'PIPE');
216 0     0   0 $SIG{INT} = $SIG{$_sig_name} = sub {};
217             }
218             else {
219 23 50       293 $_exit_status = $_sig_name if ($_sig_name =~ /^\d+$/);
220 23         132 $MCE::Signal::STOPPED = 1;
221             }
222              
223             ## Main process.
224 23 50       160 if ($$ == $main_proc_id) {
    0          
225              
226 23 50       66 if (++${ $_handler_count } == 1) {
  23         135  
227             ## Kill process group if signaled.
228 23 50       99 if ($_is_sig == 1) {
229 0 0       0 ($_sig_name eq 'PIPE')
    0          
    0          
230             ? CORE::kill('PIPE', $_is_MSWin32 ? -$$ : -getpgrp)
231             : CORE::kill('INT' , $_is_MSWin32 ? -$$ : -getpgrp);
232              
233 0 0       0 if ($_sig_name eq 'PIPE') {
234 0         0 for my $_i (1..2) { Time::HiRes::sleep(0.015); }
  0         0  
235             } else {
236 0         0 for my $_i (1..3) { Time::HiRes::sleep(0.060); }
  0         0  
237             }
238             }
239              
240             ## Remove temp directory.
241 23 100       334 _remove_tmpdir() if defined($tmp_dir);
242              
243             ## Signal process group to die.
244 23 50       113 if ($_is_sig == 1) {
245 0 0 0     0 if ($_sig_name eq 'INT' && -t STDIN) { ## no critic
246 0         0 print {*STDERR} "\n";
  0         0  
247             }
248 0 0 0     0 if ($INC{'threads.pm'} && ($] lt '5.012000' || threads->tid())) {
      0        
249 0 0 0     0 ($_no_kill9 == 1 || $_sig_name eq 'PIPE')
    0          
250             ? CORE::kill('INT', $_is_MSWin32 ? -$$ : -getpgrp)
251             : CORE::kill('KILL', -$$);
252             }
253             else {
254 0 0       0 CORE::kill('INT', $_is_MSWin32 ? -$$ : -getpgrp);
255             }
256             }
257             }
258             }
259              
260             ## Child processes.
261             elsif ($_is_sig) {
262              
263             ## Windows support, from nested workers.
264 0 0       0 if ($_is_MSWin32) {
265 0 0       0 _remove_tmpdir() if defined($tmp_dir);
266 0         0 CORE::kill('KILL', $main_proc_id, -$$);
267             }
268              
269             ## Real child processes.
270             else {
271 0         0 CORE::kill($_sig_name, $main_proc_id, -$$);
272 0         0 CORE::kill('KILL', -$$, $$);
273             }
274             }
275              
276             ## Exit with status.
277 23         1016 CORE::exit($_exit_status);
278             }
279              
280             ###############################################################################
281             ## ----------------------------------------------------------------------------
282             ## Run command via the system(...) function.
283             ##
284             ## The system function in Perl ignores SIGINT and SIGQUIT. These 2 signals
285             ## are sent to the command being executed via system() but not back to
286             ## the underlying Perl script. The code below will ensure the Perl script
287             ## receives the same signal in order to raise an exception immediately
288             ## after the system call.
289             ##
290             ## Returns the actual exit status.
291             ##
292             ###############################################################################
293              
294             sub sys_cmd {
295 0 0 0 0 1 0 shift @_ if (defined $_[0] && $_[0] eq 'MCE::Signal');
296              
297 0 0       0 _croak('MCE::Signal::sys_cmd: no arguments were specified') if (@_ == 0);
298              
299 0         0 my $_status = system(@_);
300 0         0 my $_sig_no = $_status & 127;
301 0         0 my $_exit_status = $_status >> 8;
302              
303             ## Kill the process group if command caught SIGINT or SIGQUIT.
304              
305 0 0       0 CORE::kill('INT', $main_proc_id, $_is_MSWin32 ? -$$ : -getpgrp)
    0          
306             if $_sig_no == 2;
307              
308 0 0       0 CORE::kill('QUIT', $main_proc_id, $_is_MSWin32 ? -$$ : -getpgrp)
    0          
309             if $_sig_no == 3;
310              
311 0         0 return $_exit_status;
312             }
313              
314             ###############################################################################
315             ## ----------------------------------------------------------------------------
316             ## Signal handlers for __DIE__ & __WARN__ utilized by MCE.
317             ##
318             ###############################################################################
319              
320             sub _die_handler {
321 0 0 0 0   0 shift @_ if (defined $_[0] && $_[0] eq 'MCE::Signal');
322              
323 0 0 0     0 if (!defined $^S || $^S) {
324 0 0 0     0 if ( ($INC{'threads.pm'} && threads->tid() != 0) ||
      0        
325             $ENV{'PERL_IPERL_RUNNING'}
326             ) {
327             # thread env or running inside IPerl, check stack trace
328 0         0 my $_t = Carp::longmess(); $_t =~ s/\teval [^\n]+\n$//;
  0         0  
329 0 0 0     0 if ( $_t =~ /^(?:[^\n]+\n){1,7}\teval / ||
330             $_t =~ /\n\teval [^\n]+\n\t(?:eval|Try)/ )
331             {
332 0         0 CORE::die(@_);
333             }
334             }
335             else {
336             # normal env, trust $^S
337 0         0 CORE::die(@_);
338             }
339             }
340              
341 0         0 local $\ = undef;
342              
343             ## Set $MCE::Signal::display_die_with_localtime = 1;
344             ## when wanting the output to contain the localtime.
345              
346 0 0       0 if (defined $_[0]) {
347 0         0 my $mesg = $_[0]; $mesg =~ s/, <__ANONIO__> line \d+//;
  0         0  
348 0 0       0 if ($MCE::Signal::display_die_with_localtime) {
349 0         0 my $_time_stamp = localtime;
350 0         0 print {*STDERR} "## $_time_stamp: $prog_name: ERROR:\n", $mesg;
  0         0  
351             }
352             else {
353 0         0 print {*STDERR} $mesg;
  0         0  
354             }
355             }
356              
357 0         0 MCE::Signal::stop_and_exit('__DIE__');
358             }
359              
360             sub _warn_handler {
361 0 0 0 0   0 shift @_ if (defined $_[0] && $_[0] eq 'MCE::Signal');
362              
363             ## Ignore thread warnings during exiting.
364              
365             return if (
366 0 0 0     0 $_[0] =~ /^Finished with active (?:child|hobo) processes/ ||
      0        
      0        
      0        
367             $_[0] =~ /^A thread exited while \d+ threads were running/ ||
368             $_[0] =~ /^Attempt to free unreferenced scalar/ ||
369             $_[0] =~ /^Perl exited with active threads/ ||
370             $_[0] =~ /^Thread \d+ terminated abnormally/
371             );
372              
373 0         0 local $\ = undef;
374              
375             ## Set $MCE::Signal::display_warn_with_localtime = 1;
376             ## when wanting the output to contain the localtime.
377              
378 0 0       0 if (defined $_[0]) {
379 0         0 my $mesg = $_[0]; $mesg =~ s/, <__ANONIO__> line \d+//;
  0         0  
380 0 0       0 if ($MCE::Signal::display_warn_with_localtime) {
381 0         0 my $_time_stamp = localtime;
382 0         0 print {*STDERR} "## $_time_stamp: $prog_name: WARNING:\n", $mesg;
  0         0  
383             }
384             else {
385 0         0 print {*STDERR} $mesg;
  0         0  
386             }
387             }
388              
389 0         0 return;
390             }
391              
392             1;
393              
394             ###############################################################################
395             ## ----------------------------------------------------------------------------
396             ## TIE scalar package for making $MCE::Signal::tmp_dir on demand.
397             ##
398             ###############################################################################
399              
400             package MCE::Signal::_tmpdir;
401              
402             sub TIESCALAR {
403 103     103   249 my $_class = shift;
404 103 50       171 bless \do{ my $o = defined $_[0] ? shift : undef }, $_class;
  103         1089  
405             }
406              
407             sub STORE {
408 43     43   119 ${ $_[0] } = $_[1];
  43         125  
409              
410 43 100       222 $_safe_clean = 0 if ( length $_[1] < 9 );
411 43 50 33     207 $_safe_clean = 0 if ( $ENV{'TEMP'} && $ENV{'TEMP'} eq $_[1] );
412 43 50       236 $_safe_clean = 0 if ( $_[1] =~ m{[\\/](?:etc|bin|lib|sbin)} );
413 43 50       183 $_safe_clean = 0 if ( $_[1] =~ m{[\\/](?:temp|tmp)[\\/]?$}i );
414              
415 43         142 $_[1];
416             }
417              
418             sub FETCH {
419 852 100   852   2085 if (!defined ${ $_[0] }) {
  852         3650  
420 642         1722 my $_caller = caller();
421 642 50 66     2424 if ($_caller ne 'MCE' && $_caller ne 'MCE::Signal') {
422 0 0 0     0 if ($INC{'MCE.pm'} && MCE->wid() > 0) {
423 0         0 ${ $_[0] } = MCE->tmp_dir();
  0         0  
424             } else {
425 0         0 ${ $_[0] } = MCE::Signal::_make_tmpdir();
  0         0  
426             }
427             }
428             }
429 852         1313 ${ $_[0] };
  852         16419  
430             }
431              
432             1;
433              
434             __END__
435              
436             ###############################################################################
437             ## ----------------------------------------------------------------------------
438             ## Module usage.
439             ##
440             ###############################################################################
441              
442             =head1 NAME
443              
444             MCE::Signal - Temporary directory creation/cleanup and signal handling
445              
446             =head1 VERSION
447              
448             This document describes MCE::Signal version 1.902
449              
450             =head1 SYNOPSIS
451              
452             ## Creates tmp_dir under $ENV{TEMP} if defined, otherwise /tmp.
453              
454             use MCE::Signal;
455              
456             ## Attempts to create tmp_dir under /dev/shm if writable.
457              
458             use MCE::Signal qw( -use_dev_shm );
459              
460             ## Keeps tmp_dir after the script terminates.
461              
462             use MCE::Signal qw( -keep_tmp_dir );
463             use MCE::Signal qw( -use_dev_shm -keep_tmp_dir );
464              
465             ## MCE loads MCE::Signal by default when not present.
466             ## Therefore, load MCE::Signal first for options to take effect.
467              
468             use MCE::Signal qw( -keep_tmp_dir -use_dev_shm );
469             use MCE;
470              
471             =head1 DESCRIPTION
472              
473             This package configures $SIG{ ABRT, HUP, INT, PIPE, QUIT, and TERM } to
474             point to stop_and_exit and creates a temporary directory. The main process
475             and workers receiving said signals call stop_and_exit, which signals all
476             workers to terminate, removes the temporary directory unless -keep_tmp_dir
477             is specified, and terminates itself.
478              
479             The location of the temp directory resides under $ENV{TEMP} if defined,
480             otherwise /dev/shm if writeable and -use_dev_shm is specified, or /tmp.
481             On Windows, the temp directory is made under $ENV{TEMP}/Perl-MCE/.
482              
483             As of MCE 1.405, MCE::Signal no longer calls setpgrp by default. Pass the
484             -setpgrp option to MCE::Signal to call setpgrp.
485              
486             ## Running MCE through Daemon::Control requires setpgrp to be called
487             ## for MCE releases 1.511 and below.
488              
489             use MCE::Signal qw(-setpgrp); ## Not necessary for MCE 1.512 and above
490             use MCE;
491              
492             The following are available options and their meanings.
493              
494             -keep_tmp_dir - The temporary directory is not removed during exiting
495             A message is displayed with the location afterwards
496              
497             -use_dev_shm - Create the temporary directory under /dev/shm
498             -no_kill9 - Do not kill -9 after receiving a signal to terminate
499              
500             -setpgrp - Calls setpgrp to set the process group for the process
501             This option ensures all workers terminate when reading
502             STDIN for MCE releases 1.511 and below.
503              
504             cat big_input_file | ./mce_script.pl | head -10
505              
506             This works fine without the -setpgrp option:
507              
508             ./mce_script.pl < big_input_file | head -10
509              
510             Nothing is exported by default. Exportable are 1 variable and 2 subroutines.
511              
512             use MCE::Signal qw( $tmp_dir stop_and_exit sys_cmd );
513             use MCE::Signal qw( :all );
514              
515             $tmp_dir - Path to the temporary directory.
516             stop_and_exit - Described below
517             sys_cmd - Described below
518              
519             =head2 stop_and_exit ( [ $exit_status | $signal ] )
520              
521             Stops execution, removes temp directory, and exits the entire application.
522             Pass 'INT' to terminate a spawned or running MCE session.
523              
524             MCE::Signal::stop_and_exit(1);
525             MCE::Signal::stop_and_exit('INT');
526              
527             =head2 sys_cmd ( $command )
528              
529             The system function in Perl ignores SIGINT and SIGQUIT. These 2 signals are
530             sent to the command being executed via system() but not back to the underlying
531             Perl script. For this reason, sys_cmd was added to MCE::Signal.
532              
533             ## Execute command and return the actual exit status. The perl script
534             ## is also signaled if command caught SIGINT or SIGQUIT.
535              
536             use MCE::Signal qw(sys_cmd); ## Include before MCE
537             use MCE;
538              
539             my $exit_status = sys_cmd($command);
540              
541             =head1 DEFER SIGNAL
542              
543             =head2 defer ( $signal )
544              
545             Returns immediately inside a signal handler if signaled during IPC.
546             The signal is deferred momentarily and re-signaled automatically upon
547             completing IPC. Currently, all IPC related methods in C<MCE::Shared> and
548             one method C<send2> in C<MCE::Channel> set the flag C<$MCE::Signal::IPC>
549             before initiating IPC.
550              
551             Current API available since 1.863.
552              
553             sub sig_handler {
554             return MCE::Signal::defer($_[0]) if $MCE::Signal::IPC;
555             ...
556             }
557              
558             In a nutshell, C<defer> helps safeguard IPC from stalling between workers
559             and the shared manager-process. The following is a demonstration for Unix
560             platforms. Deferring the signal inside the C<WINCH> handler prevents the
561             app from eventually failing while resizing the window.
562              
563             use strict;
564             use warnings;
565              
566             use MCE::Hobo;
567             use MCE::Shared;
568             use Time::HiRes 'sleep';
569              
570             my $count = MCE::Shared->scalar(0);
571             my $winch = MCE::Shared->scalar(0);
572             my $done = MCE::Shared->scalar(0);
573              
574             $SIG{WINCH} = sub {
575             # defer signal if signaled during IPC
576             return MCE::Signal::defer($_[0]) if $MCE::Signal::IPC;
577              
578             # mask signal handler
579             local $SIG{$_[0]} = 'IGNORE';
580              
581             printf "inside winch handler %d\n", $winch->incr;
582             };
583              
584             $SIG{INT} = sub {
585             # defer signal if signaled during IPC
586             return MCE::Signal::defer($_[0]) if $MCE::Signal::IPC;
587              
588             # set flag for workers to leave loop
589             $done->set(1);
590             };
591              
592             sub task {
593             while ( ! $done->get ) {
594             $count->incr;
595             sleep 0.03;
596             };
597             }
598              
599             print "Resize the terminal window continuously.\n";
600             print "Press Ctrl-C to stop.\n";
601              
602             MCE::Hobo->create('task') for 1..8;
603             sleep 0.015 until $done->get;
604             MCE::Hobo->wait_all;
605              
606             printf "\ncount incremented %d times\n\n", $count->get;
607              
608             =head1 INDEX
609              
610             L<MCE|MCE>, L<MCE::Core>
611              
612             =head1 AUTHOR
613              
614             Mario E. Roy, S<E<lt>marioeroy AT gmail DOT comE<gt>>
615              
616             =cut
617