1 package MooseX::Runnable::Invocation::Plugin::Restart::Base;
3 use MooseX::Types::Moose qw(Int);
4 use namespace::autoclean;
9 clearer => 'clear_child_pid',
10 predicate => 'has_child_pid',
13 requires 'run_parent_loop';
15 my $is_debug = sub { return 1;
16 $_[0]->meta->does_role('MooseX::Runnable::Invocation::Plugin::Debug');
19 sub _restart_parent_setup {
25 return unless $self->has_child_pid;
26 eval { $self->_debug_message("Restarting...") };
27 kill 'HUP', $self->child_pid;
32 return unless $self->has_child_pid;
33 eval { $self->_debug_message("Killing ", $self->child_pid) };
35 kill 'KILL', $self->child_pid;
36 $self->clear_child_pid;
40 my ($next, $self, @args) = @_;
43 local $SIG{CHLD} = sub {
44 # handle the case where the child dies unexpectedly
45 waitpid $self->child_pid, 0;
46 $self->clear_child_pid;
47 my ($code, $sig) = ($? >> 8, $? & 127);
48 eval { $self->_debug_message(
49 "Exiting early, child died with status $code (signal $sig).",
52 # relay the error up, so the shell (etc.) can see it
53 kill $sig, $$ if $sig; # no-op?
58 $self->child_pid( $pid );
59 $self->_restart_parent_setup;
61 my $code = $self->run_parent_loop;
62 eval { $self->_debug_message("Shutting down.") };
68 # we go to all this effort so that the child process is always
69 # free of any "infection" by the parent (like the event loop,
70 # used by the parent to receive filesystem events or signals,
71 # which can't be cancelled by the child)
73 my $child_body; $child_body = sub {
77 # parent? wait for kid to die
78 local $SIG{HUP} = sub {
87 eval { $self->_debug_message(
88 "Child exited with non-zero status; aborting.",
94 # child? actually do the work
95 exit $self->$next(@args);