4

I have a small python script, that essentially looks like the following:

import os
import psutil

def processtree():
    pid = os.getpid()
    # have to go two levels up to skip calling shell and 
    # get to actual parent process
    parent = psutil.Process(pid).parent().parent()

    print 'Parent %s [PID = %d]' % (parent.name(), parent.pid)
    print '        |'
    for child in parent.children(recursive=True):
        if child.pid != pid:
            print '        - Child %s [PID = %d]' % (child.name(), child.pid)
        else:
            print '        - Child %s [PID = %d] (Self)' % (child.name(), child.pid)

if '__name__' == '__main__':
    processtree()

When I run this script in bash on Windows, with nothing else running, I see the following:

Parent bash.exe [PID = 5984]
       |
       - Child bash.exe [PID = 5008]
       |
       - Child python.exe [PID = 3736] (Self)

This information is correct. The parent bash process is PID 5984, and the python process is 3736. Now, I run sleep 10000 & so that it is running as a child of the PID 5984. I check ps -aef | grep 5984 and it is there;:

$ ps -aef | grep 5984 | grep -v grep | grep -v ps
myuser    5984       1 con    May 12 /bin/bash
myuser    5080    5984 con  11:17:12 /bin/sleep
myuser    3948    5984 con  11:36:47 /bin/bash

However, when I run my script again, it still shows:

Parent bash.exe [PID = 5984]
       |
       - Child bash.exe [PID = 7560]
       |
       - Child python.exe [PID = 5168] (Self)

It does not show sleep as a child of the parent bash process, even though ps is showing it as present.

Note that the PID for the bash.exe child has changed since a new calling shell was created (not sure why this happens, but I don't think it's related). The PID of the python interpreter because I called the script again python processtree.py.

Not sure what I'm doing wrong, and I've been staring at this for a while. Any help is appreciated...

Sagar
  • 9,456
  • 6
  • 54
  • 96
  • Actually I think the intervening `bash` process is the problem. Since `sleep` was run as a background process its immediate parent shell has probably exited. That leaves no way for psutil to build a tree because there's no connection in Windows between the grandparent `bash` process and `sleep`. A Windows process only records the ID of its parent, and the Windows subsystem server (`csrss.exe`) doesn't maintain a Unix-style process tree. On the other hand, Cygwin does maintain a process tree. – Eryk Sun May 14 '15 at 02:49
  • Oh ok. In `ps`, when I saw the grandparent bash shell as the parent PID, I figured it was the direct parent process of sleep. I'll see if I can run it in a Cygwin shell or on a Unix machine. Thanks @eryksun. – Sagar May 14 '15 at 19:09
  • In Unix the combination of `fork` and `exec` causes the 2nd `bash` process to be replaced by `sleep`. Thus you'll need to instead use `parent = psutil.Process(pid).parent()`. Windows is based on the spawn model of creating processes, which is a legacy inherited from DEC VMS. (Dave Cutler managed the design of both VMS and NT. A lot of former DEC engineers followed him to Microsoft in 1988.) The NT kernel actually can implement `fork` and `exec`, which it does for the [SUA subsystem](https://technet.microsoft.com/en-us/library/cc772343.aspx). – Eryk Sun May 14 '15 at 20:57
  • @eryksun that was exactly it. Would you post your comment as an answer, so I can accept it? Thank you so much! – Sagar May 28 '15 at 13:24

1 Answers1

3

Posting from comments so others don't see this as an unanswered open question

You'll need to instead use parent = psutil.Process(pid).parent().

In Unix the combination of fork and exec causes the 2nd bash process to be replaced by sleep.

Windows is based on the spawn model of creating processes, which is a legacy inherited from DEC VMS. (Dave Cutler managed the design of both VMS and NT. A lot of former DEC engineers followed him to Microsoft in 1988.) The NT kernel actually can implement fork and exec, which it does for the SUA subsystem.

rocky
  • 7,226
  • 3
  • 33
  • 74