BGS - Background execution of subroutines in child processes.


BGS documentation Contained in the BGS distribution.

Index


Code Index:

NAME

Top

BGS - Background execution of subroutines in child processes.

SYNOPSIS

Top

  use BGS;

  my @foo;

  foreach my $i (1 .. 2) {
    bgs_call {
      # child process
      return "Start $i";
    } bgs_back {
      # callback subroutine
      my $r = shift;
      push @foo, "End $i. Result: '$r'.\n";
    };
  }

  bgs_wait();

  print foreach @foo;

MOTIVATION

Top

The module was created when need to receive information from dozens of database servers in the shortest time appeared.

DESCRIPTION

Top

bgs_call

Child process is created for each subroutine, that is prescribed with bgs_call, and it executes within this child process.

The subroutine must return either a scalar or a reference!

The answer of the subroutine passes to the callback subroutine as an argument. If a child process ended without bgs_call value returning, than bgs_back subprogram is called without argument.

bgs_call return PID of child proces.

bgs_back

The callback subroutine is described in bgs_back block.

The answer of bgs_call subroutine passes to bgs_back subroutine as an argument.

bgs_wait

Call of bgs_wait() reduces to child processes answers wait and callback subroutines execution.

AUTHOR

Top

Nick Kostirya

COPYRIGHT AND LICENSE

Top


BGS documentation Contained in the BGS distribution.

package BGS;

use strict;
use warnings;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(bgs_call bgs_back bgs_wait);

our $VERSION = '0.03';

use IO::Select;
use Storable qw(freeze thaw);


my $sel = IO::Select->new();
my %callbacks = (); 


sub bgs_call(&$) {
	my ($sub, $callback) = @_;

	pipe my $from_kid_fh, my $to_parent_fh or die "pipe: $!";

	my $kid_pid = fork;
	defined $kid_pid or die "Can't fork: $!";

	if ($kid_pid) {
		$sel->add($from_kid_fh);
		$callbacks{$from_kid_fh} = $callback;
	} else {
		binmode $to_parent_fh;
		print $to_parent_fh freeze \ scalar $sub->();
		close $to_parent_fh;
		exit;
	}
	return $kid_pid;
}

sub bgs_back(&) { shift }


sub bgs_wait() {
	local $SIG{CHLD} = "IGNORE";
	my %from_kid;       
	my $buf;            
	my $blksize = 1024; 
 	while ($sel->count()) {
 		foreach my $fh ($sel->can_read()) {
 			my $len = sysread $fh, $buf, $blksize;
 			if ($len) {
 				push @{$from_kid{$fh}}, $buf;
 			} elsif (defined $len) { 
				$sel->remove($fh); 
				close $fh or warn "Kid is existed: $?";

				if (exists $from_kid{$fh}) {
	 				my $r = join "", @{$from_kid{$fh}};
 					delete $from_kid{$fh};
					$callbacks{$fh}->(${thaw $r});
				} else {
					$callbacks{$fh}->();
				}

 				delete $callbacks{$fh};

 			} else {
 				die "Can't read '$fh': $!";
 			}
 		}
 	}
}


1;


__END__