File Coverage

blib/lib/Sys/ForkAsync.pm
Criterion Covered Total %
statement 11 13 84.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 16 18 88.8


line stmt bran cond sub pod time code
1             package Sys::ForkAsync;
2             {
3             $Sys::ForkAsync::VERSION = '0.14';
4             }
5             BEGIN {
6 1     1   4799 $Sys::ForkAsync::AUTHORITY = 'cpan:TEX';
7             }
8             # ABSTRACT: Simple async one-time job
9              
10 1     1   32 use 5.010_000;
  1         4  
  1         43  
11 1     1   6 use mro 'c3';
  1         2  
  1         8  
12 1     1   37 use feature ':5.10';
  1         2  
  1         120  
13              
14 1     1   434 use Moose;
  0            
  0            
15             use namespace::autoclean;
16              
17             # use IO::Handle;
18             # use autodie;
19             # use MooseX::Params::Validate;
20              
21             # for fork()
22             use Errno qw(EAGAIN);
23             use POSIX qw(WNOHANG);
24              
25             has 'chdir' => (
26             'is' => 'rw',
27             'isa' => 'Str',
28             'default' => 0,
29             );
30              
31             has 'redirect_output' => (
32             'is' => 'rw',
33             'isa' => 'Bool',
34             'default' => 1,
35             );
36              
37             has 'close_fhs' => (
38             'is' => 'rw',
39             'isa' => 'Bool',
40             'default' => 1,
41             );
42              
43             has 'setsid' => (
44             'is' => 'rw',
45             'isa' => 'Bool',
46             'default' => 0,
47             );
48              
49             has 'name' => (
50             'is' => 'ro',
51             'isa' => 'Str',
52             );
53              
54             sub dispatch {
55             my $self = shift;
56              
57             my $code_ref = shift;
58             my $arg_ref = shift;
59              
60             # fork() - see Programming Perl p. 737
61             FORK:
62             {
63             if ( my $pid = fork ) {
64              
65             # This is the parent process, child pid is in $pid
66             }
67             elsif ( defined $pid ) {
68             POSIX::setsid() if $self->setsid(); # create own process group
69             if ( $self->chdir() && -d $self->chdir() ) {
70             chdir( $self->chdir() );
71             }
72             elsif ( $self->chdir() ) {
73             chdir(q{/});
74             }
75             # DGR: what should i do? just ignore it ...
76             ## no critic (RequireCheckedClose)
77             close(STDIN);
78             if ( $self->redirect_output() ) {
79             close(STDOUT);
80             close(STDERR);
81             }
82             ## use critic
83             ## no critic (RequireCheckedOpen ProhibitUnixDevNull)
84             open( STDIN, '<', '/dev/null' );
85             if ( $self->redirect_output() ) {
86             open( STDOUT, '>', '/dev/null' );
87             open( STDERR, '>', '/dev/null' );
88             }
89             ## use critic
90             # close any other filehandles (DBI, etc.)
91             # STDIN - 0
92             # STDOUT - 1
93             # STDERR - 2
94             # those were handled above ... now take care of the rest
95             if ( $self->close_fhs() ) {
96             ## no critic (ProhibitMagicNumbers)
97             foreach my $i ( 3 .. 255 ) {
98             POSIX::close($i);
99             }
100             ## use critic
101             }
102              
103             # $pid is null, if defined
104             # This is the child process
105             # get the pid of the parent via getppid
106             ## no critic (ProhibitPunctuationVars)
107             my $pid = $$;
108             ## use critic
109             my $ppid = getppid();
110              
111             $0 = $self->name() if $self->name();
112              
113             my $t0 = time(); # starttime
114             my $status = &{$code_ref}( 'ForkAsync', $arg_ref );
115             my $d0 = time() - $t0; # duration
116             if ($status) {
117             exit 0;
118             }
119             else {
120             exit 1;
121             }
122              
123             # end of fork(). The child _must_ exit here!
124             }
125             ## no critic (ProhibitPunctuationVars ProhibitMagicNumbers)
126             elsif ( $! == EAGAIN ) {
127             # EAGAIN, probably temporary fork error
128             sleep 5;
129             redo FORK;
130             }
131             ## use critic
132             else {
133              
134             # Strange fork error
135             ## no critic (ProhibitPunctuationVars)
136             warn 'Can not exec fork: '.$!."\n";
137             ## use critic
138             }
139             } # FORK
140             return 1;
141             }
142              
143             no Moose;
144             __PACKAGE__->meta->make_immutable;
145              
146             1;
147              
148             __END__
149              
150             =pod
151              
152             =encoding utf-8
153              
154             =head1 NAME
155              
156             Sys::ForkAsync - Simple async one-time job
157              
158             =head1 SYNOPSIS
159              
160             use Sys::ForkAsync;
161             my $Mod = Sys::ForkAsync::->new();
162              
163             =head1 DESCRIPTION
164              
165             Run a system command asynchronous.
166              
167             =head1 ATTRIBUTES
168              
169             =head2 chdir
170              
171             Change to this directory after the fork.
172              
173             =head2 redirect_output
174              
175             If set to true the output of the child will
176             be redirected to /dev/null.
177              
178             =head2 close_fhs
179              
180             Close all open filehandles after the fork
181             to prevent unsynchronized file I/O
182              
183             =head2 setsid
184              
185             Create its own process group.
186              
187             =head2 name
188              
189             Set the process name to this string, if set.
190              
191             =head1 METHODS
192              
193             =head2 dispatch
194              
195             Run the command in its own fork.
196              
197             =head2 EAGAIN
198              
199             Imported from Errno.
200              
201             1; # End of Linux::ForkAsync
202              
203             =head1 NAME
204              
205             Sys::ForkAsync - Run async commands
206              
207             =head1 AUTHOR
208              
209             Dominik Schulz <tex@cpan.org>
210              
211             =head1 COPYRIGHT AND LICENSE
212              
213             This software is copyright (c) 2012 by Dominik Schulz.
214              
215             This is free software; you can redistribute it and/or modify it under
216             the same terms as the Perl 5 programming language system itself.
217              
218             =cut