Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Child processes #78

Closed
Nukesor opened this issue May 29, 2020 · 6 comments · Fixed by #80
Closed

Child processes #78

Nukesor opened this issue May 29, 2020 · 6 comments · Fixed by #80

Comments

@Nukesor
Copy link
Contributor

Nukesor commented May 29, 2020

Hi!

First of all, thanks for providing this library! I'm currently looking for a nice solution to get all child processes of a specific process. After looking at psutil and procfs, I found that procfs is a lot cleaner and definitely better documented! Your library certainly deserves more attention :)

I would like to add the feature for Process::children() and it would be awesome to get a short introduction or a few tips on how to approach this.

Another thing I'm thinking about is, whether it should only be Process::children_ids() plus another function Process::children(), which actually returns a vector of Process.

@eminence
Copy link
Owner

Hello! Thanks for the kind words about procfs!

Getting a list of child processes for one process is pretty simple. Here's how you can get all the direct children of PID1:

    for child in all_processes()
        .unwrap()
        .into_iter()
        .filter(|p| p.stat.ppid == 1)
    {
        println!("{} {}", child.pid, child.stat.comm);
    }

But this will only get you the direct children. If you want a list of all children, you need a slightly different approach. One way to do this is to keep a HashMap that maps a PID to all its children PIDs:

    let mut map = HashMap::<i32, Vec<i32>>::new();
    for proc in all_processes().unwrap() {
        map.entry(proc.stat.ppid).or_default().push(proc.pid);
    }

Then if you wanted a list of all children of some_pid in a flat list, you could do something like:

    fn get_children_recursive(child_map: &HashMap<i32, Vec<i32>>, pid: i32) -> Vec<i32> {
        let mut children: Vec<i32> = child_map.get(&pid).cloned().unwrap_or_default();

        for child in children.clone() {
            children.extend(get_children_recursive(child_map, child));
        }

        children
    }

    let all_children = get_children_recursive(&map, some_pid);

For your own purposes, does this look like it would work for you?

@Nukesor
Copy link
Contributor Author

Nukesor commented May 29, 2020

This would definitely work :)
I just thought, that it would be more convenient to directly use the proc(5) feature for children.
This doesn't require iterating through all processes and allows instant lookup:

      /proc/[pid]/task/[tid]/children (since Linux 3.5)
              A space-separated list of child tasks of this task.  Each
              child task is represented by its TID.

              This option is intended for use by the checkpoint-restore
              (CRIU) system, and reliably provides a list of children only
              if all of the child processes are stopped or frozen.  It does
              not work properly if children of the target task exit while
              the file is being read!  Exiting children may cause non-exit‐
              ing children to be omitted from the list.  This makes this
              interface even more unreliable than classic PID-based
              approaches if the inspected task and its children aren't
              frozen, and most code should probably not use this interface.

              Until Linux 4.2, the presence of this file was governed by the
              CONFIG_CHECKPOINT_RESTORE kernel configuration option.  Since
              Linux 4.2, it is governed by the CONFIG_PROC_CHILDREN option.

Do you see an problems with such an helper function?
Could backwards compatibility for Linux <3.5 become a problem?

@Nukesor
Copy link
Contributor Author

Nukesor commented May 29, 2020

There's also this nice post, which explains why they added the feature. (Before that, the only approach to get child processes was exactly as you described above)

@Nukesor
Copy link
Contributor Author

Nukesor commented May 29, 2020

Ok. Nevermind, I obviously haven't read the full documentation.
and most code should probably not use this interface.

I completely omitted this part.

@eminence
Copy link
Owner

Ahh, yes it's tempting to use that /children file, but I do believe that the recommended way to get process children is to iterate over all processes.

For completeness, I think procfs should eventually add some functions to interface with with the [pid]/task/[tid]/children file (since it's a goal of procfs to cover everything in /proc), but it wouldn't be the recommended way to list child processes for general use.

Independently of that, procfs should also have some documentation and/or examples about how to get a list of child processes.

If you're interested in working on any of this, let me know! 😀

@Nukesor
Copy link
Contributor Author

Nukesor commented May 30, 2020

I'm definitely interested on contributing, so I'll probably add an example for getting children of a process :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants