diff options
| author | landley <landley@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-02-23 19:59:34 +0000 |
|---|---|---|
| committer | landley <landley@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-02-23 19:59:34 +0000 |
| commit | d3f7a3f7cfe60f5d5c74a5ed5f98fbc1b4b3a670 (patch) | |
| tree | ab95766754d89ccab7b76bf007dd1e10c88ee022 /docs | |
| parent | 7ea99820e7562201595f6baf3b22f08a7669a72d (diff) | |
| download | busybox-w32-d3f7a3f7cfe60f5d5c74a5ed5f98fbc1b4b3a670.tar.gz busybox-w32-d3f7a3f7cfe60f5d5c74a5ed5f98fbc1b4b3a670.tar.bz2 busybox-w32-d3f7a3f7cfe60f5d5c74a5ed5f98fbc1b4b3a670.zip | |
Documentation update: more detail on vfork.
git-svn-id: svn://busybox.net/trunk/busybox@14247 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/busybox.net/programming.html | 55 |
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 | ||
| 241 | expensive to implement (and sometimes even impossible), so a less capable | ||
| 242 | function called vfork() is used instead. (Using vfork() on a system with an | ||
| 243 | MMU is like pounding a nail with a wrench. Not the best tool for the job, but | ||
| 244 | it 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 |
| 241 | libbb/bb_fork_exec.c. If you ever want to fork and exec, use bb_fork_exec() | 247 | libbb/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 |
| 243 | this case envp can be NULL) and don't worry about it. This description is | 249 | this case envp can be NULL) and don't worry about it. This description is |
| 244 | here in case you want to know why that does what it does.</p> | 250 | here 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 |
| 247 | expensive to implement, so a less capable function called vfork() is used | 253 | MMU then you can simply set up a second set of page tables and share the |
| 248 | instead.</p> | 254 | physical memory via copy-on-write. So a fork() followed quickly by exec() |
| 249 | 255 | only 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 | 256 | before freeing them.</p> |
| 251 | simply set up a second set of page tables and share the physical memory via | 257 | |
| 252 | copy-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 |
| 253 | forking has to copy all the parent's memory (which could easily be tens of | 259 | tables, which can provide virtual addresses and protect processes from each |
| 254 | megabytes). And you have to do this even though that memory gets freed again | 260 | other, but no copy on write) you can still implement fork. But it's |
| 255 | as soon as the exec happens, so it's probably all a big waste of time.</p> | 261 | unreasonably expensive, because you have to copy all the parent process's |
| 256 | 262 | memory 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 | 263 | And you have to do this even though that memory gets freed again as soon as the |
| 258 | unnecessary memory usage spikes based on how big the _parent_ process is (not | 264 | exec happens. (This is not just slow and a waste of space but causes memory |
| 259 | the child), and these spikes are quite likely to trigger an out of memory | 265 | usage spikes that can easily cause the system to run out of memory.)</p> |
| 260 | condition on small systems (which is where nommu is common anyway). So | 266 | |
| 261 | although 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 |
| 262 | want to.</p> | 268 | can reach out and touch any other process's memory, because all pointers are to |
| 269 | physical addresses with no protection. Even if you copy a process's memory to | ||
| 270 | new physical addresses, all of its pointers point to the old objects in the | ||
| 271 | old process. (Searching through the new copy's memory for pointers and | ||
| 272 | redirect 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 |
| 265 | rather than copying it (so what one process writes the other one sees). In | 277 | rather 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, | |||
| 267 | at which point the parent wakes up and resumes by returning from the call to | 279 | at which point the parent wakes up and resumes by returning from the call to |
| 268 | vfork(). All modern kernel/libc combinations implement vfork() to put the | 280 | vfork(). All modern kernel/libc combinations implement vfork() to put the |
| 269 | parent to sleep until the child does its exec. There's just no other way to | 281 | parent to sleep until the child does its exec. There's just no other way to |
| 270 | make it work: they're sharing the same stack, so if either one returns from its | 282 | make it work: the parent has to know the child has done its exec() or exit() |
| 271 | function it stomps on the callstack so that when the other process returns, | 283 | before it's safe to return from the function it's in, so it has to block |
| 272 | hilarity ensues. In fact without suspending the parent there's no way to even | 284 | until that happens. In fact without suspending the parent there's no way to |
| 273 | store separate copies of the return value (the pid) from the vfork() call | 285 | even store separate copies of the return value (the pid) from the vfork() call |
| 274 | itself: both assignments write into the same memory location.</p> | 286 | itself: 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. |
| 307 | Even with no MMU at all | ||
| 295 | In practice, you've just wound up in a multi-threaded situation and you can't | 308 | In practice, you've just wound up in a multi-threaded situation and you can't |
| 296 | do a malloc() or free() on your heap without freeing the other process's memory | 309 | do 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 |
