I have seen Windows do some strange things from time to time, but I
would not expect it to re-parent explorer.exe.
Nevertheless, subprocesses can be a little tricky. It appears that when
Windows starts a process, it records as the parent the PID of the
process that started it. Now, when a process exits, its subprocesses do
not go away, and they continue to think the "dead" process is their
parent. You could say they are orphans but do not know it.
Worse than that, Windows re-uses process IDs, so if you go on PID alone
(which I think Subprocesses() does), you can think that a new process
having the same PID as the old process is your parent, when it really is
not.
Now, Subprocesses() simply walks through the system getting a list of
PIDs and their parents, and matches them up. To get the true
subprocesses, you should compare the start time of the parent to the
start time of the subprocess, and reject any subprocesses that started
before the parent. In fact, Subprocesses() should probably do this, but
I just found out that was an issue.
I do not understand how this mechanism could make explorer.exe appear to
be a subprocess of your service, but it is a fact that, at the point you
say the script goes wrong, you have explorer.exe with ProcessId 2292,
CreationDate of 1211364961 (= Wed May 21 10:16:01 2008 UT), and
ParentProcessId of 2188, though ProcessId 2188 is cmd.exe, started at
CreationDate 1211370389 (= Wed May 21 11:46:29 2008 UT). So explorer.exe
is clearly not a subprocess of cmd.exe, no matter what the PIDs say.
So although I do not completely understand what is going on in your
system, I do have some recommendations:
Recommendation: Try comparing the CreationDate of the parent process to
the CreationDate of the subprocess, and ignoring those apparent
subprocesses that started before their parent processes. Please let me
know if this helps. I may be able to develop a patch to Subprocesses()
without Windows, since all it does is to match up process IDs. I will
have to see what information is available in Subprocesses() to know what
I can do in this area.
Recommendation: There are system explorers (or whatever you call them)
available that will give you a process hierarchy. There used to be an
outfit called "System Internals" that had a program called "Process
Explorer" that would do this for you. Currently their url redirects to
http://technet.microsoft.com/en-us/sysinternals/default.aspx but
"Process Explorer" still seems to be available. If there is some
question about who is whose parent process, something like this would be
helpful.
Recommendation: If you could recode updateMemoryUsageStat() so that the
calls to Subprocess() and GetProcInfo() were outside the "for" loop, the
script that contains updateMemoryUsageStat() might run longer. This
might complicate matters inside the loop a little, but you might get
away with something like
# Get the subprocess tree of the whole system.
my $subprocs = $pi->Subprocesses();
# Make a hash for all the processes, keyed on PID
my %proc_inf = map {$_->{ProcessId}, $_} $pi->GetProcInfo();
outside the loop, and then
# Get all subprocesses of $task->{PID) (if that's what this does.
my @procList = subprocessList($task->{PID}, $subprocs);
# Get the process information for the desired processes.
my @procsInfo = map {$proc_inf{$_}} @procList;
The above assumes (at least!) that your subprocessList() does not care
if there are extra items passed in the hash that is the second argument.
I should have recommended this in response to the previous bug, but I
confess that it was not until this bug that I investigated your sample
code that thoroughly.