fork, vfork

Dear all,

The difference between fork and vfork used to be whether copying parent process's pages to child or not. But nowadays an OS might use copy-on-write technique for the fork call, thus fork won't do any copy if not needed. So that running another program using fork()+exec() will have the same efficiency with vfork()+exec().

My question is, does the fork implementation of FreeBSD behave like this (the C-O-W one) too?
 
Fork has always used shared memory mapping, or at least as long as I can think back. However that memory mapping is likely going to not be a sequence in it's physical representation, i.e. you have a set (linked list here) of memory chunks that form the mapping instead of just a large chunk. When a process forks, all those memory chunks need to have their reference counter incremented as they are shared more times now, and if a memory mapping is heavily fragmented this reference counter incrementing can take "considerable" time. Therefore the vfork syscall is provided to allow you to clone a process metadata without needing to do the "slow" reference keeping. For this reason the vforking process will not be running until the child process has "released" it's memory mapping by either replacing it on exec or releasing it on _exit, as allowing the parent to run would have the parent process manipulate pages of the child process including the stack segment ones which will _very_ likely break it.

Nowadays it should be prefered to run fork instead of vfork, as the memory mapping metadata is likely going to be paged in at that point to begin with and therefore the savings of vfork will be small (unless of cause you want to interrupt the parent while it's child is running).

EDIT:
Yes, it uses a copy on write protection. That's what the reference counter is good for to begin with: determine whether a page needs to be copied on write (because there's multiple references) or not (because there's only one)
 
From vfork's man:

...
The vfork() system call can be used to create new processes without fully copying the address space of the old process, which is horrendously inefficient in a paged environment. It is useful when the purpose of fork(2) would have been to create a new system context for an execve(2). The vfork() system call differs from fork(2) in that the child borrows the parent's memory and thread of control until a call to execve(2) or an exit (either by a call to _exit(2) or abnormally). The parent process is suspended while the child is using its resources.

The vfork() system call returns 0 in the child's context and (later) the pid of the child in the parent's context.

The vfork() system call can normally be used just like fork(2). It does not work, however, to return while running in the child's context from the procedure that called vfork() since the eventual return from vfork() would then return to a no longer existent stack frame. Be careful, also, to call _exit(2) rather than exit(3) if you cannot execve(2), since exit(3) will flush and close standard I/O channels, and thereby mess up the parent processes standard I/O data structures. (Even with fork(2) it is wrong to call exit(3) since buffered data would then be flushed twice.)
...
 
Back
Top