mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 15:50:51 +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);
 | |
| 
 | |
| 
 |