The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package t::Watchdog;

use strict;

use Config;
use Test::More;

my $waitfor = 360; # 30-45 seconds is normal (load affects this).
my $watchdog_pid;
my $TheEnd;

if ($Config{d_fork}) {
    note "I am the main process $$, starting the watchdog process...";
    $watchdog_pid = fork();
    if (defined $watchdog_pid) {
	if ($watchdog_pid == 0) { # We are the kid, set up the watchdog.
	    my $ppid = getppid();
	    note "I am the watchdog process $$, sleeping for $waitfor seconds...";
	    sleep($waitfor - 2);    # Workaround for perlbug #49073
	    sleep(2);               # Wait for parent to exit
	    if (kill(0, $ppid)) {   # Check if parent still exists
		warn "\n$0: overall time allowed for tests (${waitfor}s) exceeded!\n";
		note "Terminating main process $ppid...";
		kill('KILL', $ppid);
		note "This is the watchdog process $$, over and out.";
	    }
	    exit(0);
	} else {
	    note "The watchdog process $watchdog_pid launched, continuing testing...";
	    $TheEnd = time() + $waitfor;
	}
    } else {
	warn "$0: fork failed: $!\n";
    }
} else {
    note "No watchdog process (need fork)";
}

END {
    if ($watchdog_pid) { # Only in the main process.
	my $left = $TheEnd - time();
	note sprintf "I am the main process $$, terminating the watchdog process $watchdog_pid before it terminates me in %d seconds (testing took %d seconds).", $left, $waitfor - $left;
	if (kill(0, $watchdog_pid)) {
	    local $? = 0;
	    my $kill = kill('KILL', $watchdog_pid); # We are done, the watchdog can go.
	    wait();
	    note sprintf "kill KILL $watchdog_pid = %d", $kill;
	}
	unlink("ktrace.out"); # Used in BSD system call tracing.
	note "All done.";
    }
}

1;