monotone

monotone Commit Details

Date:2009-07-07 18:10:52 (9 years 10 months ago)
Author:Tony Cooper
Branch:net.venge.monotone.contrib.lib.automate-stdio
Commit:5af35bcd8cad5741a2e924c5cda83ffcc3bd28d6
Parents: 5d6b88e48e877ce680168756043ac728da5a38ff
Message:- Corrected the use of IO::Poll's mask method and added POLLHUP to the mask.

- Now much more explicit in handling the reaping of subprocesses and much more
robust in the face of a subprocess that won't die.
- Now test for the presence of exceptions by using a simple boolean test.
- Now cope with open3() throwing exceptions whilst inside the child process.
Changes:
Mlib/Monotone/AutomateStdio.pm (10 diffs)

File differences

lib/Monotone/AutomateStdio.pm
6262
6363
6464
65
65
6666
6767
6868
......
101101
102102
103103
104
105
106
107
104108
105109
106110
......
28372841
28382842
28392843
2840
2841
2842
2843
28442844
28452845
2846
2847
2848
2849
28462850
28472851
28482852
2849
2853
2854
2855
2856
28502857
2851
28522858
2853
2854
2859
28552860
2861
2862
2863
2864
2865
28562866
28572867
28582868
28592869
2860
2870
28612871
2862
2872
28632873
28642874
2875
2876
2877
28652878
2866
2879
2880
2881
2882
28672883
28682884
28692885
2870
2886
2887
2888
2889
2890
28712891
28722892
28732893
2894
2895
2896
2897
28742898
28752899
28762900
......
28782902
28792903
28802904
2881
2905
2906
2907
2908
28822909
2883
2884
2885
2886
2887
2888
2910
28892911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
28902924
2925
28912926
28922927
2928
28932929
28942930
28952931
......
40094045
40104046
40114047
4012
4048
40134049
40144050
40154051
......
42124248
42134249
42144250
4215
4251
42164252
42174253
42184254
......
42574293
42584294
42594295
4260
4261
4262
4263
4264
42654296
42664297
42674298
4299
4300
4301
4302
4303
4304
42684305
42694306
42704307
......
42924329
42934330
42944331
4332
42954333
42964334
42974335
......
43104348
43114349
43124350
4313
43144351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
43154379
43164380
4317
4318
4381
43194382
43204383
43214384
......
43254388
43264389
43274390
4328
4391
43294392
43304393
43314394
use File::Basename;
use File::Spec;
use IO::File;
use IO::Poll qw(POLLIN POLLPRI);
use IO::Poll qw(POLLHUP POLLIN POLLPRI);
use IPC::Open3;
use POSIX qw(:errno_h);
use Symbol qw(gensym);
use constant MTN_SEVERITY_ERROR => 0x01;
use constant MTN_SEVERITY_WARNING => 0x02;
# Constant used to represent the exception thrown when interrupting waitpid().
use constant WAITPID_INTERRUPT => __PACKAGE__ . "::waitpid-interrupt";
# Constants used to represent different value formats.
use constant BARE_PHRASE => 0x01; # E.g. orphaned_directory.
my $this = $_[0];
my($err_msg,
$i,
$ret_val);
if ($this->{mtn_pid} != 0)
{
# Close off all file descriptors to the mtn subprocess. This should be
# enough to cause it to exit gracefully.
close($this->{mtn_in});
close($this->{mtn_out});
close($this->{mtn_err});
for ($i = 0; $i < 3; ++ $i)
# Reap the mtn subprocess and deal with any errors.
for (my $i = 0; $i < 4; ++ $i)
{
$ret_val = 0;
# Make sure that the eval block below does not affect any existing
# exception status.
my $wait_status = 0;
# Wait for the mtn subprocess to exit (preserving the current state
# of $@ so that any exception that has already occurred is not
# lost, also ignore any errors resulting from waitpid()
# interruption).
{
local $@;
eval
{
local $SIG{ALRM} = sub { die("internal sigalarm"); };
local $SIG{ALRM} = sub { die(WAITPID_INTERRUPT); };
alarm(5);
$ret_val = waitpid($this->{mtn_pid}, 0);
$wait_status = waitpid($this->{mtn_pid}, 0);
alarm(0);
};
$wait_status = 0
if ($@ eq WAITPID_INTERRUPT && $wait_status < 0
&& $! == EINTR);
}
if ($ret_val == $this->{mtn_pid})
# The mtn subprocess has terminated.
if ($wait_status == $this->{mtn_pid})
{
last;
}
elsif ($ret_val == 0)
# The mtn subprocess is still there so try and kill it unless it's
# time to just give up.
elsif ($i < 3 && $wait_status == 0)
{
if ($i == 0)
{
kill("INT", $this->{mtn_pid});
}
elsif ($i == 1)
{
kill("TERM", $this->{mtn_pid});
}
else
kill("KILL", $this->{mtn_pid});
}
}
else
# Stop if we don't have any relevant children to wait for anymore.
elsif ($wait_status < 0 && $! == ECHILD)
{
if ($! != ECHILD)
{
$err_msg = $!;
kill("KILL", $this->{mtn_pid});
&$croaker("waitpid failed: $err_msg");
}
last;
}
# Either there is some other error with waitpid() or a child
# process has been reaped that we aren't interested in (in which
# case just ignore it).
elsif ($wait_status < 0)
{
my $err_msg = $!;
kill("KILL", $this->{mtn_pid});
&$croaker("waitpid failed: " . $err_msg);
}
}
$this->{poll} = undef;
$this->{mtn_pid} = 0;
}
}
$$buffer_ref = decode_utf8($$buffer_ref) if ($in_as_utf8);
};
$exception = $@;
if ($exception ne "")
if ($exception)
{
if ($exception =~ m/$database_locked_re/)
{
$size,
$offset)))
{
croak("sysread failed: $!");
croak("sysread failed: " . $!);
}
$size -= $bytes_read;
$offset += $bytes_read;
my $this = $_[0];
my(@args,
$cwd,
$err,
$version);
if ($this->{mtn_pid} == 0)
{
my(@args,
$cwd,
$err,
$my_pid,
$version);
# Switch to the default locale. We only want to parse the output from
# Monotone in one language!
# feature if it wishes to do so).
$cwd = getcwd();
$my_pid = $$;
eval
{
if (defined($this->{db_name}))
};
$err = $@;
chdir($cwd);
&$croaker($err) if ($err ne "");
# Check for errors (remember that open3() errors can happen in both the
# parent and child processes).
if ($err)
{
if ($$ != $my_pid)
{
# In the child process so all we can do is complain and exit.
print(STDERR "open3 failed: " . $err);
exit(1);
}
else
{
# In the parent process so deal with the error in the usual
# way.
&$croaker($err);
}
}
# Ok so reset the command count and setup polling.
$this->{cmd_cnt} = 0;
$this->{poll} = IO::Poll->new();
$this->{poll}->mask($this->{mtn_out} => POLLIN,
$this->{mtn_out} => POLLPRI);
$this->{poll}->mask($this->{mtn_out}, POLLIN | POLLPRI | POLLHUP);
# Get the interface version.
# If necessary get the version of the actual application (sometimes
# needed to differentiate when certain features were introduced that do
# not affect the automate stdio interface version.
# not affect the automate stdio interface version).
if ($this->{mtn_aif_major} == 9)
{

Archive Download the corresponding diff file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status