mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/usr/bin/perl
 | 
						|
# -*- cperl -*-
 | 
						|
 | 
						|
use strict;
 | 
						|
use warnings;
 | 
						|
 | 
						|
use lib 'lib';
 | 
						|
use My::SafeProcess::Base;
 | 
						|
use POSIX qw(WNOHANG);
 | 
						|
 | 
						|
###########################################################################
 | 
						|
# Util functions
 | 
						|
###########################################################################
 | 
						|
 | 
						|
#
 | 
						|
#Print message to stderr
 | 
						|
#
 | 
						|
my $verbose= 0;
 | 
						|
sub message {
 | 
						|
  if ($verbose > 0){
 | 
						|
    use Time::localtime;
 | 
						|
    my $tm= localtime();
 | 
						|
    my $timestamp= sprintf("%02d%02d%02d %2d:%02d:%02d",
 | 
						|
			   $tm->year % 100, $tm->mon+1, $tm->mday,
 | 
						|
			   $tm->hour, $tm->min, $tm->sec);
 | 
						|
    print STDERR $timestamp, " monitor[$$]: ", @_, "\n";
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
###########################################################################
 | 
						|
# Main program
 | 
						|
###########################################################################
 | 
						|
 | 
						|
my $terminated= 0;
 | 
						|
 | 
						|
# Protect against being killed in the middle
 | 
						|
# of child creation, just set the terminated flag
 | 
						|
# to make sure the child will be killed off
 | 
						|
# when program is ready to do that
 | 
						|
$SIG{TERM}= sub { message("!Got signal @_"); $terminated= 1; };
 | 
						|
$SIG{INT}= sub { message("!Got signal @_"); $terminated= 1; };
 | 
						|
 | 
						|
my $parent_pid= getppid();
 | 
						|
 | 
						|
my $found_double_dash= 0;
 | 
						|
while (my $arg= shift(@ARGV)){
 | 
						|
 | 
						|
  if ($arg =~ /^--$/){
 | 
						|
    $found_double_dash= 1;
 | 
						|
    last;
 | 
						|
  }
 | 
						|
  elsif ($arg =~ /^--verbose$/){
 | 
						|
    $verbose= 1;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    die "Unknown option: $arg";
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
my $path=       shift(@ARGV); # Executable
 | 
						|
 | 
						|
die "usage:\n" .
 | 
						|
    " safe_process.pl [opts] -- <path> [<args> [...<args_n>]]"
 | 
						|
  unless defined $path || $found_double_dash;
 | 
						|
 | 
						|
 | 
						|
message("started");
 | 
						|
#message("path: '$path'");
 | 
						|
message("parent: $parent_pid");
 | 
						|
 | 
						|
# Start process to monitor
 | 
						|
my $child_pid=
 | 
						|
  create_process(
 | 
						|
		 path     => $path,
 | 
						|
		 args     => \@ARGV,
 | 
						|
		 setpgrp  => 1,
 | 
						|
		);
 | 
						|
message("Started child $child_pid");
 | 
						|
 | 
						|
eval {
 | 
						|
  sub handle_signal {
 | 
						|
    $terminated= 1;
 | 
						|
    message("Got signal @_");
 | 
						|
 | 
						|
    # Ignore all signals
 | 
						|
    foreach my $name (keys %SIG){
 | 
						|
      $SIG{$name}= 'IGNORE';
 | 
						|
    }
 | 
						|
 | 
						|
    die "signaled\n";
 | 
						|
  };
 | 
						|
  local $SIG{TERM}= \&handle_signal;
 | 
						|
  local $SIG{INT}=  \&handle_signal;
 | 
						|
  local $SIG{CHLD}= sub {
 | 
						|
    message("Got signal @_");
 | 
						|
    kill(9, -$child_pid);
 | 
						|
    my $ret= waitpid($child_pid, 0);
 | 
						|
    if ($? & 127){
 | 
						|
      exit(65); # Killed by signal
 | 
						|
    }
 | 
						|
    exit($? >> 8);
 | 
						|
  };
 | 
						|
 | 
						|
  # Monitoring loop
 | 
						|
  while(!$terminated) {
 | 
						|
 | 
						|
    # Check if parent is still alive
 | 
						|
    if (kill(0, $parent_pid) < 1){
 | 
						|
      message("Parent is not alive anymore");
 | 
						|
      last;
 | 
						|
    }
 | 
						|
 | 
						|
    # Wait for child to terminate but wakeup every
 | 
						|
    # second to also check that parent is still alive
 | 
						|
    my $ret_pid;
 | 
						|
    $ret_pid= waitpid($child_pid, &WNOHANG);
 | 
						|
    if ($ret_pid == $child_pid) {
 | 
						|
      # Process has exited, collect return status
 | 
						|
      my $ret_code= $? >> 8;
 | 
						|
      message("Child exit: $ret_code");
 | 
						|
      # Exit with exit status of the child
 | 
						|
      exit ($ret_code);
 | 
						|
    }
 | 
						|
    sleep(1);
 | 
						|
  }
 | 
						|
};
 | 
						|
if ( $@ ) {
 | 
						|
  # The monitoring loop should have been
 | 
						|
  # broken by handle_signal
 | 
						|
  warn "Unexpected: $@" unless ( $@ =~ /signaled/ );
 | 
						|
}
 | 
						|
 | 
						|
# Use negative pid in order to kill the whole
 | 
						|
# process group
 | 
						|
#
 | 
						|
my $ret= kill(9, -$child_pid);
 | 
						|
message("Killed child: $child_pid, ret: $ret");
 | 
						|
if ($ret > 0) {
 | 
						|
  message("Killed child: $child_pid");
 | 
						|
  # Wait blocking for the child to return
 | 
						|
  my $ret_pid= waitpid($child_pid, 0);
 | 
						|
  if ($ret_pid != $child_pid){
 | 
						|
    message("unexpected pid $ret_pid returned from waitpid($child_pid)");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
message("DONE!");
 | 
						|
exit (1);
 | 
						|
 | 
						|
 |