App-MtAws

 view release on metacpan or  search on metacpan

lib/App/MtAws/ForkEngine.pm  view on Meta::CPAN

			# child code
			my $first_time = 1;
			my @signals = qw/INT TERM USR2 HUP/;
			for my $sig (@signals) {
				$SIG{$sig} = sub {
					if ($first_time) {
						$first_time = 0;
						exit(1); # we need exit, it will call all destructors which will destroy tempfiles
					}
				};
			}
			$self->run_children($child_fromchild, $child_tochild);
			exit(1);
		}
	}

	my $first_time = 1;
	for my $sig (qw/INT TERM CHLD USR1 HUP/) {
		$SIG{$sig} = sub {
			local ($!,$^E,$@);
			my $status = undef;
			if ($sig eq 'CHLD') {
				my $pid = waitpid(-1, WNOHANG);
				$status = $?;
				# make sure we caugth signal from our children, not from external command executionin 3rd party module
				# easy to test by adding `whoami` to parent after-fork-code
				return unless $pid > 0 and defined delete $self->{children}{$pid}; # we also remove $pid
			}
			if ($first_time) {
				$first_time = 0;
				kill (POSIX::SIGUSR2, keys %{$self->{children}});
				while( wait() != -1 ){};
				$self->parent_exit_on_signal($sig, $status);
			}
		};
	}

	return $self->run_parent($disp_select);
}

#
# child/parent code
#
sub create_child
{
	my ($self, $disp_select) = @_;

	my $fromchild = new IO::Pipe;
	#log("created fromchild pipe $!", 10) if level(10);
	my $tochild = new IO::Pipe;
	#log("created tochild pipe $!", 10) if level(10);
	my $pid;
	my $parent_pid = $$;

	if($pid = fork()) { # Parent
		$|=1;
		STDERR->autoflush(1);
		$fromchild->reader();
		$fromchild->autoflush(1);
		$fromchild->blocking(1);
		binmode $fromchild;

		$tochild->writer();
		$tochild->autoflush(1);
		$tochild->blocking(1);
		binmode $tochild;

		$disp_select->add($fromchild);
		$self->{children}->{$pid} = { pid => $pid, fromchild => $fromchild, tochild => $tochild };

		print "PID $pid Started worker\n";
		return (0, undef, undef);
	} elsif (defined ($pid)) { # Child
		$|=1;
		STDERR->autoflush(1);
		$fromchild->writer();
		$fromchild->autoflush(1);
		$fromchild->blocking(1);
		binmode $fromchild;

		$tochild->reader();
		$tochild->autoflush(1);
		$tochild->blocking(1);
		binmode $tochild;

		undef $disp_select; # we discard tonns of unneeded pipes !
		undef $self->{children};

		return (1, $fromchild, $tochild);
	} else {
		die "Cannot fork()";
	}
}


sub terminate_children
{
	my ($self) = @_;
	$SIG{CHLD} = 'DEFAULT'; # don't set SIGCHLD to IGNORE, prevents wait() from working under 5.12.2,3 undef OpenBSD
	$SIG{INT} = $SIG{USR2}='IGNORE';

	# close all pipes, just in case select() in child is not interruptable (seems it is under 5.14.2?)
	# https://rt.perl.org/Ticket/Display.html?id=93428
	for (values %{$self->{children}}) {
		close $_->{fromchild};
		close $_->{tochild};
	}
	kill (POSIX::SIGUSR2, keys %{$self->{children}}); # TODO: we terminate all children with SIGUSR2 even on normal exit
	$SIG{TERM} = 'DEFAULT';
	while( wait() != -1 ){};
}
1;



( run in 0.820 second using v1.01-cache-2.11-cpan-99c4e6809bf )