Skip to content
Closed
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 38 additions & 37 deletions t/test.pl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
our $TODO = 0;
our $NO_ENDING = 0;
our $Tests_Are_Passing = 1;
our @watchdog_threads_;

# Use this instead of print to avoid interference while testing globals.
sub _print {
Expand Down Expand Up @@ -1834,8 +1835,7 @@ sub warning_like {
# NOTE: If the test file uses 'threads', then call the watchdog() function
# _AFTER_ the 'threads' module is loaded.
{ # Closure
my $watchdog;
my $watchdog_thread;
my $cancel_string;

sub watchdog ($;$)
{
Expand All @@ -1844,29 +1844,18 @@ ($;$)
# If cancelling, use the state variables to know which method was used to
# create the watchdog.
if ($timeout == 0) {
if ($watchdog_thread) {
$watchdog_thread->kill('KILL');
undef $watchdog_thread;
}
elsif ($watchdog) {
kill('KILL', $watchdog);
undef $watchdog;
}
else {
alarm(0);
}

eval $cancel_string if defined $cancel_string;
return;
}

# Make sure these aren't defined.
undef $watchdog;
undef $watchdog_thread;

my $method = shift || "";

my $timeout_msg = 'Test process timed out - terminating';

# Common to all cancellation types; HERE gets replaced below by the
# individual code
$cancel_string = 'local $! = 0; local $? = 0; HERE; undef $cancel_string';

# Accept either spelling
my $timeout_factor = $ENV{PERL_TEST_TIME_OUT_FACTOR}
|| $ENV{PERL_TEST_TIMEOUT_FACTOR}
Expand All @@ -1888,9 +1877,13 @@ ($;$)
# shut up use only once warning
my $threads_on = $threads::threads && $threads::threads;

# Don't use a watchdog process if 'threads' is loaded -
# use a watchdog thread instead
if (!$threads_on || $method eq "process") {
# Use a watchdog process unless 'threads' is loaded and is killable by a
# signal
if ( ! $threads_on
|| (defined $ENV{PERL_SIGNALS} && $ENV{PERL_SIGNALS} eq "unsafe")
|| $method eq "process")
{
my $watchdog;

# On Windows and VMS, try launching a watchdog process
# using system(1, ...) (see perlport.pod). system() returns
Expand All @@ -1909,7 +1902,6 @@ ($;$)
return if ($pid_to_kill <= 0);

# Launch watchdog process
undef $watchdog;
eval {
local $SIG{'__WARN__'} = sub {
_diag("Watchdog warning: $_[0]");
Expand Down Expand Up @@ -1950,22 +1942,21 @@ ($;$)
return;
}

# Add END block to parent to terminate and
# clean up watchdog process
eval("END { local \$! = 0; local \$? = 0;
wait() if kill('KILL', $watchdog); };");
# Add END block to parent to terminate and clean up watchdog
# process
$cancel_string =~ s/HERE/wait() if kill('KILL', $watchdog)/;
eval("END { $cancel_string };");
return;
}

# Try using fork() to generate a watchdog process
undef $watchdog;
eval { $watchdog = fork() };
if (defined($watchdog)) {
if ($watchdog) { # Parent process
# Add END block to parent to terminate and
# clean up watchdog process
eval "END { local \$! = 0; local \$? = 0;
wait() if kill('KILL', $watchdog); };";
# Add END block to parent to terminate and clean up watchdog
# process
$cancel_string =~ s/HERE/wait() if kill('KILL', $watchdog)/;
eval("END { $cancel_string };");
return;
}

Expand Down Expand Up @@ -2000,10 +1991,12 @@ ($;$)
# fork() failed - fall through and try using a thread
}

# Use a watchdog thread because either 'threads' is loaded,
# or fork() failed
# Use a watchdog thread because either 'threads' is loaded, or fork()
# failed
if (eval {require threads; 1}) {
$watchdog_thread = 'threads'->create(sub {

# Use an array so can handle multiple timers
push @watchdog_threads_, 'threads'->create(sub {
# Load POSIX if available
eval { require POSIX; };

Expand All @@ -2027,20 +2020,25 @@ ($;$)
kill($sig, $pid_to_kill);
});

#my $index = scalar @watchd
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment here seems leftover

$cancel_string =~ s/HERE/\$watchdog_threads_[$#watchdog_threads_]->kill('KILL')/;
eval "END { $cancel_string }";

# Don't proceed until the watchdog has set up its signal handler.
# (Otherwise there is a possibility that we will exit with threads
# running.) The watchdog tells us that the handler is set by
# detaching itself. (The 'is_running()' is a fail-safe.)
while ( $watchdog_thread->is_running()
&& ! $watchdog_thread->is_detached())
while ( $watchdog_threads_[-1]->is_running()
&& ! $watchdog_threads_[-1]->is_detached())
{
'threads'->yield();
}

return;
}

# If everything above fails, then just use an alarm timeout
# If everything above fails, then just use an alarm timeout. There can
# only be one in effect at a time. This cancels any previous one.
WATCHDOG_VIA_ALARM:
if (eval { alarm($timeout); 1; }) {
# Load POSIX if available
Expand All @@ -2054,6 +2052,9 @@ ($;$)
my $sig = $is_vms ? 'TERM' : 'KILL';
kill($sig, $pid_to_kill);
};

$cancel_string =~ s/HERE/alarm(0)/;
eval "END { $cancel_string }";
}
}
} # End closure
Expand Down