mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
WL#4189
- dynamic configuration support - safe process - cleanups - create new suite for fedarated BitKeeper/deleted/.del-basic.test: Rename: mysql-test/ndb/basic.test -> BitKeeper/deleted/.del-basic.test BitKeeper/deleted/.del-basic_log.result: Rename: mysql-test/ndb/basic_log.result -> BitKeeper/deleted/.del-basic_log.result mysql-test/suite/federated/federated_transactions.result: Rename: mysql-test/r/federated_transactions.result -> mysql-test/suite/federated/federated_transactions.result BitKeeper/deleted/.del-have_bug25714.require: Rename: mysql-test/r/have_bug25714.require -> BitKeeper/deleted/.del-have_bug25714.require BitKeeper/deleted/.del-kill_master.sh: Rename: mysql-test/misc/kill_master.sh -> BitKeeper/deleted/.del-kill_master.sh BitKeeper/deleted/.del-ndb_config_4_node.ini~d8e572e9b68f933a: Rename: mysql-test/ndb/ndb_config_4_node.ini -> BitKeeper/deleted/.del-ndb_config_4_node.ini~d8e572e9b68f933a BitKeeper/deleted/.del-restart.result: Rename: mysql-test/ndb/restart.result -> BitKeeper/deleted/.del-restart.result mysql-test/suite/federated/federated_cleanup.inc: Rename: mysql-test/include/federated_cleanup.inc -> mysql-test/suite/federated/federated_cleanup.inc mysql-test/suite/rpl/t/rpl_rotate_logs-slave.opt: Rename: mysql-test/suite/rpl/t/rpl_rotate_logs.slave-mi -> mysql-test/suite/rpl/t/rpl_rotate_logs-slave.opt BitKeeper/deleted/.del-install_test_db.sh: Rename: mysql-test/install_test_db.sh -> BitKeeper/deleted/.del-install_test_db.sh BitKeeper/deleted/.del-ndb_config_1_node.ini~7ec640ed25570e16: Rename: mysql-test/ndb/ndb_config_1_node.ini -> BitKeeper/deleted/.del-ndb_config_1_node.ini~7ec640ed25570e16 BitKeeper/deleted/.del-mtr_timer.pl: Rename: mysql-test/lib/mtr_timer.pl -> BitKeeper/deleted/.del-mtr_timer.pl BitKeeper/deleted/.del-create-test-result: Rename: mysql-test/create-test-result -> BitKeeper/deleted/.del-create-test-result BitKeeper/deleted/.del-fix-result: Rename: mysql-test/fix-result -> BitKeeper/deleted/.del-fix-result BitKeeper/deleted/.del-mysql-test-run-shell.sh: Rename: mysql-test/mysql-test-run-shell.sh -> BitKeeper/deleted/.del-mysql-test-run-shell.sh BitKeeper/deleted/.del-mysql-test_V1.9.pl: Rename: mysql-test/misc/mysql-test_V1.9.pl -> BitKeeper/deleted/.del-mysql-test_V1.9.pl BitKeeper/deleted/.del-resolve-stack: Rename: mysql-test/resolve-stack -> BitKeeper/deleted/.del-resolve-stack BitKeeper/deleted/.del-restart_log.result: Rename: mysql-test/ndb/restart_log.result -> BitKeeper/deleted/.del-restart_log.result mysql-test/suite/rpl/t/rpl_000015-slave.opt: Rename: mysql-test/suite/rpl/t/rpl_000015.slave-mi -> mysql-test/suite/rpl/t/rpl_000015-slave.opt BitKeeper/deleted/.del-ndb_config_2_node.ini: Rename: mysql-test/ndb/ndb_config_2_node.ini -> BitKeeper/deleted/.del-ndb_config_2_node.ini BitKeeper/deleted/.del-ndbcluster.sh: Rename: mysql-test/ndb/ndbcluster.sh -> BitKeeper/deleted/.del-ndbcluster.sh BitKeeper/deleted/.del-basic.result: Rename: mysql-test/ndb/basic.result -> BitKeeper/deleted/.del-basic.result BitKeeper/deleted/.del-restart.test: Rename: mysql-test/ndb/restart.test -> BitKeeper/deleted/.del-restart.test BitKeeper/deleted/.del-have_bug25714.inc: Rename: mysql-test/include/have_bug25714.inc -> BitKeeper/deleted/.del-have_bug25714.inc BitKeeper/deleted/.del-mtr_diff.pl: Rename: mysql-test/lib/mtr_diff.pl -> BitKeeper/deleted/.del-mtr_diff.pl mysql-test/suite/federated/federated_transactions-slave.opt: Rename: mysql-test/t/federated_transactions-slave.opt -> mysql-test/suite/federated/federated_transactions-slave.opt BitKeeper/deleted/.del-Makefile.am~343467da4d0f211b: Rename: mysql-test/ndb/Makefile.am -> BitKeeper/deleted/.del-Makefile.am~343467da4d0f211b BitKeeper/deleted/.del-mtr_im.pl~9762b0336c28949: Rename: mysql-test/lib/mtr_im.pl -> BitKeeper/deleted/.del-mtr_im.pl~9762b0336c28949 mysql-test/suite/federated/federated_innodb-slave.opt: Rename: mysql-test/t/federated_innodb-slave.opt -> mysql-test/suite/federated/federated_innodb-slave.opt client/mysqltest.c: Use current files path first when looking for include file configure.in: Remove mysql-test/nbd mysql-test/Makefile.am: Cleanup mysql-test/Makefile.am mysql-test/extra/binlog_tests/blackhole.test: Use new paths mysql-test/extra/binlog_tests/ctype_ucs_binlog.test: Use new paths mysql-test/mysql-test-run.pl: Dynamic configuration support Safe process mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test: Use new paths mysql-test/extra/rpl_tests/rpl_EE_err.test: Use new paths mysql-test/extra/rpl_tests/rpl_loaddata.test: Use new paths mysql-test/extra/rpl_tests/rpl_log.test: Use new paths mysql-test/extra/rpl_tests/rpl_row_001.test: Use new paths mysql-test/extra/rpl_tests/rpl_row_charset.test: Use new paths mysql-test/extra/rpl_tests/rpl_stm_000001.test: Use new paths mysql-test/extra/rpl_tests/rpl_stm_charset.test: Use new paths mysql-test/include/have_blackhole.inc: Use new paths mysql-test/include/have_ndbapi_examples.inc: Use new paths mysql-test/include/loaddata_autocom.inc: Use new paths mysql-test/include/mix1.inc: Use new paths mysql-test/include/ndb_backup.inc: Use new paths mysql-test/include/ndb_restore_master.inc: Use new paths mysql-test/include/ndb_restore_slave_eoption.inc: Use new paths mysql-test/include/testdb_only.inc: Use new paths mysql-test/lib/My/Config.pm: dynamic configuration safe process cleanups mysql-test/lib/mtr_cases.pm: dynamic configuration safe process cleanups mysql-test/lib/mtr_io.pl: dynamic configuration safe process cleanups mysql-test/lib/mtr_misc.pl: dynamic configuration safe process cleanups mysql-test/lib/mtr_process.pl: dynamic configuration safe process cleanups mysql-test/lib/mtr_report.pl: dynamic configuration safe process cleanups mysql-test/lib/mtr_stress.pl: dynamic configuration safe process cleanups mysql-test/r/backup.result: Use new paths mysql-test/r/ctype_big5.result: Use new paths mysql-test/r/gis.result: Use new paths mysql-test/r/loaddata.result: Use new paths mysql-test/r/loaddata_autocom_innodb.result: Use new paths mysql-test/r/mysqlbinlog.result: Use new paths mysql-test/r/mysqlbinlog_base64.result: Use new paths mysql-test/r/outfile.result: Use new paths mysql-test/r/partition_error.result: Use new paths mysql-test/r/partition_not_windows.result: Use new paths mysql-test/r/partition_symlink.result: Use new paths mysql-test/r/query_cache.result: Use new paths mysql-test/r/sp.result: Use new paths mysql-test/r/symlink.result: Use new paths mysql-test/r/system_mysql_db.result: Use new paths mysql-test/r/trigger.result: Use new paths mysql-test/r/type_blob.result: Use new paths mysql-test/r/view.result: Use new paths mysql-test/r/warnings.result: Use new paths mysql-test/suite/binlog/r/binlog_killed_simulate.result: Use new paths mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: Use new paths mysql-test/suite/binlog/r/binlog_stm_blackhole.result: Use new paths mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: Use new paths mysql-test/suite/binlog/t/binlog_killed.test: Use new paths mysql-test/suite/binlog/t/binlog_killed_simulate.test: Use new paths mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test: Use new paths mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: Use new paths mysql-test/suite/federated/federated.inc: Use new paths mysql-test/suite/federated/federated.result: Use new paths mysql-test/suite/federated/federated.test: Use new paths mysql-test/suite/federated/federated_archive.result: Use new paths mysql-test/suite/federated/federated_archive.test: Use new paths mysql-test/suite/federated/federated_bug_13118.result: Use new paths mysql-test/suite/federated/federated_bug_13118.test: Use new paths mysql-test/suite/federated/federated_bug_25714.result: Use new paths mysql-test/suite/federated/federated_bug_25714.test: Use new paths mysql-test/suite/federated/federated_innodb.result: Use new paths mysql-test/suite/federated/federated_innodb.test: Use new paths mysql-test/suite/federated/federated_server.result: Use new paths mysql-test/suite/federated/federated_server.test: Use new paths mysql-test/suite/federated/federated_transactions.test: Use new paths mysql-test/suite/federated/have_federated_db.inc: Use new paths mysql-test/suite/ndb/r/loaddata_autocom_ndb.result: Use new paths mysql-test/suite/ndb/r/ndb_config.result: Use new paths mysql-test/suite/ndb/r/ndb_dd_backuprestore.result: Use new paths mysql-test/suite/ndb/r/ndb_load.result: Use new paths mysql-test/suite/ndb/r/ndb_loaddatalocal.result: Use new paths mysql-test/suite/ndb/r/ndb_replace.result: Use new paths mysql-test/suite/ndb/r/ndb_restore.result: Use new paths mysql-test/suite/ndb/r/ndb_restore_partition.result: Use new paths mysql-test/suite/ndb/r/ndb_restore_print.result: Use new paths mysql-test/suite/ndb/r/ndb_trigger.result: Use new paths mysql-test/suite/ndb/t/ndb_alter_table.test: Use new paths mysql-test/suite/ndb/t/ndb_config.test: Use new paths mysql-test/suite/ndb/t/ndb_load.test: Use new paths mysql-test/suite/ndb/t/ndb_loaddatalocal.test: Use new paths mysql-test/suite/ndb/t/ndb_replace.test: Use new paths mysql-test/suite/ndb/t/ndb_restore.test: Use new paths mysql-test/suite/ndb/t/ndb_single_user.test: Use new paths mysql-test/suite/ndb/t/ndb_trigger.test: Use new paths mysql-test/suite/ndb/t/ndbapi.test: Use new paths mysql-test/suite/rpl/include/rpl_mixed_dml.inc: Use new paths mysql-test/suite/rpl/r/rpl_LD_INFILE.result: Use new paths mysql-test/suite/rpl/r/rpl_flushlog_loop.result: Use new paths mysql-test/suite/rpl/r/rpl_innodb.result: Use new paths mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result: Use new paths mysql-test/suite/rpl/r/rpl_load_table_from_master.result: Use new paths mysql-test/suite/rpl/r/rpl_loaddata.result: Use new paths mysql-test/suite/rpl/r/rpl_loaddata_charset.result: Use new paths mysql-test/suite/rpl/r/rpl_loaddata_fatal.result: Use new paths mysql-test/suite/rpl/r/rpl_loaddata_m.result: Use new paths mysql-test/suite/rpl/r/rpl_loaddata_s.result: Use new paths mysql-test/suite/rpl/r/rpl_loaddata_simple.result: Use new paths mysql-test/suite/rpl/r/rpl_loaddatalocal.result: Use new paths mysql-test/suite/rpl/r/rpl_loadfile.result: Use new paths mysql-test/suite/rpl/r/rpl_misc_functions.result: Use new paths mysql-test/suite/rpl/r/rpl_replicate_do.result: Use new paths mysql-test/suite/rpl/r/rpl_rewrt_db.result: Use new paths mysql-test/suite/rpl/r/rpl_row_001.result: Use new paths mysql-test/suite/rpl/r/rpl_row_loaddata_m.result: Use new paths mysql-test/suite/rpl/r/rpl_row_log.result: Use new paths mysql-test/suite/rpl/r/rpl_row_log_innodb.result: Use new paths mysql-test/suite/rpl/r/rpl_row_stop_middle_update.result: Use new paths mysql-test/suite/rpl/r/rpl_stm_000001.result: Use new paths mysql-test/suite/rpl/r/rpl_stm_log.result: Use new paths mysql-test/suite/rpl/r/rpl_timezone.result: Use new paths mysql-test/suite/rpl/t/disabled.def: Use new paths mysql-test/suite/rpl/t/rpl000017-slave.sh: Use new paths mysql-test/suite/rpl/t/rpl_LD_INFILE.test: Use new paths mysql-test/suite/rpl/t/rpl_drop_db.test: Use new paths mysql-test/suite/rpl/t/rpl_flushlog_loop-master.opt: Use new paths mysql-test/suite/rpl/t/rpl_flushlog_loop-slave.opt: Use new paths mysql-test/suite/rpl/t/rpl_flushlog_loop.test: Use new paths mysql-test/suite/rpl/t/rpl_innodb.test: Use new paths mysql-test/suite/rpl/t/rpl_innodb_bug30919.test: Use new paths mysql-test/suite/rpl/t/rpl_load_from_master.test: Use new paths mysql-test/suite/rpl/t/rpl_load_table_from_master.test: Use new paths mysql-test/suite/rpl/t/rpl_loaddata_charset.test: Use new paths mysql-test/suite/rpl/t/rpl_loaddata_fatal.test: Use new paths mysql-test/suite/rpl/t/rpl_loaddata_m.test: Use new paths mysql-test/suite/rpl/t/rpl_loaddata_s.test: Use new paths mysql-test/suite/rpl/t/rpl_loaddata_simple.test: Use new paths mysql-test/suite/rpl/t/rpl_loaddatalocal.test: Use new paths mysql-test/suite/rpl/t/rpl_loadfile.test: Use new paths mysql-test/suite/rpl/t/rpl_misc_functions.test: Use new paths mysql-test/suite/rpl/t/rpl_replicate_do.test: Use new paths mysql-test/suite/rpl/t/rpl_rewrt_db.test: Use new paths mysql-test/suite/rpl/t/rpl_rotate_logs-master.opt: Use new paths mysql-test/suite/rpl/t/rpl_rotate_logs.test: Use new paths mysql-test/suite/rpl/t/rpl_row_charset_innodb.test: Use new paths mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test: Use new paths mysql-test/suite/rpl/t/rpl_row_stop_middle_update.test: Use new paths mysql-test/suite/rpl/t/rpl_timezone.test: Use new paths mysql-test/suite/rpl/t/rpl_trigger.test: Use new paths mysql-test/suite/rpl_ndb/r/rpl_ndb_dd_advance.result: Use new paths mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb_trans.result: Use new paths mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result: Use new paths mysql-test/suite/rpl_ndb/r/rpl_ndb_multi.result: Use new paths mysql-test/suite/rpl_ndb/r/rpl_ndb_row_001.result: Use new paths mysql-test/suite/rpl_ndb/r/rpl_ndb_sync.result: Use new paths mysql-test/suite/rpl_ndb/t/rpl_ndb_bank.test: Use new paths mysql-test/suite/rpl_ndb/t/rpl_ndb_dd_advance.test: Use new paths mysql-test/suite/rpl_ndb/t/rpl_ndb_innodb_trans.test: Use new paths mysql-test/suite/rpl_ndb/t/rpl_ndb_load.test: Use new paths mysql-test/suite/rpl_ndb/t/rpl_ndb_sync.test: Use new paths mysql-test/suite/rpl_ndb/t/rpl_ndbapi_multi.test: Use new paths mysql-test/t/backup.test: Use new paths mysql-test/t/bootstrap.test: Use new paths mysql-test/t/crash_commit_before.test: Use new paths mysql-test/t/create_not_windows.test: Use new paths mysql-test/t/csv.test: Use new paths mysql-test/t/ctype_big5.test: Use new paths mysql-test/t/disabled.def: Use new paths mysql-test/t/distinct.test: Use new paths mysql-test/t/gis.test: Use new paths mysql-test/t/grant_cache_no_prot.test: Use new paths mysql-test/t/grant_cache_ps_prot.test: Use new paths mysql-test/t/information_schema_chmod.test: Use new paths mysql-test/t/loaddata.test: Use new paths mysql-test/t/log_state.test: Use new paths mysql-test/t/myisam-system.test: Use new paths mysql-test/t/mysql_upgrade.test: Use new paths mysql-test/t/mysqlbinlog-cp932.test: Use new paths mysql-test/t/mysqlbinlog.test: Use new paths mysql-test/t/mysqlbinlog2.test: Use new paths mysql-test/t/mysqlbinlog_base64.test: Use new paths mysql-test/t/mysqldump.test: Use new paths mysql-test/t/outfile.test: Use new paths mysql-test/t/partition.test: Use new paths mysql-test/t/partition_error.test: Use new paths mysql-test/t/partition_federated.test: Use new paths mysql-test/t/partition_mgm.test: Use new paths mysql-test/t/partition_not_windows.test: Use new paths mysql-test/t/partition_symlink.test: Use new paths mysql-test/t/query_cache.test: Use new paths mysql-test/t/repair.test: Use new paths mysql-test/t/show_check.test: Use new paths mysql-test/t/sp-destruct.test: Use new paths mysql-test/t/sp.test: Use new paths mysql-test/t/symlink.test: Use new paths mysql-test/t/system_mysql_db.test: Use new paths mysql-test/t/system_mysql_db_fix30020.test: Use new paths mysql-test/t/system_mysql_db_fix40123.test: Use new paths mysql-test/t/system_mysql_db_fix50030.test: Use new paths mysql-test/t/system_mysql_db_fix50117.test: Use new paths mysql-test/t/trigger-compat.test: Use new paths mysql-test/t/trigger-grant.test: Use new paths mysql-test/t/trigger.test: Use new paths mysql-test/t/type_blob.test: Use new paths mysql-test/t/type_varchar.test: Use new paths mysql-test/t/upgrade.test: Use new paths mysql-test/t/user_var-binlog.test: Use new paths mysql-test/t/varbinary.test: Use new paths mysql-test/t/view.test: Use new paths mysql-test/t/warnings.test: Use new paths mysql-test/lib/My/ConfigFactory.pm: Initial version mysql-test/lib/My/Find.pm: Initial version mysql-test/lib/My/SafeProcess.pm: Initial version mysql-test/std_data/ndb_config_config.ini: Add "old" style config.ini for ndb mysql-test/suite/federated/disabled.def: Move disabled federated to it's new suite mysql-test/suite/federated/my.cnf: Add config for federated mysql-test/suite/ndb/my.cnf: Add config for ndb mysql-test/suite/rpl/my.cnf: Add config for rpl mysql-test/suite/rpl/rpl_1slave_base.cnf: Add base config for rpl mysql-test/suite/rpl/t/rpl_000015-master.opt: Use new paths mysql-test/suite/rpl_ndb/my.cnf: Add config for rpl_ndb mysql-test/lib/My/File/Path.pm: Initial version mysql-test/lib/My/SafeProcess/Base.pm: Initial version mysql-test/lib/My/SafeProcess/safe_kill_win.cc: Initial version mysql-test/lib/My/SafeProcess/safe_process.pl: Initial version mysql-test/lib/My/SafeProcess/safe_process_win.cc: Initial version mysql-test/lib/t/Base.t: Initial version mysql-test/lib/t/Find.t: Initial version mysql-test/lib/t/SafeProcess.t: Initial version mysql-test/lib/t/SafeProcessStress.pl: Initial version mysql-test/lib/t/copytree.t: Initial version mysql-test/lib/t/dummyd.pl: Initial version mysql-test/lib/t/rmtree.t: Initial version mysql-test/lib/t/testMyConfig.t: Initial version mysql-test/lib/t/testMyConfigFactory.t: Initial version mysql-test/lib/t/test_child.pl: Initial version mysql-test/include/default_my.cnf: Add default config file used when no suite specific file is found mysql-test/include/default_mysqld.cnf: New BitKeeper file ``mysql-test/include/default_mysqld.cnf'' mysql-test/include/default_ndbd.cnf: Add default settings for all ndbds mysql-test/lib/mtr_settings.pl: Initial version
This commit is contained in:
236
mysql-test/lib/My/SafeProcess/Base.pm
Normal file
236
mysql-test/lib/My/SafeProcess/Base.pm
Normal file
@ -0,0 +1,236 @@
|
||||
# -*- cperl -*-
|
||||
# Copyright (C) 2004-2006 MySQL AB
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
# This is a library file used by the Perl version of mysql-test-run,
|
||||
# and is part of the translation of the Bourne shell script with the
|
||||
# same name.
|
||||
|
||||
use strict;
|
||||
|
||||
package My::SafeProcess::Base;
|
||||
|
||||
#
|
||||
# Utility functions for Process management
|
||||
#
|
||||
|
||||
use Carp;
|
||||
use IO::Pipe;
|
||||
|
||||
use base qw(Exporter);
|
||||
our @EXPORT= qw(create_process);
|
||||
|
||||
|
||||
sub winpid {
|
||||
my ($pid)= @_;
|
||||
|
||||
return undef unless $^O eq "cygwin";
|
||||
|
||||
# The child get a new winpid when the exec takes
|
||||
# place, wait for that to happen
|
||||
my $winpid;
|
||||
my $delay= 0;
|
||||
do
|
||||
{
|
||||
# Yield to the child
|
||||
select(undef, undef, undef, $delay);
|
||||
# Increase the delay slightly for each loop
|
||||
$delay += 0.000001;
|
||||
|
||||
$winpid= Cygwin::pid_to_winpid($pid);
|
||||
|
||||
} until ($winpid != $pid);
|
||||
|
||||
return $winpid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# safe_fork
|
||||
# Retry a couple of times if fork returns EAGAIN
|
||||
#
|
||||
sub _safe_fork {
|
||||
my $retries= 5;
|
||||
my $pid;
|
||||
|
||||
FORK:
|
||||
{
|
||||
$pid= fork;
|
||||
if ( not defined($pid)) {
|
||||
|
||||
croak("fork failed after: $!") if (!$retries--);
|
||||
|
||||
warn("fork failed sleep 1 second and redo: $!");
|
||||
sleep(1);
|
||||
redo FORK;
|
||||
}
|
||||
}
|
||||
|
||||
return $pid;
|
||||
};
|
||||
|
||||
|
||||
#
|
||||
# Decode exit status
|
||||
#
|
||||
sub exit_status {
|
||||
my $self= shift;
|
||||
my $raw= $self->{EXIT_STATUS};
|
||||
|
||||
croak("Can't call exit_status before process has died")
|
||||
unless defined $raw;
|
||||
|
||||
if ($raw & 127)
|
||||
{
|
||||
# Killed by signal
|
||||
my $signal_num= $raw & 127;
|
||||
my $dumped_core= $raw & 128;
|
||||
return 1; # Return error code
|
||||
}
|
||||
else
|
||||
{
|
||||
# Normal process exit
|
||||
return $raw >> 8;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Create a new process
|
||||
# Return pid of the new process
|
||||
#
|
||||
sub create_process {
|
||||
my %opts=
|
||||
(
|
||||
@_
|
||||
);
|
||||
|
||||
my $path = delete($opts{'path'}) or die "path required";
|
||||
my $args = delete($opts{'args'}) or die "args required";
|
||||
my $input = delete($opts{'input'});
|
||||
my $output = delete($opts{'output'});
|
||||
my $error = delete($opts{'error'});
|
||||
|
||||
my $open_mode= $opts{append} ? ">>" : ">";
|
||||
|
||||
if ($^O eq "MSWin32"){
|
||||
|
||||
#printf STDERR "stdin %d, stdout %d, stderr %d\n",
|
||||
# fileno STDIN, fileno STDOUT, fileno STDERR;
|
||||
|
||||
# input output redirect
|
||||
my ($oldin, $oldout, $olderr);
|
||||
open $oldin, '<&', \*STDIN or die "Failed to save old stdin: $!";
|
||||
open $oldout, '>&', \*STDOUT or die "Failed to save old stdout: $!";
|
||||
open $olderr, '>&', \*STDERR or die "Failed to save old stderr: $!";
|
||||
|
||||
if ( $input ) {
|
||||
if ( ! open(STDIN, "<", $input) ) {
|
||||
croak("can't redirect STDIN to '$input': $!");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $output ) {
|
||||
if ( ! open(STDOUT, $open_mode, $output) ) {
|
||||
croak("can't redirect STDOUT to '$output': $!");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $error ) {
|
||||
if ( $output eq $error ) {
|
||||
if ( ! open(STDERR, ">&STDOUT") ) {
|
||||
croak("can't dup STDOUT: $!");
|
||||
}
|
||||
}
|
||||
elsif ( ! open(STDERR, $open_mode, $error) ) {
|
||||
croak("can't redirect STDERR to '$error': $!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Magic use of 'system(1, @args)' to spawn a process
|
||||
# and get a proper Win32 pid
|
||||
unshift (@$args, $path);
|
||||
my $pid= system(1, @$args);
|
||||
if ( $pid == 0 ){
|
||||
print $olderr "create_process failed: $^E\n";
|
||||
die "create_process failed: $^E";
|
||||
}
|
||||
|
||||
# Retore IO redirects
|
||||
open STDERR, '>&', $olderr
|
||||
or croak("unable to reestablish STDERR");
|
||||
open STDOUT, '>&', $oldout
|
||||
or croak("unable to reestablish STDOUT");
|
||||
open STDIN, '<&', $oldin
|
||||
or croak("unable to reestablish STDIN");
|
||||
#printf STDERR "stdin %d, stdout %d, stderr %d\n",
|
||||
# fileno STDIN, fileno STDOUT, fileno STDERR;
|
||||
return wantarray ? ($pid, $pid) : $pid;
|
||||
|
||||
}
|
||||
|
||||
local $SIG{PIPE}= sub { print STDERR "Got signal $@\n"; };
|
||||
my $pipe= IO::Pipe->new();
|
||||
my $pid= _safe_fork();
|
||||
if ($pid){
|
||||
# Parent
|
||||
$pipe->reader();
|
||||
my $line= <$pipe>; # Wait for child to say it's ready
|
||||
return wantarray ? ($pid, winpid($pid)) : $pid;
|
||||
}
|
||||
|
||||
$SIG{INT}= 'DEFAULT';
|
||||
|
||||
# Make this process it's own process group to be able to kill
|
||||
# it and any childs(that hasn't changed group themself)
|
||||
setpgrp(0,0) if $opts{setpgrp};
|
||||
|
||||
if ( $output and !open(STDOUT, $open_mode, $output) ) {
|
||||
croak("can't redirect STDOUT to '$output': $!");
|
||||
}
|
||||
|
||||
if ( $error ) {
|
||||
if ( defined $output and $output eq $error ) {
|
||||
if ( ! open(STDERR, ">&STDOUT") ) {
|
||||
croak("can't dup STDOUT: $!");
|
||||
}
|
||||
}
|
||||
elsif ( ! open(STDERR, $open_mode, $error) ) {
|
||||
croak("can't redirect STDERR to '$error': $!");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $input ) {
|
||||
if ( ! open(STDIN, "<", $input) ) {
|
||||
croak("can't redirect STDIN to '$input': $!");
|
||||
}
|
||||
}
|
||||
|
||||
# Tell parent to continue
|
||||
$pipe->writer();
|
||||
print $pipe "ready\n";
|
||||
|
||||
if ( !exec($path, @$args) ){
|
||||
croak("Failed to exec '$path': $!");
|
||||
}
|
||||
|
||||
croak("Should never come here");
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
|
56
mysql-test/lib/My/SafeProcess/safe_kill_win.cc
Executable file
56
mysql-test/lib/My/SafeProcess/safe_kill_win.cc
Executable file
@ -0,0 +1,56 @@
|
||||
/* Copyright (C) 2004 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
/*
|
||||
Utility program used to signal a safe_process it's time to shutdown
|
||||
|
||||
Usage:
|
||||
safe_kill <pid>
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, const char** argv )
|
||||
{
|
||||
DWORD pid= -1;
|
||||
HANDLE shutdown_event;
|
||||
char safe_process_name[32]= {0};
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "safe_kill <pid>\n");
|
||||
exit(2);
|
||||
}
|
||||
pid= atoi(argv[1]);
|
||||
|
||||
_snprintf(safe_process_name, sizeof(safe_process_name), "safe_process[%d]", pid);
|
||||
|
||||
/* Open the event to signal */
|
||||
if ((shutdown_event=
|
||||
OpenEvent(EVENT_MODIFY_STATE, FALSE, safe_process_name)) == NULL){
|
||||
fprintf(stderr, "Failed to open shutdown_event\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(SetEvent(shutdown_event) == 0) {
|
||||
fprintf(stderr, "Failed to signal shutdown_event\n");
|
||||
CloseHandle(shutdown_event);
|
||||
exit(1);
|
||||
}
|
||||
CloseHandle(shutdown_event);
|
||||
exit(0);
|
||||
}
|
||||
|
141
mysql-test/lib/My/SafeProcess/safe_process.pl
Normal file
141
mysql-test/lib/My/SafeProcess/safe_process.pl
Normal file
@ -0,0 +1,141 @@
|
||||
#!/usr/bin/perl
|
||||
# -*- cperl -*-
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Time::localtime;
|
||||
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){
|
||||
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();
|
||||
|
||||
use Getopt::Long;
|
||||
GetOptions(
|
||||
'verbose' => \$verbose,
|
||||
) or die "GetOptions failed";
|
||||
shift(@ARGV) if defined($ARGV[0]) and $ARGV[0] eq "--";
|
||||
my $path= shift(@ARGV); # Executable
|
||||
|
||||
die "usage:\n" .
|
||||
" safe_process.pl [opts] -- <path> [<args> [...<args_n>]]"
|
||||
unless defined $path;
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
312
mysql-test/lib/My/SafeProcess/safe_process_win.cc
Executable file
312
mysql-test/lib/My/SafeProcess/safe_process_win.cc
Executable file
@ -0,0 +1,312 @@
|
||||
/* Copyright (C) 2004 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
/*
|
||||
Utility program that encapsulates process creation, monitoring
|
||||
and bulletproof process cleanup
|
||||
|
||||
Usage:
|
||||
safe_process [options to safe_process] -- progname arg1 ... argn
|
||||
|
||||
To safeguard mysqld you would invoke safe_process with a few options
|
||||
for safe_process itself followed by a double dash to indicate start
|
||||
of the command line for the program you really want to start
|
||||
|
||||
$> safe_process --output=output.log -- mysqld --datadir=var/data1 ...
|
||||
|
||||
This would redirect output to output.log and then start mysqld,
|
||||
once it has done that it will continue to monitor the child as well
|
||||
as the parent.
|
||||
|
||||
The safe_process then checks the follwing things:
|
||||
1. Child exits, propagate the childs return code to the parent
|
||||
by exiting with the same return code as the child.
|
||||
|
||||
2. Parent dies, immediately kill the child and exit, thus the
|
||||
parent does not need to properly cleanup any child, it is handled
|
||||
automatically.
|
||||
|
||||
3. Signal's recieced by the process will trigger same action as 2)
|
||||
|
||||
4. The named event "safe_process[pid]" can be signaled and will
|
||||
trigger same action as 2)
|
||||
|
||||
WARNING! Be careful when using ProcessExplorer, since it will open
|
||||
a handle to each process(and maybe also the Job), the process
|
||||
spawned by safe_process will not be closed off when safe_process
|
||||
is killed.
|
||||
*/
|
||||
|
||||
/* Requires Windows 2000 or higher */
|
||||
#define _WIN32_WINNT 0x0500
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <signal.h>
|
||||
|
||||
static int verbose= 0;
|
||||
static char safe_process_name[32]= {0};
|
||||
|
||||
static void message(const char* fmt, ...)
|
||||
{
|
||||
if (!verbose)
|
||||
return;
|
||||
va_list args;
|
||||
fprintf(stderr, "%s: ", safe_process_name);
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
static void die(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
fprintf(stderr, "%s: FATAL ERROR, ", safe_process_name);
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
if (int last_err= GetLastError())
|
||||
fprintf(stderr, "error: %d, %s\n", last_err, strerror(last_err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
DWORD get_parent_pid(DWORD pid)
|
||||
{
|
||||
HANDLE snapshot;
|
||||
DWORD parent_pid= -1;
|
||||
PROCESSENTRY32 pe32;
|
||||
pe32.dwSize= sizeof(PROCESSENTRY32);
|
||||
|
||||
snapshot= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
die("CreateToolhelp32Snapshot failed");
|
||||
|
||||
if (!Process32First(snapshot, &pe32))
|
||||
{
|
||||
CloseHandle(snapshot);
|
||||
die("Process32First failed");
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (pe32.th32ProcessID == pid)
|
||||
parent_pid= pe32.th32ParentProcessID;
|
||||
} while(Process32Next( snapshot, &pe32));
|
||||
CloseHandle(snapshot);
|
||||
|
||||
if (parent_pid == -1)
|
||||
die("Could not find parent pid");
|
||||
|
||||
return parent_pid;
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
PARENT,
|
||||
CHILD,
|
||||
EVENT,
|
||||
NUM_HANDLES
|
||||
};
|
||||
|
||||
|
||||
HANDLE shutdown_event;
|
||||
void handle_signal (int signal)
|
||||
{
|
||||
message("Got signal: %d", signal);
|
||||
if(SetEvent(shutdown_event) == 0) {
|
||||
/* exit safe_process and (hopefully) kill off the child */
|
||||
die("Failed to SetEvent");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char** argv )
|
||||
{
|
||||
char child_args[4096]= {0};
|
||||
DWORD pid= GetCurrentProcessId();
|
||||
DWORD parent_pid= get_parent_pid(pid);
|
||||
HANDLE job_handle;
|
||||
HANDLE wait_handles[NUM_HANDLES]= {0};
|
||||
PROCESS_INFORMATION process_info= {0};
|
||||
|
||||
sprintf(safe_process_name, "safe_process[%d]", pid);
|
||||
|
||||
/* Create an event for the signal handler */
|
||||
if ((shutdown_event=
|
||||
CreateEvent(NULL, TRUE, FALSE, safe_process_name)) == NULL)
|
||||
die("Failed to create shutdown_event");
|
||||
wait_handles[EVENT]= shutdown_event;
|
||||
|
||||
signal(SIGINT, handle_signal);
|
||||
signal(SIGBREAK, handle_signal);
|
||||
signal(SIGTERM, handle_signal);
|
||||
|
||||
message("Started");
|
||||
|
||||
/* Parse arguments */
|
||||
for (int i= 1; i < argc; i++) {
|
||||
const char* arg= argv[i];
|
||||
char* to= child_args;
|
||||
if (strcmp(arg, "--") == 0 && strlen(arg) == 2) {
|
||||
/* Got the "--" delimiter */
|
||||
if (i >= argc)
|
||||
die("No real args -> nothing to do");
|
||||
/* Copy the remaining args to child_arg */
|
||||
for (int j= i+1; j < argc; j++) {
|
||||
to+= _snprintf(to, child_args + sizeof(child_args) - to, "%s ", argv[j]);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if ( strcmp(arg, "--verbose") == 0 )
|
||||
verbose++;
|
||||
else if ( strncmp(arg, "--parent-pid", 10) == 0 )
|
||||
{
|
||||
/* Override parent_pid with a value provided by user */
|
||||
const char* start;
|
||||
if ((start= strstr(arg, "=")) == NULL)
|
||||
die("Could not find start of option value in '%s'", arg);
|
||||
start++; /* Step past = */
|
||||
if ((parent_pid= atoi(start)) == 0)
|
||||
die("Invalid value '%s' passed to --parent-id", start);
|
||||
}
|
||||
else
|
||||
die("Unknown option: %s", arg);
|
||||
}
|
||||
}
|
||||
if (*child_args == '\0')
|
||||
die("nothing to do");
|
||||
|
||||
/* Open a handle to the parent process */
|
||||
message("parent_pid: %d", parent_pid);
|
||||
if (parent_pid == pid)
|
||||
die("parent_pid is equal to own pid!");
|
||||
|
||||
if ((wait_handles[PARENT]=
|
||||
OpenProcess(SYNCHRONIZE, FALSE, parent_pid)) == NULL)
|
||||
die("Failed to open parent process with pid: %d", parent_pid);
|
||||
|
||||
/* Create the child process in a job */
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
|
||||
STARTUPINFO si = { 0 };
|
||||
si.cb = sizeof(si);
|
||||
|
||||
/*
|
||||
Create the job object to make it possible to kill the process
|
||||
and all of it's children in one go
|
||||
*/
|
||||
if ((job_handle= CreateJobObject(NULL, NULL)) == NULL)
|
||||
die("CreateJobObject failed");
|
||||
|
||||
/*
|
||||
Make all processes associated with the job terminate when the
|
||||
last handle to the job is closed.
|
||||
*/
|
||||
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
if (SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation,
|
||||
&jeli, sizeof(jeli)) == 0)
|
||||
message("SetInformationJobObject failed, continue anyway...");
|
||||
|
||||
#if 0
|
||||
/* Setup stdin, stdout and stderr redirect */
|
||||
si.dwFlags= STARTF_USESTDHANDLES;
|
||||
si.hStdInput= GetStdHandle(STD_INPUT_HANDLE);
|
||||
si.hStdOutput= GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
si.hStdError= GetStdHandle(STD_ERROR_HANDLE);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Create the process suspended to make sure it's assigned to the
|
||||
Job before it creates any process of it's own
|
||||
*/
|
||||
if (CreateProcess(NULL, (LPSTR)child_args,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE, /* inherit handles */
|
||||
CREATE_SUSPENDED,
|
||||
NULL,
|
||||
NULL,
|
||||
&si,
|
||||
&process_info) == 0)
|
||||
die("CreateProcess failed");
|
||||
|
||||
if (AssignProcessToJobObject(job_handle, process_info.hProcess) == 0)
|
||||
{
|
||||
TerminateProcess(process_info.hProcess, 200);
|
||||
die("AssignProcessToJobObject failed");
|
||||
}
|
||||
ResumeThread(process_info.hThread);
|
||||
CloseHandle(process_info.hThread);
|
||||
|
||||
wait_handles[CHILD]= process_info.hProcess;
|
||||
|
||||
message("Started child %d", process_info.dwProcessId);
|
||||
|
||||
/* Monitor loop */
|
||||
DWORD child_exit_code= 1;
|
||||
DWORD wait_res= WaitForMultipleObjects(NUM_HANDLES, wait_handles,
|
||||
FALSE, INFINITE);
|
||||
switch (wait_res)
|
||||
{
|
||||
case WAIT_OBJECT_0 + PARENT:
|
||||
message("Parent exit");
|
||||
break;
|
||||
case WAIT_OBJECT_0 + CHILD:
|
||||
if (GetExitCodeProcess(wait_handles[CHILD], &child_exit_code) == 0)
|
||||
message("Child exit: could not get exit_code");
|
||||
else
|
||||
message("Child exit: exit_code: %d", child_exit_code);
|
||||
break;
|
||||
case WAIT_OBJECT_0 + EVENT:
|
||||
message("Wake up from shutdown_event");
|
||||
break;
|
||||
|
||||
default:
|
||||
message("Unexpected result %d from WaitForMultipleObjects", wait_res);
|
||||
break;
|
||||
}
|
||||
message("Exiting, child: %d", process_info.dwProcessId);
|
||||
|
||||
if (TerminateJobObject(job_handle, 201) == 0)
|
||||
message("TerminateJobObject failed");
|
||||
CloseHandle(job_handle);
|
||||
|
||||
if (wait_res != WAIT_OBJECT_0 + CHILD)
|
||||
{
|
||||
/* The child has not yet returned, wait for it */
|
||||
message("waiting for child to exit");
|
||||
if ((wait_res= WaitForSingleObject(wait_handles[CHILD], INFINITE)) != WAIT_OBJECT_0)
|
||||
{
|
||||
message("child wait failed: %d", wait_res);
|
||||
}
|
||||
else
|
||||
{
|
||||
message("child wait succeeded");
|
||||
}
|
||||
/* Child's exit code should now be 201, no need to get it */
|
||||
}
|
||||
|
||||
for (int i= 0; i < NUM_HANDLES; i++)
|
||||
CloseHandle(wait_handles[i]);
|
||||
|
||||
exit(child_exit_code);
|
||||
}
|
||||
|
Reference in New Issue
Block a user