JeffGarland / liaw2019-process

Repository for initial drafting of boost.process standards paper
MIT License
5 stars 3 forks source link

Initial proposal thoughts #4

Closed klemens-morgenstern closed 5 years ago

klemens-morgenstern commented 5 years ago

Based on my current opinion, here's the basics of how I would design it. Will probably be changed quite a lot in the future & lacks a ton of details.

janwilmans commented 5 years ago

Can you elaborate on https://github.com/klemens-morgenstern/liaw2019-process/blob/patch-2/klemens_basic_thoughts_1.md#stdprocess_group what would adding a sub-process to a process-group actually do ? what behaviour results from such a group?

klemens-morgenstern commented 5 years ago

A process group allows you to manage processes together, i.e. wait for all to finish or terminate all of them. Since the grouping is done on the OS level (Job Objects or Process groups) this attaches your process, too. I.e. if you put the child process in the same group as the parent, terminating the parent from somewhere else will also kill the child processes (or it crashes with a SIGSEV).

E.g. a use-case I have is to run a gdbserver and a gdb at once, and I just throw them into one group:


bp::pipe pin, pout;

process_group gp;
gp.emplace('openocd');
gp.emplace('gdb', ..., stdio(pin, pout, stdhandles.err());

//Work with pin/pout

I don't care about exit-codes in this scenario, i just want to have them in a handle which terminates them when it goes out of scope.

Come to think of it: I could also add the following functions:

process_group::wait_one() -> pair<pid_t, int>; //wait for one child to exit
process_group::wait_for_one(time) -> optional<pair<pid_t, int>>;

This could be useful if I am tool agnostic and scheduler jobs, e.g. if I build a build system. Not sure that's generic enough to warrant a standard function though.

TL;DR: it provides terminate (on the OS level) and wait, wait_for... for all processes.

EDIT: Had it backwards, it detaches your process, at least potentially.

janwilmans commented 5 years ago

I understand this, my concern is: what happens if parent and child are in a group and the child dies? does the OS (in case of linux) differentiate between parent and child?

klemens-morgenstern commented 5 years ago

On windows the group (Job Object) is not attached to any particular process, so nothing like that can happen there. Conceptually, a group should work like that.

On linux (posix in general) groups are created with a gid_t equal to the pid_t of the leader-process - but this does not mean that the group gets killed on exit of the leader. So it is created slightly differently, but works in essence like job objects.

As for management of single processes, if we think of a group like a table we could add a few more functions:

process_group::wait(pid_t); //wait for a particular child
process_group::running(pid_t);
process_group::terminate(pid_t);

For your scenario, you basically want to do something like this:

process_group grp;
grp.attach_self(); //I forgot that one
grp.emplace("foo"); 

//handle error of foo?
janwilmans commented 5 years ago

I have experience on windows with this but not on linux. As I understand in, on Windows, Job Objects are owned/associated with the process that creates it.

So when used this way: https://github.com/CobaltFusion/DebugViewPP/blob/master/Win32Lib/Win32Lib.cpp#L614 (this is a project of mine, so I can confirm this actually works)

the children will be killed when the parent dies, but not vice-versa.

So .attach_self will 'take ownership' of the group in the sense that if you die, the group dies? and not the other way around?

Greetings,

Jan

On Fri, 24 May 2019 at 08:59, Klemens Morgenstern notifications@github.com wrote:

On windows the group (Job Object) is not attached to any particular process, so nothing like that can happen there. Conceptually, a group should work like that.

On linux (posix in general) groups are created with a gid_t equal to the pid_t of the leader-process - but this does not mean that the group gets killed on exit of the leader. So it is created slightly differently, but works in essence like job objects.

As for management of single processes, if we think of a group like a table we could add a few more functions:

process_group::wait(pid_t); //wait for a particular childprocess_group::running(pid_t);process_group::terminate(pid_t);

For your scenario, you basically want to do something like this:

``cpp process_group grp; grp.attach_self(); //I forgot that one grp.emplace("foo");

//handle error of foo?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/JeffGarland/liaw2019-process/pull/4?email_source=notifications&email_token=ABNITBE3F5AUBAZL74SQYGLPW6G6RA5CNFSM4HMH4RKKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWEKWVI#issuecomment-495496021, or mute the thread https://github.com/notifications/unsubscribe-auth/ABNITBAC2WZ7TKXUY4OHE4TPW6G6RANCNFSM4HMH4RKA .

-- Jan

klemens-morgenstern commented 5 years ago

Alright, I am pretty sure I will get something wrong now :).

In boost.process the group is created with the breakaway flag by default, meaning it will actually survive the parent process (at least optionally). The weird part is that you can cascade Job Objects on windows, while linux know no such thing. So afaik a process group itself is also a means to seperate the child process from the parent ( --> I had this backwards in the last comment).

So the way I see it is: a process launched without process settings defaults to whatever the OS does. We then have TWO group objects, a detached one and an attached one (a global that is), so you can do this:

this_process::group.emplace("attached"); //Attached to whatever group the current process is 
group g; g.emplace("detached"); //BREAKAWAY

And then you can detach a child process by putting it in it's on group explicitly:

group g;
g.emplace("chrome");
g.detach(); //survives the current process now.

Does that sound about right?

In boost.process I set the JOB_OBJECT_LIMIT_BREAKAWAY_OK and CREATE_BREAKAWAY_FROM_JOB flags.