mtr_process.pl
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:24k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. # -*- cperl -*-
  2. # This is a library file used by the Perl version of mysql-test-run,
  3. # and is part of the translation of the Bourne shell script with the
  4. # same name.
  5. #use Carp qw(cluck);
  6. use Socket;
  7. use Errno;
  8. use strict;
  9. #use POSIX ":sys_wait_h";
  10. use POSIX 'WNOHANG';
  11. sub mtr_run ($$$$$$;$);
  12. sub mtr_spawn ($$$$$$;$);
  13. sub mtr_stop_mysqld_servers ($);
  14. sub mtr_kill_leftovers ();
  15. sub mtr_record_dead_children ();
  16. sub mtr_exit ($);
  17. sub sleep_until_file_created ($$$);
  18. sub mtr_kill_processes ($);
  19. # static in C
  20. sub spawn_impl ($$$$$$$$);
  21. ##############################################################################
  22. #
  23. #  Execute an external command
  24. #
  25. ##############################################################################
  26. # This function try to mimic the C version used in "netware/mysql_test_run.c"
  27. # FIXME learn it to handle append mode as well, a "new" flag or a "append"
  28. sub mtr_run ($$$$$$;$) {
  29.   my $path=       shift;
  30.   my $arg_list_t= shift;
  31.   my $input=      shift;
  32.   my $output=     shift;
  33.   my $error=      shift;
  34.   my $pid_file=   shift;
  35.   my $spawn_opts= shift;
  36.   return spawn_impl($path,$arg_list_t,'run',$input,$output,$error,$pid_file,
  37.     $spawn_opts);
  38. }
  39. sub mtr_run_test ($$$$$$;$) {
  40.   my $path=       shift;
  41.   my $arg_list_t= shift;
  42.   my $input=      shift;
  43.   my $output=     shift;
  44.   my $error=      shift;
  45.   my $pid_file=   shift;
  46.   my $spawn_opts= shift;
  47.   return spawn_impl($path,$arg_list_t,'test',$input,$output,$error,$pid_file,
  48.     $spawn_opts);
  49. }
  50. sub mtr_spawn ($$$$$$;$) {
  51.   my $path=       shift;
  52.   my $arg_list_t= shift;
  53.   my $input=      shift;
  54.   my $output=     shift;
  55.   my $error=      shift;
  56.   my $pid_file=   shift;
  57.   my $spawn_opts= shift;
  58.   return spawn_impl($path,$arg_list_t,'spawn',$input,$output,$error,$pid_file,
  59.     $spawn_opts);
  60. }
  61. ##############################################################################
  62. #
  63. #  If $join is set, we return the error code, else we return the PID
  64. #
  65. ##############################################################################
  66. sub spawn_impl ($$$$$$$$) {
  67.   my $path=       shift;
  68.   my $arg_list_t= shift;
  69.   my $mode=       shift;
  70.   my $input=      shift;
  71.   my $output=     shift;
  72.   my $error=      shift;
  73.   my $pid_file=   shift;                 # FIXME
  74.   my $spawn_opts= shift;
  75.   if ( $::opt_script_debug )
  76.   {
  77.     print STDERR "n";
  78.     print STDERR "#### ", "-" x 78, "n";
  79.     print STDERR "#### ", "STDIN  $inputn" if $input;
  80.     print STDERR "#### ", "STDOUT $outputn" if $output;
  81.     print STDERR "#### ", "STDERR $errorn" if $error;
  82.     print STDERR "#### ", "$mode : $path ", join(" ",@$arg_list_t), "n";
  83.     print STDERR "#### ", "spawn options:n";
  84.     if ($spawn_opts)
  85.     {
  86.       foreach my $key (sort keys %{$spawn_opts})
  87.       {
  88.         print STDERR "#### ", "  - $key: $spawn_opts->{$key}n";
  89.       }
  90.     }
  91.     else
  92.     {
  93.       print STDERR "#### ", "  nonen";
  94.     }
  95.     print STDERR "#### ", "-" x 78, "n";
  96.   }
  97.  FORK:
  98.   {
  99.     my $pid= fork();
  100.     if ( ! defined $pid )
  101.     {
  102.       if ( $! == $!{EAGAIN} )           # See "perldoc Errno"
  103.       {
  104.         mtr_debug("Got EAGAIN from fork(), sleep 1 second and redo");
  105.         sleep(1);
  106.         redo FORK;
  107.       }
  108.       else
  109.       {
  110.         mtr_error("$path ($pid) can't be forked");
  111.       }
  112.     }
  113.     if ( $pid )
  114.     {
  115.       spawn_parent_impl($pid,$mode,$path);
  116.     }
  117.     else
  118.     {
  119.       # Child, redirect output and exec
  120.       # FIXME I tried POSIX::setsid() here to detach and, I hoped,
  121.       # avoid zombies. But everything went wild, somehow the parent
  122.       # became a deamon as well, and was hard to kill ;-)
  123.       # Need to catch SIGCHLD and do waitpid or something instead......
  124.       $SIG{INT}= 'DEFAULT';         # Parent do some stuff, we don't
  125.       if ( $::glob_cygwin_shell and $mode eq 'test' )
  126.       {
  127.         # Programs started from mysqltest under Cygwin, are to
  128.         # execute them within Cygwin. Else simple things in test
  129.         # files like
  130.         # --system "echo 1 > file"
  131.         # will fail.
  132.         # FIXME not working :-(
  133. #       $ENV{'COMSPEC'}= "$::glob_cygwin_shell -c";
  134.       }
  135.       my $log_file_open_mode = '>';
  136.       if ($spawn_opts and $spawn_opts->{'append_log_file'})
  137.       {
  138.         $log_file_open_mode = '>>';
  139.       }
  140.       if ( $output )
  141.       {
  142.         if ( ! open(STDOUT,$log_file_open_mode,$output) )
  143.         {
  144.           mtr_child_error("can't redirect STDOUT to "$output": $!");
  145.         }
  146.       }
  147.       if ( $error )
  148.       {
  149.         if ( $output eq $error )
  150.         {
  151.           if ( ! open(STDERR,">&STDOUT") )
  152.           {
  153.             mtr_child_error("can't dup STDOUT: $!");
  154.           }
  155.         }
  156.         else
  157.         {
  158.           if ( ! open(STDERR,$log_file_open_mode,$error) )
  159.           {
  160.             mtr_child_error("can't redirect STDERR to "$error": $!");
  161.           }
  162.         }
  163.       }
  164.       if ( $input )
  165.       {
  166.         if ( ! open(STDIN,"<",$input) )
  167.         {
  168.           mtr_child_error("can't redirect STDIN to "$input": $!");
  169.         }
  170.       }
  171.       if ( ! exec($path,@$arg_list_t) )
  172.       {
  173.         mtr_child_error("failed to execute "$path": $!");
  174.       }
  175.     }
  176.   }
  177. }
  178. sub spawn_parent_impl {
  179.   my $pid=  shift;
  180.   my $mode= shift;
  181.   my $path= shift;
  182.   if ( $mode eq 'run' or $mode eq 'test' )
  183.   {
  184.     if ( $mode eq 'run' )
  185.     {
  186.       # Simple run of command, we wait for it to return
  187.       my $ret_pid= waitpid($pid,0);
  188.       if ( $ret_pid <= 0 )
  189.       {
  190.         mtr_error("$path ($pid) got lost somehow");
  191.       }
  192.       return mtr_process_exit_status($?);
  193.     }
  194.     else
  195.     {
  196.       # We run mysqltest and wait for it to return. But we try to
  197.       # catch dying mysqld processes as well.
  198.       #
  199.       # We do blocking waitpid() until we get the return from the
  200.       # "mysqltest" call. But if a mysqld process dies that we
  201.       # started, we take this as an error, and kill mysqltest.
  202.       #
  203.       # FIXME is this as it should be? Can't mysqld terminate
  204.       # normally from running a test case?
  205.       my $exit_value= -1;
  206.       my $saved_exit_value;
  207.       my $ret_pid;                      # What waitpid() returns
  208.       while ( ($ret_pid= waitpid(-1,0)) != -1 )
  209.       {
  210.         # Someone terminated, don't know who. Collect
  211.         # status info first before $? is lost,
  212.         # but not $exit_value, this is flagged from
  213.         # 
  214.         my $timer_name= mtr_timer_timeout($::glob_timers, $ret_pid);
  215.         if ( $timer_name )
  216.         {
  217.           if ( $timer_name eq "suite" )
  218.           {
  219.             # We give up here
  220.             # FIXME we should only give up the suite, not all of the run?
  221.             print STDERR "n";
  222.             mtr_error("Test suite timeout");
  223.           }
  224.           elsif ( $timer_name eq "testcase" )
  225.           {
  226.             $saved_exit_value=  63;       # Mark as timeout
  227.             kill(9, $pid);                # Kill mysqltest
  228.             next;                         # Go on and catch the termination
  229.           }
  230.         }
  231.         if ( $ret_pid == $pid )
  232.         {
  233.           # We got termination of mysqltest, we are done
  234.           $exit_value= mtr_process_exit_status($?);
  235.           last;
  236.         }
  237.         # If one of the mysqld processes died, we want to
  238.         # mark this, and kill the mysqltest process.
  239.         foreach my $idx (0..1)
  240.         {
  241.           if ( $::master->[$idx]->{'pid'} eq $ret_pid )
  242.           {
  243.             mtr_debug("child $ret_pid was master[$idx], " .
  244.                       "exit during mysqltest run");
  245.             $::master->[$idx]->{'pid'}= 0;
  246.             last;
  247.           }
  248.         }
  249.         foreach my $idx (0..2)
  250.         {
  251.           if ( $::slave->[$idx]->{'pid'} eq $ret_pid )
  252.           {
  253.             mtr_debug("child $ret_pid was slave[$idx], " .
  254.                       "exit during mysqltest run");
  255.             $::slave->[$idx]->{'pid'}= 0;
  256.             last;
  257.           }
  258.         }
  259.         mtr_debug("waitpid() catched exit of unknown child $ret_pid, " .
  260.                   "exit during mysqltest run");
  261.       }
  262.       if ( $ret_pid != $pid )
  263.       {
  264.         # We terminated the waiting because a "mysqld" process died.
  265.         # Kill the mysqltest process.
  266.         kill(9,$pid);
  267.         $ret_pid= waitpid($pid,0);
  268.         if ( $ret_pid == -1 )
  269.         {
  270.           mtr_error("$path ($pid) got lost somehow");
  271.         }
  272.       }
  273.       return $saved_exit_value || $exit_value;
  274.     }
  275.   }
  276.   else
  277.   {
  278.     # We spawned a process we don't wait for
  279.     return $pid;
  280.   }
  281. }
  282. # ----------------------------------------------------------------------
  283. # We try to emulate how an Unix shell calculates the exit code
  284. # ----------------------------------------------------------------------
  285. sub mtr_process_exit_status {
  286.   my $raw_status= shift;
  287.   if ( $raw_status & 127 )
  288.   {
  289.     return ($raw_status & 127) + 128;  # Signal num + 128
  290.   }
  291.   else
  292.   {
  293.     return $raw_status >> 8;           # Exit code
  294.   }
  295. }
  296. ##############################################################################
  297. #
  298. #  Kill processes left from previous runs
  299. #
  300. ##############################################################################
  301. # We just "ping" on the ports, and if we can't do a socket connect
  302. # we assume the server is dead. So we don't *really* know a server
  303. # is dead, we just hope that it after letting the listen port go,
  304. # it is dead enough for us to start a new server.
  305. sub mtr_kill_leftovers () {
  306.   # First, kill all masters and slaves that would conflict with
  307.   # this run. Make sure to remove the PID file, if any.
  308.   my @args;
  309.   for ( my $idx; $idx < 2; $idx++ )
  310.   {
  311.     push(@args,{
  312.                 pid      => 0,          # We don't know the PID
  313.                 pidfile  => $::master->[$idx]->{'path_mypid'},
  314.                 sockfile => $::master->[$idx]->{'path_mysock'},
  315.                 port     => $::master->[$idx]->{'path_myport'},
  316.                });
  317.   }
  318.   for ( my $idx; $idx < 3; $idx++ )
  319.   {
  320.     push(@args,{
  321.                 pid       => 0,         # We don't know the PID
  322.                 pidfile   => $::slave->[$idx]->{'path_mypid'},
  323.                 sockfile  => $::slave->[$idx]->{'path_mysock'},
  324.                 port      => $::slave->[$idx]->{'path_myport'},
  325.                });
  326.   }
  327.   mtr_mysqladmin_shutdown(@args, 20);
  328.   # We now have tried to terminate nice. We have waited for the listen
  329.   # port to be free, but can't really tell if the mysqld process died
  330.   # or not. We now try to find the process PID from the PID file, and
  331.   # send a kill to that process. Note that Perl let kill(0,@pids) be
  332.   # a way to just return the numer of processes the kernel can send
  333.   # signals to. So this can be used (except on Cygwin) to determine
  334.   # if there are processes left running that we cound out might exists.
  335.   #
  336.   # But still after all this work, all we know is that we have
  337.   # the ports free.
  338.   # We scan the "var/run/" directory for other process id's to kill
  339.   # FIXME $path_run_dir or something
  340.   my $rundir= "$::opt_vardir/run";
  341.   if ( -d $rundir )
  342.   {
  343.     opendir(RUNDIR, $rundir)
  344.       or mtr_error("can't open directory "$rundir": $!");
  345.     my @pids;
  346.     while ( my $elem= readdir(RUNDIR) )
  347.     {
  348.       my $pidfile= "$rundir/$elem";
  349.       if ( -f $pidfile )
  350.       {
  351.         my $pid= mtr_get_pid_from_file($pidfile);
  352.         # Race, could have been removed between I tested with -f
  353.         # and the unlink() below, so I better check again with -f
  354.         if ( ! unlink($pidfile) and -f $pidfile )
  355.         {
  356.           mtr_error("can't remove $pidfile");
  357.         }
  358.         if ( $::glob_cygwin_perl or kill(0, $pid) )
  359.         {
  360.           push(@pids, $pid);            # We know (cygwin guess) it exists
  361.         }
  362.       }
  363.     }
  364.     closedir(RUNDIR);
  365.     if ( @pids )
  366.     {
  367.       if ( $::glob_cygwin_perl )
  368.       {
  369.         # We have no (easy) way of knowing the Cygwin controlling
  370.         # process, in the PID file we only have the Windows process id.
  371.         system("kill -f " . join(" ",@pids)); # Hope for the best....
  372.         mtr_debug("Sleep 5 seconds waiting for processes to die");
  373.         sleep(5);
  374.       }
  375.       else
  376.       {
  377.         my $retries= 10;                    # 10 seconds
  378.         do
  379.         {
  380.           kill(9, @pids);
  381.           mtr_debug("Sleep 1 second waiting for processes to die");
  382.           sleep(1)                      # Wait one second
  383.         } while ( $retries-- and  kill(0, @pids) );
  384.         if ( kill(0, @pids) )           # Check if some left
  385.         {
  386.           # FIXME maybe just mtr_warning() ?
  387.           mtr_error("can't kill process(es) " . join(" ", @pids));
  388.         }
  389.       }
  390.     }
  391.   }
  392.   # We may have failed everything, bug we now check again if we have
  393.   # the listen ports free to use, and if they are free, just go for it.
  394.   foreach my $srv ( @args )
  395.   {
  396.     if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
  397.     {
  398.       mtr_error("can't kill old mysqld holding port $srv->{'port'}");
  399.     }
  400.   }
  401. }
  402. ##############################################################################
  403. #
  404. #  Shut down mysqld servers we have started from this run of this script
  405. #
  406. ##############################################################################
  407. # To speed things we kill servers in parallel. The argument is a list
  408. # of 'ports', 'pids', 'pidfiles' and 'socketfiles'.
  409. # FIXME On Cygwin, and maybe some other platforms, $srv->{'pid'} and
  410. # $srv->{'pidfile'} will not be the same PID. We need to try to kill
  411. # both I think.
  412. sub mtr_stop_mysqld_servers ($) {
  413.   my $spec=  shift;
  414.   # ----------------------------------------------------------------------
  415.   # First try nice normal shutdown using 'mysqladmin'
  416.   # ----------------------------------------------------------------------
  417.   # Shutdown time must be high as slave may be in reconnect
  418.   mtr_mysqladmin_shutdown($spec, 70);
  419.   # ----------------------------------------------------------------------
  420.   # We loop with waitpid() nonblocking to see how many of the ones we
  421.   # are to kill, actually got killed by mtr_mysqladmin_shutdown().
  422.   # Note that we don't rely on this, the mysqld server might have stop
  423.   # listening to the port, but still be alive. But it is a start.
  424.   # ----------------------------------------------------------------------
  425.   foreach my $srv ( @$spec )
  426.   {
  427.     if ( $srv->{'pid'} and (waitpid($srv->{'pid'},&WNOHANG) == $srv->{'pid'}) )
  428.     {
  429.       $srv->{'pid'}= 0;
  430.     }
  431.   }
  432.   # ----------------------------------------------------------------------
  433.   # We know the process was started from this file, so there is a PID
  434.   # saved, or else we have nothing to do.
  435.   # Might be that is is recorded to be missing, but we failed to
  436.   # take away the PID file earlier, then we do it now.
  437.   # ----------------------------------------------------------------------
  438.   my %mysqld_pids;
  439.   foreach my $srv ( @$spec )
  440.   {
  441.     if ( $srv->{'pid'} )
  442.     {
  443.       $mysqld_pids{$srv->{'pid'}}= 1;
  444.     }
  445.     else
  446.     {
  447.       # Server is dead, we remove the pidfile if any
  448.       # Race, could have been removed between I tested with -f
  449.       # and the unlink() below, so I better check again with -f
  450.       if ( -f $srv->{'pidfile'} and ! unlink($srv->{'pidfile'}) and
  451.            -f $srv->{'pidfile'} )
  452.       {
  453.         mtr_error("can't remove $srv->{'pidfile'}");
  454.       }
  455.     }
  456.   }
  457.   # ----------------------------------------------------------------------
  458.   # If the processes where started from this script, and we had no PIDS
  459.   # then we don't have to do anything.
  460.   # ----------------------------------------------------------------------
  461.   if ( ! keys %mysqld_pids )
  462.   {
  463.     # cluck "This is how we got here!";
  464.     return;
  465.   }
  466.   # ----------------------------------------------------------------------
  467.   # In mtr_mysqladmin_shutdown() we only waited for the mysqld servers
  468.   # not to listen to the port. But we are not sure we got them all
  469.   # killed. If we suspect it lives, try nice kill with SIG_TERM. Note
  470.   # that for true Win32 processes, kill(0,$pid) will not return 1.
  471.   # ----------------------------------------------------------------------
  472.   start_reap_all();                     # Avoid zombies
  473.   my @mysqld_pids= keys %mysqld_pids;
  474.   mtr_kill_processes(@mysqld_pids);
  475.   stop_reap_all();                      # Get into control again
  476.   # ----------------------------------------------------------------------
  477.   # Now, we check if all we can find using kill(0,$pid) are dead,
  478.   # and just assume the rest are. We cleanup socket and PID files.
  479.   # ----------------------------------------------------------------------
  480.   {
  481.     my $errors= 0;
  482.     foreach my $srv ( @$spec )
  483.     {
  484.       if ( $srv->{'pid'} )
  485.       {
  486.         if ( kill(0,$srv->{'pid'}) )
  487.         {
  488.           # FIXME In Cygwin there seem to be some fast reuse
  489.           # of PIDs, so dying may not be the right thing to do.
  490.           $errors++;
  491.           mtr_warning("can't kill process $srv->{'pid'}");
  492.         }
  493.         else
  494.         {
  495.           # We managed to kill it at last
  496.           # FIXME In Cygwin, we will get here even if the process lives.
  497.           # Not needed as we know the process is dead, but to be safe
  498.           # we unlink and check success in two steps. We first unlink
  499.           # without checking the error code, and then check if the
  500.           # file still exists.
  501.           foreach my $file ($srv->{'pidfile'}, $srv->{'sockfile'})
  502.           {
  503.             # Know it is dead so should be no race, careful anyway
  504.             if ( -f $file and ! unlink($file) and -f $file )
  505.             {
  506.               $errors++;
  507.               mtr_warning("couldn't delete $file");
  508.             }
  509.           }
  510.         }
  511.       }
  512.     }
  513.     if ( $errors )
  514.     {
  515.       # We are in trouble, just die....
  516.       mtr_error("we could not kill or clean up all processes");
  517.     }
  518.   }
  519.   # FIXME We just assume they are all dead, for Cygwin we are not
  520.   # really sure
  521.     
  522. }
  523. ##############################################################################
  524. #
  525. #  Shut down mysqld servers using "mysqladmin ... shutdown".
  526. #  To speed this up, we start them in parallel and use waitpid() to
  527. #  catch their termination. Note that this doesn't say the servers
  528. #  are terminated, just that 'mysqladmin' is terminated.
  529. #
  530. #  Note that mysqladmin will ask the server about what PID file it uses,
  531. #  and mysqladmin will wait for it to be removed before it terminates
  532. #  (unless passes timeout).
  533. #
  534. #  This function will take at most about 20 seconds, and we still are not
  535. #  sure we killed them all. If none is responding to ping, we return 1,
  536. #  else we return 0.
  537. #
  538. ##############################################################################
  539. sub mtr_mysqladmin_shutdown {
  540.   my $spec= shift;
  541.   my $adm_shutdown_tmo= shift;
  542.   my %mysql_admin_pids;
  543.   my @to_kill_specs;
  544.   foreach my $srv ( @$spec )
  545.   {
  546.     if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
  547.     {
  548.       push(@to_kill_specs, $srv);
  549.     }
  550.   }
  551.   foreach my $srv ( @to_kill_specs )
  552.   {
  553.     # FIXME wrong log.....
  554.     # FIXME, stderr.....
  555.     # Shutdown time must be high as slave may be in reconnect
  556.     my $args;
  557.     mtr_init_args($args);
  558.     mtr_add_arg($args, "--no-defaults");
  559.     mtr_add_arg($args, "--user=%s", $::opt_user);
  560.     mtr_add_arg($args, "--password=");
  561.     if ( -e $srv->{'sockfile'} )
  562.     {
  563.       mtr_add_arg($args, "--socket=%s", $srv->{'sockfile'});
  564.     }
  565.     if ( $srv->{'port'} )
  566.     {
  567.       mtr_add_arg($args, "--port=%s", $srv->{'port'});
  568.     }
  569.     if ( $srv->{'port'} and ! -e $srv->{'sockfile'} )
  570.     {
  571.       mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket
  572.     }
  573.     mtr_add_arg($args, "--connect_timeout=5");
  574.     mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo");
  575.     mtr_add_arg($args, "shutdown");
  576.     # We don't wait for termination of mysqladmin
  577.     my $pid= mtr_spawn($::exe_mysqladmin, $args,
  578.                        "", $::path_manager_log, $::path_manager_log, "",
  579.                        { append_log_file => 1 });
  580.     $mysql_admin_pids{$pid}= 1;
  581.   }
  582.   # As mysqladmin is such a simple program, we trust it to terminate.
  583.   # I.e. we wait blocking, and wait wait for them all before we go on.
  584.   while (keys %mysql_admin_pids)
  585.   {
  586.     foreach my $pid (keys %mysql_admin_pids)
  587.     {
  588.       if ( waitpid($pid,0) > 0 )
  589.       {
  590.         delete $mysql_admin_pids{$pid};
  591.       }
  592.     }
  593.   }
  594.   # If we trusted "mysqladmin --shutdown_timeout= ..." we could just
  595.   # terminate now, but we don't (FIXME should be debugged).
  596.   # So we try again to ping and at least wait the same amount of time
  597.   # mysqladmin would for all to die.
  598.   my $timeout= 20;                      # 20 seconds max
  599.   my $res= 1;                           # If we just fall through, we are done
  600.                                         # in the sense that the servers don't
  601.                                         # listen to their ports any longer
  602.  TIME:
  603.   while ( $timeout-- )
  604.   {
  605.     foreach my $srv ( @to_kill_specs )
  606.     {
  607.       $res= 1;                          # We are optimistic
  608.       if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
  609.       {
  610.         mtr_debug("Sleep 1 second waiting for processes to stop using port");
  611.         sleep(1);                       # One second
  612.         $res= 0;
  613.         next TIME;
  614.       }
  615.     }
  616.     last;                               # If we got here, we are done
  617.   }
  618.   $timeout or mtr_debug("At least one server is still listening to its port");
  619.   sleep(5) if $::glob_win32;            # FIXME next startup fails if no sleep
  620.   return $res;
  621. }
  622. ##############################################################################
  623. #
  624. #  The operating system will keep information about dead children, 
  625. #  we read this information here, and if we have records the process
  626. #  is alive, we mark it as dead.
  627. #
  628. ##############################################################################
  629. sub mtr_record_dead_children () {
  630.   my $ret_pid;
  631.   # FIXME the man page says to wait for -1 to terminate,
  632.   # but on OS X we get '0' all the time...
  633.   while ( ($ret_pid= waitpid(-1,&WNOHANG)) > 0 )
  634.   {
  635.     mtr_debug("waitpid() catched exit of child $ret_pid");
  636.     foreach my $idx (0..1)
  637.     {
  638.       if ( $::master->[$idx]->{'pid'} eq $ret_pid )
  639.       {
  640.         mtr_debug("child $ret_pid was master[$idx]");
  641.         $::master->[$idx]->{'pid'}= 0;
  642.       }
  643.     }
  644.     foreach my $idx (0..2)
  645.     {
  646.       if ( $::slave->[$idx]->{'pid'} eq $ret_pid )
  647.       {
  648.         mtr_debug("child $ret_pid was slave[$idx]");
  649.         $::slave->[$idx]->{'pid'}= 0;
  650.         last;
  651.       }
  652.     }
  653.   }
  654. }
  655. sub start_reap_all {
  656.   $SIG{CHLD}= 'IGNORE';                 # FIXME is this enough?
  657. }
  658. sub stop_reap_all {
  659.   $SIG{CHLD}= 'DEFAULT';
  660. }
  661. sub mtr_ping_mysqld_server () {
  662.   my $port= shift;
  663.   my $remote= "localhost";
  664.   my $iaddr=  inet_aton($remote);
  665.   if ( ! $iaddr )
  666.   {
  667.     mtr_error("can't find IP number for $remote");
  668.   }
  669.   my $paddr=  sockaddr_in($port, $iaddr);
  670.   my $proto=  getprotobyname('tcp');
  671.   if ( ! socket(SOCK, PF_INET, SOCK_STREAM, $proto) )
  672.   {
  673.     mtr_error("can't create socket: $!");
  674.   }
  675.   if ( connect(SOCK, $paddr) )
  676.   {
  677.     close(SOCK);                        # FIXME check error?
  678.     return 1;
  679.   }
  680.   else
  681.   {
  682.     return 0;
  683.   }
  684. }
  685. ##############################################################################
  686. #
  687. #  Wait for a file to be created
  688. #
  689. ##############################################################################
  690. # FIXME check that the pidfile contains the expected pid!
  691. sub sleep_until_file_created ($$$) {
  692.   my $pidfile= shift;
  693.   my $timeout= shift;
  694.   my $pid=     shift;
  695.   for ( my $loop= 1; $loop <= $timeout; $loop++ )
  696.   {
  697.     if ( -r $pidfile )
  698.     {
  699.       return $pid;
  700.     }
  701.     # Check if it died after the fork() was successful 
  702.     if ( waitpid($pid,&WNOHANG) == $pid )
  703.     {
  704.       return 0;
  705.     }
  706.     mtr_debug("Sleep 1 second waiting for creation of $pidfile");
  707.     if ( $loop % 60 == 0 )
  708.     {
  709.       my $left= $timeout - $loop;
  710.       mtr_warning("Waited $loop seconds for $pidfile to be created, " .
  711.                   "still waiting for $left seconds...");
  712.     }
  713.     sleep(1);
  714.   }
  715.   return 0;
  716. }
  717. sub mtr_kill_processes ($) {
  718.   my $pids = shift;
  719.   foreach my $sig (15,9)
  720.   {
  721.     my $retries= 20;                    # FIXME 20 seconds, this is silly!
  722.     kill($sig, @{$pids});
  723.     while ( $retries-- and  kill(0, @{$pids}) )
  724.     {
  725.       mtr_debug("Sleep 1 second waiting for processes to die");
  726.       sleep(1)                      # Wait one second
  727.     }
  728.   }
  729. }
  730. ##############################################################################
  731. #
  732. #  When we exit, we kill off all children
  733. #
  734. ##############################################################################
  735. # FIXME something is wrong, we sometimes terminate with "Hangup" written
  736. # to tty, and no STDERR output telling us why.
  737. # FIXME for some readon, setting HUP to 'IGNORE' will cause exit() to
  738. # write out "Hangup", and maybe loose some output. We insert a sleep...
  739. sub mtr_exit ($) {
  740.   my $code= shift;
  741. #  cluck("Called mtr_exit()");
  742.   mtr_timer_stop_all($::glob_timers);
  743.   local $SIG{HUP} = 'IGNORE';
  744.   kill('HUP', -$$);
  745.   sleep 2;
  746.   exit($code);
  747. }
  748. 1;