summaryrefslogtreecommitdiff
path: root/docs/busybox.net
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-02-23 19:59:34 +0000
committerRob Landley <rob@landley.net>2006-02-23 19:59:34 +0000
commitb21837714a3765137bfad16e139bf7b9d6fbbcc6 (patch)
treeab95766754d89ccab7b76bf007dd1e10c88ee022 /docs/busybox.net
parent73a20f355102b715e1ce5f5d268539ee932de708 (diff)
downloadbusybox-w32-b21837714a3765137bfad16e139bf7b9d6fbbcc6.tar.gz
busybox-w32-b21837714a3765137bfad16e139bf7b9d6fbbcc6.tar.bz2
busybox-w32-b21837714a3765137bfad16e139bf7b9d6fbbcc6.zip
Documentation update: more detail on vfork.
Diffstat (limited to 'docs/busybox.net')
-rw-r--r--docs/busybox.net/programming.html55
1 files changed, 34 insertions, 21 deletions
diff --git a/docs/busybox.net/programming.html b/docs/busybox.net/programming.html
index 11d6d6e43..7afa53e27 100644
--- a/docs/busybox.net/programming.html
+++ b/docs/busybox.net/programming.html
@@ -237,29 +237,41 @@ second argument to pw_encrypt(text,buffer).</p>
237 237
238<h2><a name="tips_vfork">Fork and vfork</a></h2> 238<h2><a name="tips_vfork">Fork and vfork</a></h2>
239 239
240<p>On systems that haven't got a Memory Management Unit, fork() is unreasonably
241expensive to implement (and sometimes even impossible), so a less capable
242function called vfork() is used instead. (Using vfork() on a system with an
243MMU is like pounding a nail with a wrench. Not the best tool for the job, but
244it works.)</p>
245
240<p>Busybox hides the difference between fork() and vfork() in 246<p>Busybox hides the difference between fork() and vfork() in
241libbb/bb_fork_exec.c. If you ever want to fork and exec, use bb_fork_exec() 247libbb/bb_fork_exec.c. If you ever want to fork and exec, use bb_fork_exec()
242(which returns a pid and takes the same arguments as execve(), although in 248(which returns a pid and takes the same arguments as execve(), although in
243this case envp can be NULL) and don't worry about it. This description is 249this case envp can be NULL) and don't worry about it. This description is
244here in case you want to know why that does what it does.</p> 250here in case you want to know why that does what it does.</p>
245 251
246<p>On systems that haven't got a Memory Management Unit, fork() is unreasonably 252<p>Implementing fork() depends on having a Memory Management Unit. With an
247expensive to implement, so a less capable function called vfork() is used 253MMU then you can simply set up a second set of page tables and share the
248instead.</p> 254physical memory via copy-on-write. So a fork() followed quickly by exec()
249 255only copies a few pages of the parent's memory, just the ones it changes
250<p>The reason vfork() exists is that if you haven't got an MMU then you can't 256before freeing them.</p>
251simply set up a second set of page tables and share the physical memory via 257
252copy-on-write, which is what fork() normally does. This means that actually 258<p>With a very primitive MMU (using a base pointer plus length instead of page
253forking has to copy all the parent's memory (which could easily be tens of 259tables, which can provide virtual addresses and protect processes from each
254megabytes). And you have to do this even though that memory gets freed again 260other, but no copy on write) you can still implement fork. But it's
255as soon as the exec happens, so it's probably all a big waste of time.</p> 261unreasonably expensive, because you have to copy all the parent process's
256 262memory into the new process (which could easily be several megabytes per fork).
257<p>This is not only slow and a waste of space, it also causes totally 263And you have to do this even though that memory gets freed again as soon as the
258unnecessary memory usage spikes based on how big the _parent_ process is (not 264exec happens. (This is not just slow and a waste of space but causes memory
259the child), and these spikes are quite likely to trigger an out of memory 265usage spikes that can easily cause the system to run out of memory.)</p>
260condition on small systems (which is where nommu is common anyway). So 266
261although you _can_ emulate a real fork on a nommu system, you really don't 267<p>Without even a primitive MMU, you have no virtual addresses. Every process
262want to.</p> 268can reach out and touch any other process's memory, because all pointers are to
269physical addresses with no protection. Even if you copy a process's memory to
270new physical addresses, all of its pointers point to the old objects in the
271old process. (Searching through the new copy's memory for pointers and
272redirect them to the new locations is not an easy problem.)</p>
273
274<p>So with a primitive or missing MMU, fork() is just not a good idea.</p>
263 275
264<p>In theory, vfork() is just a fork() that writeably shares the heap and stack 276<p>In theory, vfork() is just a fork() that writeably shares the heap and stack
265rather than copying it (so what one process writes the other one sees). In 277rather than copying it (so what one process writes the other one sees). In
@@ -267,10 +279,10 @@ practice, vfork() has to suspend the parent process until the child does exec,
267at which point the parent wakes up and resumes by returning from the call to 279at which point the parent wakes up and resumes by returning from the call to
268vfork(). All modern kernel/libc combinations implement vfork() to put the 280vfork(). All modern kernel/libc combinations implement vfork() to put the
269parent to sleep until the child does its exec. There's just no other way to 281parent to sleep until the child does its exec. There's just no other way to
270make it work: they're sharing the same stack, so if either one returns from its 282make it work: the parent has to know the child has done its exec() or exit()
271function it stomps on the callstack so that when the other process returns, 283before it's safe to return from the function it's in, so it has to block
272hilarity ensues. In fact without suspending the parent there's no way to even 284until that happens. In fact without suspending the parent there's no way to
273store separate copies of the return value (the pid) from the vfork() call 285even store separate copies of the return value (the pid) from the vfork() call
274itself: both assignments write into the same memory location.</p> 286itself: both assignments write into the same memory location.</p>
275 287
276<p>One way to understand (and in fact implement) vfork() is this: imagine 288<p>One way to understand (and in fact implement) vfork() is this: imagine
@@ -292,6 +304,7 @@ failed to exec.)</p>
292 304
293<p>(Now in theory, a nommu system could just copy the _stack_ when it forks 305<p>(Now in theory, a nommu system could just copy the _stack_ when it forks
294(which presumably is much shorter than the heap), and leave the heap shared. 306(which presumably is much shorter than the heap), and leave the heap shared.
307Even with no MMU at all
295In practice, you've just wound up in a multi-threaded situation and you can't 308In practice, you've just wound up in a multi-threaded situation and you can't
296do a malloc() or free() on your heap without freeing the other process's memory 309do a malloc() or free() on your heap without freeing the other process's memory
297(and if you don't have the proper locking for being threaded, corrupting the 310(and if you don't have the proper locking for being threaded, corrupting the