summaryrefslogtreecommitdiff
path: root/t/test.pl
diff options
context:
space:
mode:
authorJerry D. Hedden <jdhedden@cpan.org>2008-06-28 11:18:48 -0400
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>2008-06-28 20:37:32 +0000
commit087986a76c08e8dfaaee54f8f476bfa315216671 (patch)
tree3e0c2ec8d850948514ec10198bf8323a8eb02642 /t/test.pl
parent280cf07eab629d0d4801176eedac7fefa4afecc7 (diff)
downloadperl-087986a76c08e8dfaaee54f8f476bfa315216671.tar.gz
common test code for timed bail
From: "Jerry D. Hedden" <jdhedden@cpan.org> Message-ID: <1ff86f510806281218i65d32061w27a4431b9b357107@mail.gmail.com> p4raw-id: //depot/perl@34091
Diffstat (limited to 't/test.pl')
-rw-r--r--t/test.pl102
1 files changed, 102 insertions, 0 deletions
diff --git a/t/test.pl b/t/test.pl
index 9b896f7341..2caf2e89a2 100644
--- a/t/test.pl
+++ b/t/test.pl
@@ -781,4 +781,106 @@ WHOA
_ok( !$diag, _where(), $name );
}
+# Set a watchdog to timeout the entire test file
+sub watchdog ($)
+{
+ my $timeout = shift;
+ my $timeout_msg = 'Test process timed out - terminating';
+
+ my $pid_to_kill = $$; # PID for this process
+
+ # On Windows and VMS, try launching a watchdog process
+ # using system(1, ...) (see perlport.pod)
+ if (($^O eq 'MSWin32') || ($^O eq 'VMS')) {
+ # On Windows, try to get the 'real' PID
+ if ($^O eq 'MSWin32') {
+ eval { require Win32; };
+ if (defined(&Win32::GetCurrentProcessId)) {
+ $pid_to_kill = Win32::GetCurrentProcessId();
+ }
+ }
+
+ # If we still have a fake PID, we can't use this method at all
+ return if ($pid_to_kill <= 0);
+
+ # Launch watchdog process
+ my $watchdog;
+ eval {
+ local $SIG{'__WARN__'} = sub {};
+ $watchdog = system(1, $^X, '-e', "sleep($timeout);" .
+ "kill('KILL', $pid_to_kill);");
+ };
+
+ # If the above worked, add END block to parent
+ # to clean up watchdog process
+ if (! $@ && ($watchdog > 0)) {
+ eval "END { kill('KILL', $watchdog); }";
+ }
+ return;
+ }
+
+
+ # Try using fork() to generate a watchdog process
+ my $watchdog;
+ eval { $watchdog = fork() };
+ if (defined($watchdog)) {
+ if ($watchdog) { # Parent process
+ # Add END block to parent to clean up watchdog process
+ eval "END { kill('KILL', $watchdog); }";
+ return;
+ }
+
+ ### Watchdog process code
+
+ # Load POSIX if available
+ eval { require POSIX; };
+
+ # Execute the timeout
+ sleep($timeout - 2) if ($timeout > 2); # Workaround for perlbug #49073
+ sleep(2);
+
+ # Kill test process if still running
+ if (kill(0, $pid_to_kill)) {
+ _diag($timeout_msg);
+ kill('KILL', $pid_to_kill);
+ }
+
+ # Terminate ourself (i.e., the watchdog)
+ POSIX::_exit(1) if (defined(&POSIX::_exit));
+ exit(1);
+ }
+
+ # fork() failed - try a thread
+ if (eval { require threads; }) {
+ threads->create(sub {
+ # Load POSIX if available
+ eval { require POSIX; };
+
+ # Execute the timeout
+ sleep($timeout);
+
+ # Kill the parent (and ourself)
+ _diag($timeout_msg);
+ POSIX::_exit(1) if (defined(&POSIX::_exit));
+ kill('KILL', $pid_to_kill);
+ })->detach();
+ return;
+ }
+
+ # Threads failed, too - try use alarm()
+
+ # Try to set the timeout
+ if (eval { alarm($timeout); 1; }) {
+ # Load POSIX if available
+ eval { require POSIX; };
+
+ # Alarm handler will do the actual 'killing'
+ $SIG{'ALRM'} = sub {
+ _diag($timeout_msg);
+ POSIX::_exit(1) if (defined(&POSIX::_exit));
+ kill('KILL', $pid_to_kill);
+ };
+ }
+}
+
1;