55

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?

5
  • 4
    Note that the fork(2) man page under Linux says: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. I imagine (but do not know for certain) that this is the case for other modern Unix flavors.
    – larsks
    Commented Feb 7, 2012 at 19:17
  • 6
    The original, PDP-11 Unix realy, truly did copy all the bytes of a forked process: but it only had 64Kb of executable, and at most 64Kb of data, so it wasn't a huge burden, even in 1975. I would guess that EVERY unix and unix-a-like since about 1990 has had copy-on-write text segments, so I'm not even sure why books and articles propagate "performance problem with fork" any more.
    – user732
    Commented Feb 7, 2012 at 19:52
  • 2
    Nowadays, fork is implemented in a similar fashion to vfork (openbsd.org/cgi-bin/…). It's efficient, don't worry.
    – Aki
    Commented Feb 7, 2012 at 20:27
  • 1
    Also note that there are lots of usage where you do not exec after a fork (or at least, does not exec right away): think of pipes and web servers.
    – jfg956
    Commented Feb 13, 2012 at 18:34
  • 1
    You may thing is would be slow. But as @cjm says look at the alternative Microsoft uses CreateProcess, they had to implement threads early (may be the only thing they lead on), because CreateProcess is slow. (They also needed threads because select was broken, but that is another story). Commented May 6, 2017 at 11:12

2 Answers 2

74

It's to simplify the interface. The alternative to fork and 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.

With the 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: fork, chdir, exec.

If you want to redirect stdin/stdout: fork, close/open files, exec.

If you want to switch users: fork, setuid, exec.

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 fork and exec.

As larsks mentioned, most modern Unixes use copy-on-write, so fork doesn't involve significant overhead.

11
  • 21
    Excellent explanation. "Those who don't understand UNIX are condemned to reinvent it, poorly." -- Henry Spencer
    – Kyle Jones
    Commented Feb 7, 2012 at 19:57
  • 2
    @Aki, nope, CreateProcess() literally makes a new process and builds it up from scratch, no forking.
    – psusi
    Commented Feb 7, 2012 at 23:19
  • 4
    But must there not be some equivalent of CreateProcess() somewhere in Unix? Otherwise how does the very first process get created? Unlike a mythological creator god, the first process cannot fork() itself from nothingness. ;-) Commented Feb 8, 2012 at 3:54
  • 8
    @StevenMonday, yes, but it's in the kernel's initialization code and not externally accessible. It doesn't need all those parameters because almost everything is hardcoded. It can only create process ID 1, a.k.a. the init process. After that, processes are created only by forking.
    – cjm
    Commented Feb 8, 2012 at 23:18
  • 6
    @StevenMonday, the first process is hand crafted by God ( the kernel )
    – psusi
    Commented Feb 9, 2012 at 2:43
10

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 _exit().

Thus pretty much the only use with defined behavior is:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _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 fork and exec, and an example implementation is provided.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .