Change 34091 by [EMAIL PROTECTED] on 2008/06/28 20:37:32

        Subject: [PATCH-revised^6] common test code for timed bail
        From: "Jerry D. Hedden" <[EMAIL PROTECTED]>
        Date: Sat, 28 Jun 2008 15:18:48 -0400
        Message-ID: <[EMAIL PROTECTED]>

Affected files ...

... //depot/perl/pod/perltodo.pod#232 edit
... //depot/perl/t/test.pl#79 edit

Differences ...

==== //depot/perl/pod/perltodo.pod#232 (text) ====
Index: perl/pod/perltodo.pod
--- perl/pod/perltodo.pod#231~33896~    2008-05-21 02:18:00.000000000 -0700
+++ perl/pod/perltodo.pod       2008-06-28 13:37:32.000000000 -0700
@@ -30,12 +30,6 @@
 into a file, change it to build an C<%Is> hash and require it.  Maybe just put
 it into F<test.pl>. Throw in the handy tainting subroutines.
 
-=head2 common test code for timed bail out
-
-Write portable self destruct code for tests to stop them burning CPU in
-infinite loops. This needs to avoid using alarm, as some of the tests are
-testing alarm/sleep or timers.
-
 =head2 POD -E<gt> HTML conversion in the core still sucks
 
 Which is crazy given just how simple POD purports to be, and how simple HTML

==== //depot/perl/t/test.pl#79 (text) ====
Index: perl/t/test.pl
--- perl/t/test.pl#78~32801~    2008-01-02 04:01:29.000000000 -0800
+++ perl/t/test.pl      2008-06-28 13:37:32.000000000 -0700
@@ -781,4 +781,106 @@
     _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;
End of Patch.

Reply via email to