package fork_bufferd_read; use IO::Pipe; use strict; use warnings; my %running=(); $SIG{CHLD}=\&__child_died; # new instance # $obj=fork_bufferd_read->new(); sub new { my $class=shift; my $code=shift; my $self={}; $self->{pipe} = undef; $self->{pid} = undef; $self->{running}=0; $self->{code}=$code; return undef unless(_start($self)); bless($self,$class); return $self; } # read buffer # $str=$obj->read(); sub read { my $self=shift; my $buffer=''; if($self->{running}) { my $pipe=$self->{pipe}; if($pipe->opened()) { kill('USR1',$self->{pid}); local $/=undef; $buffer=<$pipe>; $buffer='' unless(defined($buffer)); } else { $self->_finish(); } } return $buffer; } sub running { $_[0]->{running}; } ######################################################################## sub DESTROY { my $self=shift; $self->_finish(); } sub _finish { my $self=shift; local $SIG{CHLD}='IGNORE'; if($self->{running}) { kill(15,$self->{pid}); $self->{running}=0; $self->{pipe}=undef; } delete($running{$self->{pid}}) if($self->{pid}); } sub _start { my $self=shift; return 1 if(defined($self->{pipe}) && $self->{pid} && $self->{running}); return 0 unless(ref($self->{code}) eq 'CODE'); my $pipe=IO::Pipe->new(); return 0 if(!defined($pipe)); my $pid=fork(); return 0 if(!defined($pid)); if($pid) { $pipe->reader(); $pipe->blocking(0); $self->{pipe} = $pipe; $self->{pid} = $pid; $self->{running}=1; $running{$pid}=$self; return 1; } $pipe->writer(); $pipe->autoflush(1); __child_process($pipe, $self->{code}); die("ERROR RUNN CHILD\n"); } sub __child_died { my $pid=wait(); if(exists($running{$pid})) { $running{$pid}->{running}=0; $running{$pid}->{pipe}=undef; $running{$pid}->{pid}=undef; delete($running{$pid}); return 1; } return 0; } sub __child_process { my $pipe=shift; my $code=shift; die() unless(ref($code) eq 'CODE'); local $SIG{CHLD}='IGNORE'; local $SIG{TERM}=sub{ exit(); }; my $buffer=''; local $SIG{USR1}=sub{ print $pipe $buffer; $buffer=''; }; while($code->(\$buffer)) { 1; } while(length($buffer)>0) { select(undef,undef,undef,0.01); } exit(); } 1;