0

Suppose I have process foo and executable bar. foo calls fork() and now I have two, call them foo_parent and foo_child.

  • foo_parent calls wait()
  • foo_child calls execvp([stuff to run bar]);

I don't quite understand what happens to foo_child/bar. Is foo_child overwritten in memory with bar? Is a new bar process started and given foo_child's pid? Is bar a child of foo_child and foo_child just passes the return on to foo_parent?

I know that when foo_parent gets the exit status after wait, it's the result of bar's exit() call, but I don't have a good grasp of what's happening "under the hood," as it were.

Daniel B.
  • 1,254
  • 1
  • 16
  • 35

2 Answers2

2

The process that was foo_child is replaced by bar in its entirety. It has the same PID, and many other properties are the same in foo_child and bar, but the executable is started afresh. The process bar is still a child of foo_parent, so foo_parent can obtain its exit status, etc.

Note that the exec*() family of functions never return if they succeed. If they return at all, they failed.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • How is the pid attached to bar (and for that matter, how is it "attached" to foo_parent and foo_child in the first place)? – Daniel B. Feb 14 '15 at 04:55
  • I'm not sure how to explain it. The PID is a property of the process; it is stored in the data structure in the kernel that contains all the information about the process. It isn't quite as simple as "it is the index number into an array of process entries", but conceptually, it is not too far off (it is a sparse array, in general). – Jonathan Leffler Feb 14 '15 at 04:57
  • I guess return is the wrong term ... but ... the last 8 bits from WEXITSTATUS(status) is the return of bar? I'm not sure how to word that in a coherent way -_- – Daniel B. Feb 14 '15 at 04:58
  • The PID would be stored in a process control block right? So it would write the new program in and set the program counter to the start of bar? – Daniel B. Feb 14 '15 at 04:59
  • 1
    The exit status is the term to use. The exit status is normally the high-order 8 bits of a 16-bit value; the low-order 8 bits contain information about the signal that killed the process, if it was killed by a signal, and whether it dumped core. This can be picked up by WIFEXITED, WIFSIGNALED, WEXISTATUS, WTERMSIG (and usually WCOREDUMP, but that is not standardized by POSIX). – Jonathan Leffler Feb 14 '15 at 05:00
  • 1
    You can think of the `proc` structure as the process control block. It would record the new program (or the original program if you re-exec the original program) in the process structure, but the content of the program would remain on disk. Yes, part of the `exec` processing would start the process and set the program counter to the start of the code in `bar`. – Jonathan Leffler Feb 14 '15 at 05:25
  • 1
    Note that if the `foo_parent` process exec'd another process, the second process would inherit the `foo_child` or `bar` process, even though it probably wouldn't know that it had done so. You can find all the details at [`execvp()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/execvp.html) and related manual pages. – Jonathan Leffler Feb 14 '15 at 05:29
2

"foo calls fork() and now I have two, call them foo_parent and foo_child."

Less confusing: you still have the process foo (parent) and now you also have a child process (foo_child).

"Is foo overwritten in memory with bar?"

When foo_child calls exec(), then its memory space is overwritten with that of bar. It retains some things from foo. In particular, file descriptors that were open in foo (and are not close-on-exec) are still open in bar and it also inherits some of the signal handling dispositions of foo (consult the man pages of exec* for details).

"Is a new bar process started and given foo_child's pid?"

Sorta, not quite. The new process foo_child, with its own pid and memory space, began when you forked. It has a copy of foo's memory space at the time of the fork. When it calls exec(bar), then its memory space is overwritten with bar and runs the executable code of bar rather than foo.

"Is bar a child of foo_child and foo_child just passes the return on to foo_parent?"

No, bar (i.e. - foo_child now executing bar) is a child process of foo whose exit value can be returned to foo.

jschultz410
  • 2,849
  • 14
  • 22
  • Bar gets new memory space, so it's not overwriting the text section for foo_child? So basically a whole new process is created and given the pid (and possibly some other data) from foo_child? – Daniel B. Feb 14 '15 at 05:03
  • I'm reminded of cuckoos, pushing babies out of the nest and getting fed by the mother :p – Daniel B. Feb 14 '15 at 05:06
  • One caveat: some file descriptors open in foo remain open in bar, and some signal handling dispositions are inherited. Files that are marked 'close on exec' are not maintained, and any signals that are being handled will get the default disposition reset. – William Pursell Feb 14 '15 at 05:10
  • @WilliamPursell I was with you right up to "Some." "file descriptors?" "Signal handling dispositions?" How would I mark a file as close on exec? (I assume this would be something that I used with fopen() or the like that I want to make sure closes so I don't leave an open file) – Daniel B. Feb 14 '15 at 05:15
  • @DanielBall Correction to my former comment. After the fork the child has a COPY of the parent at the time of the fork but its own memory space. If the child (or parent) alters variables within themselves, then the change will not be reflected in the other process. So, yes, when foo_child calls exec the memory space of foo_child is getting overwritten with a new binary image -- text and data regions -- of bar. – jschultz410 Feb 14 '15 at 05:21
  • http://stackoverflow.com/questions/6125068/what-does-the-fd-cloexec-fcntl-flag-do – William Pursell Feb 14 '15 at 05:21