LWN.net Logo

Ghosts of Unix past, part 4: High-maintenance designs

Ghosts of Unix past, part 4: High-maintenance designs

Posted Dec 4, 2010 18:00 UTC (Sat) by nix (subscriber, #2304)
In reply to: Ghosts of Unix past, part 4: High-maintenance designs by pbonzini
Parent article: Ghosts of Unix past, part 4: High-maintenance designs

Yeah, that's quite nasty. But spawn*() has all the same problems and a bunch of extra ones, prominent among them the fact that it's exactly the same as fork()/exec() with the code between the fork() and exec() hardwired. So you end up with dozens of spawn*() calls and no benefit over fork()/exec() at all (except on tiny non-MMU systems, which can theoretically implement spawn*() but not fork()/exec() --- but usually implement both, because most code uses fork()/exec() and not spawn*().)

I suspect that a combination of waitpid() (to catch signals and read-from-pipe to catch errno might work: if you played games with self-signalling you could possibly encode errnos as rare signals and drop the pipe, at the cost of losing the ability to detect those rare signals.

A bit of extra effort (sending something down the pipe right before exec() as well as right after a failed one, and opening the pipe end O_CLOEXEC) enables you to distinguish between a signal hitting before exec() and a signal hitting after a successful exec().

But, yes, this is all pointlessly complex. If C had proper Lisp-style macros we could wrap this up in a library without the result becoming as inflexible as spawn(). (Something involving function pointers could get halfway there, perhaps. But it wouldn't be as neat.)


(Log in to post comments)

Ghosts of Unix past, part 4: High-maintenance designs

Posted Dec 5, 2010 20:40 UTC (Sun) by quotemstr (subscriber, #45331) [Link]

except on tiny non-MMU systems, which can theoretically implement spawn*() but not fork()/exec()
Cygwin also falls into this category. fork() works there, but it's painfully slow because it copies the entire address space. spawn() is far more efficient.

Ghosts of Unix past, part 4: High-maintenance designs

Posted Dec 6, 2010 10:58 UTC (Mon) by pbonzini (subscriber, #60935) [Link]

no benefit over fork()/exec() at all (except on tiny non-MMU systems, which can theoretically implement spawn*() but not fork()/exec()
Actually, if the parent has a large RSS it is quite common to see major performance improvements with vfork() over fork(). And given how hacky vfork() is, I'd really be happy to pay the price of spawn()'s inflexibility. fork() should be treated like a relic of when parallelism was achieved using processes rather than threads, IMO.

Ghosts of Unix past, part 4: High-maintenance designs

Posted Dec 6, 2010 11:31 UTC (Mon) by dlang (✭ supporter ✭, #313) [Link]

does this vfork advantage still exist (i.e., is it measurable) when the host OS does Copy On Write for the fork instead of actually copying all ram?

yes, the page tables still get modified twice, but is this measurable on modern hardware?

Ghosts of Unix past, part 4: High-maintenance designs

Posted Dec 6, 2010 11:58 UTC (Mon) by pbonzini (subscriber, #60935) [Link]

Yes, I've seen forking take 60% of CPU (that was forking 4 child processes per second from a +2 GB process). Using fork to vfork, or equivalently switching to posix_spawn, brought it down to 3-4%.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds