Subject: | ProcessTable misreports certain children PIDs on Cygwin |
Hello!
Proc::ProcessTable Ver. 0.39 misreports certain PIDs in the Cygwin environment. Specifically, when a forked Perl subprocess starts another child process using backticks, it misreports the WINPID of the child as the Cygwin PID. I can consistently reproduce the bug with the attached testcase: timeout_test3.pl. This bug causes follow-on bugs in software that uses ProcessTable, for eg: Proc::Killfam which is shown in the testcase).
Here are the results of running the testcase on linux and cygwin:
1. When the testcase was run on Linux RHAS 2.1, both 'ps' and Proc::ProcessTable reported the same PID for the 'sleep' process, which is correct:
-----------------------------------
'ps' reported the following about the 'sleep' process:
PID TTY TIME CMD
1624 pts/3 00:00:00 sleep
'Proc::ProcessTable' reports the following about it:
PID=1624 PPID=1623 Command=sleep
-----------------------------------
2. When the testcase was run on the latest Cygwin (ver. 1.5.16-1), 'ps' and Proc::ProcessTable report different PIDs for the 'sleep' process. ProcessTable misreported the WINPID as the PID, and also misreported it's PPID as 0:
-----------------------------------
'ps' reported the following about the 'sleep' process:
PID PPID PGID WINPID TTY UID STIME COMMAND
2432 2164 3284 3656 con 400 14:23:21 /usr/bin/sleep
'Proc::ProcessTable' reports the following about it:
PID=3656 PPID=0 Command=C:\cygwin\bin\sleep.exe
-----------------------------------
This problem occurs on the latest Cygwin distribution. I'm running Perl on Cygwin on Windows XP SP2. Running 'cygcheck -c' gives the following package status for cygwin and Perl:
--------------------------
cygwin 1.5.16-1 OK
perl 5.8.6-4 OK
--------------------------
The Cygwin version reported by cygcheck is Ver. 1.5.16-1. The 'uname -a' output reported is:
------------
$ uname -a
CYGWIN_NT-5.1 WNN11467 1.5.16(0.128/4/2) 2005-04-25 20:26 i686 unknown unknown Cygwin
------------
Perl Version:
--------------
$ perl -v
This is perl, v5.8.6 built for cygwin-thread-multi-64int
--------------
I originally reported this on the Cygwin mailing list [1] where Reini Urban advised I could report this as a bug here.
Regards,
Sonam Chauhan
[1] http://sourceware.org/ml/cygwin/2005-05/threads.html#00427
#!/usr/bin/perl
use Proc::Killfam;
use Proc::ProcessTable;
use Data::Dumper;
#This is a demonstrator program to show a bug in Proc::ProcessTable in Cygwin
# This program works normally on RHAS Linux 2.1, On Cygwin 1.5.16-1 on windows XP,
# different PIDs are reported for the sleep process by ps and Proc::ProcessTable.
# Cygwin Proc::ProcessTable incorrectly reports the WINPID as the PID (instead of the
# Cygwin PID). It also reports the PPID of 'sleep' as 0 - it should be the Perl process that called `sleep`.
#Alarm Signal Handler - reports on the sleep PID, then tries to kills the child and its descendants
$SIG{ALRM} = sub {
print "$$: woke up after $timeout seconds. Will report on sleep PIDs, then kill child $childpid and it's family\n";
# First, print ps's version of the 'sleep' process PID
$ps_output = `/bin/ps`;
$ps_output =~ /^(\s*PID.+)$/m;
$ps_first_line = $1;
$ps_output =~ /^(.+sleep)$/m;
$ps_sleep_line = $1;
print "'ps' reported the following about the 'sleep' process:\n";
print "$ps_first_line\n";
print "$ps_sleep_line\n";
# Next, print Proc::ProcessTable's information about the same process
# Note, this will print info for all 'sleep' processes currently running on the system
$p = new Proc::ProcessTable();
foreach $p ( @{$p->table} )
{
if ($p->fname =~ /sleep/) {
print "'Proc::ProcessTable' reports the following about it:\n";
#print "\tPID=".$p->pid."\tPPID=".$p->ppid."\tPGID=".$p->pgid."\tWINPID=".$p->winpid."\tCommand=".$p->fname."\n";
print "\tPID=".$p->pid."\tPPID=".$p->ppid."\tCommand=".$p->fname."\n";
}
}
# Now try to kill the child process and all it's subchildren - this should include the 'sleep' process
# However, on Perl/Cygwin, the sleep process is not killed
killfam 'KILL', $childpid;
};
# Main routine - sets alarm and forks child to start a blocking `sleep`
sub timeout_test {
print "Starting... my own PID=$$\n";
$timeout =3;
$childpid = fork();
if ($childpid > 0) { # this is the parent process - wait for children to die
print "$$: Forked child $childpid. Set alarm for $timeout seconds\n";
alarm $timeout;
do {
$kid = waitpid (-1, 0);
} until $kid == -1;
exit;
}
$s = `/bin/sleep 7`;
print "Sleep ended with returned text: $s";
}
# Kick it all off
timeout_test();