The UNIX system call for process creation, fork(), creates a child process by copying the parent process. My understanding is that this is almost always followed by a call to exec() to replace the child process' memory space (including text segment). Copying the parent's memory space in fork() always seemed wasteful to me (although I realize the waste can be minimized by making the memory segments copy-on-write so only pointers are copied). Anyway, does anyone know why this duplication approach is required for process creation?
It's to simplify the interface. The alternative to
exec would be something like Windows' CreateProcess function. Notice how many parameters
CreateProcess has, and many of them are structs with even more parameters. This is because everything you might want to control about the new process has to be passed to
CreateProcess. In fact,
CreateProcess doesn't have enough parameters, so Microsoft had to add CreateProcessAsUser and CreateProcessWithLogonW.
fork/exec model, you don't need all those parameters. Instead, certain attributes of the process are preserved across
exec. This allows you to
fork, then change whatever process attributes you want (using the same functions you'd use normally), and then
exec. In Linux,
fork has no parameters, and
execve has only 3: the program to run, the command line to give it, and its environment. (There are other
exec functions, but they're just wrappers around
execve provided by the C library to simplify common use cases.)
If you want to start a process with a different current directory:
If you want to redirect stdin/stdout:
fork, close/open files,
If you want to switch users:
All these things can be combined as needed. If somebody comes up with a new kind of process attribute, you don't have to change
As larsks mentioned, most modern Unixes use copy-on-write, so
fork doesn't involve significant overhead.
In adition to the cjm's answer, the Single Unix Specification defines a function named
vfork(). That function works like fork, except that the forked process has undefined behavior if it does anything other than try calling an exec familly function, or calling
Thus pretty much the only use with defined behavior is:
pid_t ret = vfork();
if(ret == 0)
_exit(EXIT_FAILURE); //in case exec failed for any reason.
So what does
vfork do? It is is an inexpensive
fork. In implemenations without copy-on-write, the resulting process will share memory space with the original process (hence the undefined behavior). In implementations with copy-on-write,
vfork is permitted to be identical to
fork(), since copy-on-write implementations are fast.
There is also the optional
posix_spawn function (and a
posix_spawnp function) which can directly create a new process. (It is also permissible to implement them with a library call using
exec, and an example implementation is provided.)