26

Process A fork()s process B.

Process A dies and therefore init adopts B.

A watchdog creates process C.

Is it somehow possible for C to adopt B from init?


Update:

Or would it even be possible to have C adopt B directly (when A dies), if C were created prior to A's dead, without init becoming an intermediate parent of B?


Update-1:

Also I would appreciate any comments on why having the possiblity to adopt a process the way I described would be a bad thing or difficult to impossible to implement.


Update-2 - The use case (parent and children refer to process(es)):

I have an app using a parent to manage a whole bunch of children, which rely on the parent's managment facility. To do its job the parent relies on being notified by a child's termination, which is done via receiving the related SIGCHLD signal.

If the parent itself dies due some accident (including segfaulting) I need to restart the whole "family", as it's impossible now to trigger something on a child's termination (which also might due to a segfault).

In such a case I need to bring down all children and do a full system's restart.

A possible approach to avoid this situation, would be to have a spare-process in place which could take over the dead parent's role ... - if it could again receive the step children's SIGCHLD signals!

alk
  • 69,737
  • 10
  • 105
  • 255
  • The children could bring themselves down if they inherit the just the 'read' end of a pipe made by the parent. The 'read' end will select readable (for EOF) upon the parent's death, an IO event each child could trap and react to. – pilcrow May 17 '12 at 16:56
  • This issues is, I do not want to bring down the children. I'd like to have the possiblity to replace the dead parent (in terms of being able to receive their SIGCHLD, in case they terminate), by a step-parent process. @pilcrow – alk May 18 '12 at 20:49
  • In my above comment this "*... receive their SIGCHLD ...*" should read "*... receive their children's SIGCHLD ...*". – alk Aug 08 '15 at 13:31

4 Answers4

17

No, most definitely not possible. It couldn't be implemented either, without some nasty race conditions. The POSIX guys who make these APIs would never create something with an inherent race condition, so even if you're not bothered, your kernel's not getting it anytime soon.

One problem is that pids get reused (they're a scarce resource!), and you can't get a handle or lock on one either; it's just a number. So, say, somewhere in your code, you have a variable where you put the pid of the process you want to reparent. Then you call make_this_a_child_of_me(thepid). What would happen then? In the meantime, the other process might have exited and thepid changed to refer to some other process! Oops. There can't be a way to provide a make_this_a_child_of_me API without large restructuring of the way unix handles processes.

Note that the whole deal with waiting on child pids is precisely to prevent this problem: a zombie process still exists in the process table in order to prevent its pid being reused. The parent can then refer to its child by its pid, confident that the process isn't going to exit and have the child pid reused. If the child does exit, its pid is reserved until the parent catches SIGCHLD, or waits for it. Once the process is reaped, its pid is up for grabs immediately for other programs to start using when they fork, but the parent is guaranteed to already know about it.

Response to update: consider a more complicated scheme, where processes are reparented to their next ancestor. Clearly, this can't be done in every case, because you often want a way of disowning a child, to ensure that you avoid zombies. init fulfills that role very well. So, there has to some way for a process to specify that it intends to either adopt, or not, its grandchildren (or lower). The problem with this design is exactly the same as the first situation: you still get race conditions.

If it's done by pid again, then the grandparent exposes itself to a race condition: only the parent is able to reap a pid, so only the parent really knows which process a pid goes with. Because the grandparent can't reap, it can't be sure that the grandchild process hasn't changed from the one it intended to adopt (or disown, depending on how the hypothetical API would work). Remember, on a heavily-loaded machine, there's nothing stopping a process from being taken off the CPU for minutes, and a whole load could have changed in that time! Not ideal, but POSIX's got to account for it.

Finally, suppose then that this API doesn't work by pid, but just generally says, "send all grandchildren to me" or "send them to init". If it's called after the child processes are spawned, then you get race conditions just as before. If it's called before, then the whole thing's useless: you should be able to restructure your application a little bit to get the same behaviour. That is, if you know before you start spawning child processes who should be the parent of whom, why can't you just go ahead and create them the right way round in the first place? Pipes and IPC really are able to do all the required work.

Nicholas Wilson
  • 9,435
  • 1
  • 41
  • 80
  • Thanks for you explanations. I though understand it is not feasable to simply take over parentship of a process. But for the second way to go (mentioned under `Update` in my question) there might exist a possibilty by registering an existing process as spare-process to step in place (regarding parentship) in case another process dies, so that its children then won't be adopted by `init` but by (the previously registered) spare-process. – alk May 11 '12 at 14:32
  • Thanks again for communicating your thoughts. Regarding reparenting to grandparents I surely see that this could not be made a default behaviour as lot's of existing implementations (and pattern) rely on children losing their parent to become adopted by init. – alk May 16 '12 at 15:43
  • As `init` *is* a process, which *does* adopt children (which is performed by the kernel), so why not allow the kernel to assign those orphans some other prcoess but init. I indeed were thinking about an approach as you mentioned in your paragraph starting with "*send all grandchildren to me" or "send them to init*". Please see Update-2 in my question for details on the use case I am facing. – alk May 16 '12 at 15:47
  • Good points. In Linux kernel though child and parent `task_struct` keep pointers to each other, so it would technically be possible for a grandparent to inherit a child when the parent dies. – Maxim Egorushkin May 16 '12 at 16:00
  • Luky me, I'm on Linux! :-) @MaximYegorushkin – alk May 16 '12 at 16:07
  • Well it must be patch the kernel day then. Enjoy. – Joshua May 16 '12 at 16:21
  • @Maxim: Right. It's possible for the kernel to do this, because it knows about locks and process scheduling. But, given that the default can't be changed, an API would have to offer a choice of behaviours to processes. That API would either have an inherent race condition, or else require the processes to know in advance their subprocesses, in which case the API isn't needed. – Nicholas Wilson May 17 '12 at 11:20
  • 2
    Do note that e.g. linux (since kernel 3.4) have one additional way besides "re-parent to init" , to re-parent a process, see http://stackoverflow.com/questions/6476452/process-re-parenting-controlling-who-is-the-new-parent , (but still no way to adopt a process from init again) – nos Apr 22 '15 at 11:08
  • @nos: Thanks a lot for pointing this out, as this would cover the use case mentioned in the 1st update to my question. – alk Aug 08 '15 at 13:37
  • The race condition you mentioned is well known in POSIX/Linux. AFAIU, PID race conditions exist on most if not all PID related syscalls/operations. kill()ing a successfully fork()ed child process cannot be done without race conditions. Please correct me if I'm wrong, but it's always possible that the fork()ed child died before it was kill()ed by the parent, with a slight chance of the PID being reused in the meantime. – jg6 Apr 22 '23 at 13:14
8

No there is no way that you can enforce Reparenting in the way you have described.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Allthough it's hard for me to accept what you are writing, I do accept your answer ... ;-) - anyway, I wonder if there are any good reasons to not having such a possibility available. Or is it just because no one needs it, so no one implemented it (yet)? @als – alk May 10 '12 at 15:52
  • @alk: If you find hard to accept it don't accept it, let the q be or perhaps add an bounty. – Alok Save May 10 '12 at 15:57
  • 1
    You are right. I'll unaccept your answer, as this perhaps might motivate somebody to comment on this question. @als – alk May 11 '12 at 09:24
0

I don't know of a good way to do this, but one reason for having it is that a process running can stand on its own or add a capability to a parent process. The adoption would occur as the result of an event, know by the (not yet) child, but not the parent. The soon-to-be child would send a signal to the parent. The parent would adopt (or not) the child. Once part of the parent, the parent/child process would be able to react to the event, whereas neither could react to the event when standing alone.

This docking behavior could be coded into the apps, but I don't know how to do it in real-time. There are other ways to achieve the same functionality. A parent, who could accept docking children could have its functionality extended in novel ways not previously known to the parent.

jrjbertsch
  • 11
  • 1
0

While the original question is tagged with unix, there is a way to achieve this on linux so it's worth mentioning. This is achievable with the use of a subreaper process. When a process's parent, it will get adopted by the nearest subreaper ancestor or init. So in your case you'll have process C set as subreaper via prctl(PR_SET_CHILD_SUBREAPER) and spawns process A, when process A dies, process B will be adopted by C

An alternative on Linux would be to spawn C in a separate PID namespace, making it the init process of the PID namespace and hence can adopt the children of A when A dies.

attempt0
  • 639
  • 5
  • 14