package Zing::Fork; use 5.014; use strict; use warnings; use registry 'Zing::Types'; use routines; use Data::Object::Class; use Data::Object::ClassHas; use Data::Object::Space; extends 'Zing::Class'; use POSIX (); use Config; our $VERSION = '0.27'; # VERSION # ATTRIBUTES has 'scheme' => ( is => 'ro', isa => 'Scheme', req => 1, ); has 'parent' => ( is => 'rw', isa => 'Process', req => 1, ); has 'processes' => ( is => 'rw', isa => 'HashRef[Process]', def => sub{{}}, ); has 'space' => ( is => 'ro', isa => 'Space', new => 1 ); fun new_space($self) { Data::Object::Space->new($self->scheme->[0]) } # SHIMS sub _waitpid { CORE::waitpid(shift, POSIX::WNOHANG) } # METHODS method execute() { my $pid; my $process; my $sid = $$; if ($Config{d_pseudofork}) { $self->throw(error_fork('emulation not supported')); } if(!defined($pid = fork)) { $self->fork(error_fork("$!")); } # parent if ($pid) { $process = $self->space->load->new( @{$self->scheme->[1]}, pid => $pid, parent => $self->parent, ); return $self->processes->{$pid} = $process; } # child else { $pid = $$; $process = $self->space->load->new( @{$self->scheme->[1]}, pid => $pid, parent => $self->parent, ); $process->execute; } POSIX::_exit(0); } method monitor() { my $result = {}; for my $pid (sort keys %{$self->processes}) { $result->{$pid} = _waitpid $pid; } return $result; } method sanitize() { my $result = $self->monitor; for my $pid (sort keys %{$result}) { if ($result->{$pid} == $pid || $result->{$pid} == -1) { delete $self->processes->{$pid}; } } return scalar(keys %{$self->processes}); } method terminate(Str $signal = 'kill') { my $result = {}; for my $pid (sort keys %{$self->processes}) { $result->{$pid} = $self->processes->{$pid}->signal($pid, $signal); } return $result; } # ERRORS fun error_fork(Str $reason) { code => 'error_fork', message => "Error on fork: $reason", } 1; =encoding utf8 =head1 NAME Zing::Fork - Fork Manager =cut =head1 ABSTRACT Scheme Fork Manager =cut =head1 SYNOPSIS use Zing::Fork; use Zing::Process; my $scheme = ['MyApp', [], 1]; my $fork = Zing::Fork->new(scheme => $scheme, parent => Zing::Process->new); # $fork->execute; =cut =head1 DESCRIPTION This package provides provides a mechanism for forking and tracking processes, as well as establishing the parent-child relationship. B The C<$num> part of the application scheme, i.e. C<['MyApp', [], $num]>, is ignored and launching the desired forks requires calling L multiple times. =cut =head1 LIBRARIES This package uses type constraints from: L =cut =head1 ATTRIBUTES This package has the following attributes: =cut =head2 parent parent(Process) This attribute is read-only, accepts C<(Process)> values, and is required. =cut =head2 processes processes(HashRef[Process]) This attribute is read-only, accepts C<(HashRef[Process])> values, and is optional. =cut =head2 scheme scheme(Scheme) This attribute is read-only, accepts C<(Scheme)> values, and is required. =cut =head2 space space(Space) This attribute is read-only, accepts C<(Space)> values, and is optional. =cut =head1 METHODS This package implements the following methods: =cut =head2 execute execute() : Process The execute method forks a process based on the scheme, adds it to the process list and returns a representation of the child process. =over 4 =item execute example #1 # given: synopsis my $process = $fork->execute; =back =cut =head2 monitor monitor() : HashRef[Int] The monitor method calls L on tracked processes and returns the results as a pid/result map. =over 4 =item monitor example #1 # given: synopsis $fork->execute; $fork->execute; # forks still alive my $results = $fork->monitor; # { 1000 => 1000, ... } =back =over 4 =item monitor example #2 # given: synopsis $fork->execute; $fork->execute; # forks are dead my $results = $fork->monitor; # { 1000 => -1, ... } =back =cut =head2 sanitize sanitize() : Int The sanitize method removes inactive child processes from the process list and returns the number of processes remaining. =over 4 =item sanitize example #1 # given: synopsis $fork->execute; # dead $fork->execute; # dead my $results = $fork->sanitize; # 0 =back =over 4 =item sanitize example #2 # given: synopsis $fork->execute; # live $fork->execute; # dead my $results = $fork->sanitize; # 1 =back =over 4 =item sanitize example #3 # given: synopsis $fork->execute; # live $fork->execute; # live my $results = $fork->sanitize; # 2 =back =cut =head2 terminate terminate(Str $signal = 'kill') : HashRef[Int] The terminate method call L and sends a signal to all tracked processes and returns the results as a pid/result map. =over 4 =item terminate example #1 # given: synopsis $fork->execute; $fork->execute; my $results = $fork->terminate; # kill =back =over 4 =item terminate example #2 # given: synopsis $fork->execute; $fork->execute; my $results = $fork->terminate('term'); =back =over 4 =item terminate example #3 # given: synopsis $fork->execute; $fork->execute; my $results = $fork->terminate('usr2'); =back =cut =head1 AUTHOR Al Newkirk, C =head1 LICENSE Copyright (C) 2011-2019, Al Newkirk, et al. This is free software; you can redistribute it and/or modify it under the terms of the The Apache License, Version 2.0, as elucidated in the L<"license file"|https://github.com/cpanery/zing/blob/master/LICENSE>. =head1 PROJECT L L L L L L =cut