File Coverage

blib/lib/BGS.pm
Criterion Covered Total %
statement 58 78 74.3
branch 10 22 45.4
condition n/a
subroutine 9 11 81.8
pod 4 4 100.0
total 81 115 70.4


line stmt bran cond sub pod time code
1             package BGS;
2              
3 7     7   191972 use strict;
  7         14  
  7         202  
4 7     7   37 use warnings;
  7         13  
  7         195  
5              
6 7     7   37 use Exporter;
  7         13  
  7         441  
7             our @ISA = qw(Exporter);
8             our @EXPORT = qw(bgs_call bgs_back bgs_wait bgs_break);
9              
10             our $VERSION = '0.08';
11              
12 7     7   1857 use IO::Select;
  7         8773  
  7         283  
13 7     7   2688 use Storable qw(freeze thaw);
  7         16887  
  7         415  
14 7     7   2059 use POSIX ":sys_wait_h";
  7         38964  
  7         63  
15              
16              
17             $SIG{CHLD} = "IGNORE";
18              
19             my $sel = IO::Select->new();
20              
21             my %callbacks = ();
22             my %fh2vpid = ();
23             my %vpid2fh = ();
24             my %vpid2pid = ();
25              
26              
27             sub bgs_call(&$) {
28 14     14 1 37 my ($sub, $callback) = @_;
29              
30 14 50       385 pipe my $from_kid_fh, my $to_parent_fh or die "pipe: $!";
31              
32 14         9797 my $kid_pid = fork;
33 14 50       534 defined $kid_pid or die "Can't fork: $!";
34 14         99 my $vpid = $kid_pid;
35              
36 14 100       250 if ($kid_pid) {
37 9         345 $sel->add($from_kid_fh);
38 9         1306 $callbacks{$from_kid_fh} = $callback;
39 9         66 $fh2vpid{$from_kid_fh} = $vpid;
40 9         86 $vpid2fh{$vpid} = $from_kid_fh;
41 9         45 $vpid2pid{$vpid} = $kid_pid;
42             } else {
43 5         217 binmode $to_parent_fh;
44 5         160 print $to_parent_fh freeze \ scalar $sub->();
45 5         1003 close $to_parent_fh;
46 5         995 exit;
47             }
48 9         594 return $vpid;
49             }
50              
51 5     5 1 252 sub bgs_back(&) { shift }
52              
53              
54             sub bgs_wait() {
55 3     3 1 166 local $SIG{PIPE} = "IGNORE";
56 3         23 my %from_kid;
57             my $buf;
58 3         37 my $blksize = 1024;
59 3         44 while ($sel->count()) {
60 10         136 foreach my $fh ($sel->can_read()) {
61 12         584 my $len = sysread $fh, $buf, $blksize;
62 12 100       75 if ($len) {
    50          
63 6         15 push @{$from_kid{$fh}}, $buf;
  6         67  
64             } elsif (defined $len) {
65 6         55 $sel->remove($fh);
66 6 50       335 close $fh or warn "Kid is existed: $?";
67              
68 6 50       27 if (exists $from_kid{$fh}) {
69 6         14 my $r = join "", @{$from_kid{$fh}};
  6         56  
70 6         19 delete $from_kid{$fh};
71 6         13 $callbacks{$fh}->(${thaw $r});
  6         44  
72             } else {
73 0         0 $callbacks{$fh}->();
74             }
75              
76 5         1873 my $vpid = $fh2vpid{$fh};
77 5         82 delete $callbacks{$fh};
78 5         28 delete $fh2vpid{$fh};
79 5 50       22 if ($vpid) {
80 5         14 delete $vpid2fh{$vpid};
81 5         43 delete $vpid2pid{$vpid};
82             }
83              
84             } else {
85 0           die "Can't read '$fh': $!";
86             }
87             }
88             }
89             }
90              
91              
92             sub _clean_by_vpid {
93 0     0     my ($vpid) = @_;
94 0 0         my $fh = $vpid2fh{$vpid} or return;
95              
96 0           $sel->remove($fh);
97 0           close $fh;
98              
99 0           delete $callbacks{$fh};
100 0           delete $fh2vpid{$fh};
101 0           delete $vpid2fh{$vpid};
102 0           delete $vpid2pid{$vpid};
103             }
104              
105              
106             sub bgs_break(;$) {
107 0     0 1   my ($vpid) = @_;
108 0 0         if (defined $vpid) {
109 0 0         if (my $pid = $vpid2pid{$vpid}) {
110 0           kill 15, $pid;
111 0           1 while waitpid($pid, WNOHANG) > 0;
112 0           _clean_by_vpid($vpid);
113             }
114             } else {
115 0           local $SIG{TERM} = "IGNORE";
116 0           kill 15, -$$;
117 0           1 while waitpid(-1, WNOHANG) > 0;
118 0           _clean_by_vpid($_) foreach keys %vpid2fh;
119             }
120             }
121              
122              
123             1;
124              
125              
126             __END__