[comp.unix.questions] Using vfork

mouse@mcgill-vision.UUCP (der Mouse) (06/27/87)

Quotes are from articles <21731@sun.uucp> and <21685@sun.uucp>,
written by guy%gorodish@Sun.COM (Guy Harris).

> There is very little you can do with the (temporarily) shared memory
> you get from "vfork", and in most, if not all, cases, you can do the
> same thing just as well without it.

Well, I wrote such code (just once, as far as I can recall).  The child
process had to do some fiddling before execing.  It was possible for it
to fail during this fiddling.  Also, the parent had to know the exit
code of the execed program, if it was really executed; this exit code
could be any of the possible exit codes.  How is the parent to know
whether the child succeeded in its fiddling and exec?  I used the
`shared' memory to pass a flag back to the parent.  This was simple,
fast, and obvious (I noted the dependence on the (admittedly) ugly
vfork() semantics in a comment at that point in the code).  I see no
way to pass this back without using a temporary file (ugh) or a pipe
(double ugh; and is it guaranteed to have enough buffer capacity?).

> The only remaining reason to use vfork is that one has written ugly
> and brain-damaged code that depends on the semantics of "vfork".
> [...] If anybody has written code of this sort, they should hang
> their head in shame and then go out and fix it NOW.

Well, I'm not exactly proud of the technique, but I won't go so far as
to hang my head in shame.  Fix it, you say; but what fix would you
recommend I use?

					der Mouse

				(mouse@mcgill-vision.uucp)

guy%gorodish@Sun.COM (Guy Harris) (06/30/87)

> Well, I'm not exactly proud of the technique, but I won't go so far as
> to hang my head in shame.  Fix it, you say; but what fix would you
> recommend I use?

Well, first go read the "vfork" manual, paying special attention to
the part that says "don't do that", and then change the process to
send itself an unused signal (such as SIGUSR[12] on 4.3BSD) if the
"exec" fails.  Unless somebody is being perverse and randomly sending
unused signals around, which is extremely unlikely (and anybody who
does that gets what they deserve anyway), the fact that the child was
terminated by this signal indicates that the "exec" fails.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/19/89)

In article <1989Jun19.013230.16107@marob.masa.com> daveh@marob.masa.com (Dave Hammond) writes:
>Can someone provide concrete examples of where I'd want to use vfork(),
>rather than fork()?

Don't use vfork().  It can cause problems for the unwary, it doesn't
exist on non-BSD operating systems, and even Berkeley has threatened
to remove support for it (in which case it will probably become an
alias for fork()).

guy@auspex.auspex.com (Guy Harris) (06/29/89)

>From what I can glean from the manual, the advantages of vfork() over
>fork() are (1) virtual memory efficiency and (2) shared access to parent
>memory, data structures, etc.  until an execv().

The Berkeley VFORK(2) manual page quite specifically states that 2) is
NOT to be depended on as a "feature" of "vfork()":

    BUGS
	This system call will be eliminated when proper system sharing
	mechanisms are implemented.  Users should not depend on the memory
	sharing semantics of "vfork" as it will, in that case, be made
	synonymous to "fork".

mats@oblio.UUCP (Mats Wichmann) (06/30/89)

daveh@marob.masa.com (Dave Hammond) writes:

>Can someone provide concrete examples of where I'd want to use vfork(),
>rather than fork()?

When you know you are going to do an exec() right away.  Which the Berkeley
people argue (correctly) is a very frequent use for fork().  The issue is
that copying the process space of the parent to make the child seems like a
lot of work if you are going to throw it away by exec'ing another program
right away.  So vfork() shares the addresses spaces instead of making a
copy.  Making the child copy-on-write is another way to accomplish this
(transparently), as in Sys V.3, but there you still pay the costs to set up
the table structures.  Another way is to get real virtual memory (Mach
claims to do this stuff better, for example).

Mats Wichmann
Acer America

daveh@marob.masa.com (Dave Hammond) (07/22/89)

Pertaining to vfork() and fork() usage in Berkely-specific C programs:

From what I can glean from the manual, the advantages of vfork() over
fork() are (1) virtual memory efficiency and (2) shared access to parent
memory, data structures, etc.  until an execv().

The disadvantage seems to be that returning to the parent context while
the childs context still exists does not work.  Does this mean that
spawning an asynchronous process via vfork() is not possible?

My application wants to spawn children to:
(1) execute adhoc subtasks (like `system("command")' ).
(2) execute adhoc subtasks asynchronously (like `system("command &")' ).
(3) execute cooperative subtasks for data sharing (like `popen("command")' ).

My feeling is that vfork() is less appropo for this application than
fork().  Am I offbase about this?

Can someone provide concrete examples of where I'd want to use vfork(),
rather than fork()?

--
Dave Hammond
daveh@marob.masa.com

guy@auspex.auspex.com (Guy Harris) (08/18/89)

>Pertaining to vfork() and fork() usage in Berkely-specific C programs:
>
>From what I can glean from the manual, the advantages of vfork() over
>fork() are (1) virtual memory efficiency and (2) shared access to parent
>memory, data structures, etc.  until an execv().

Uhh, 2) isn't supposed to be thought of as an advantage - it's supposed
to be thought of as a consequence of the current implementation, subject
to change at any time.  I.e., don't *rely* on this behavior, for, as the
vfork man page says:

     BUGS
	This system call will be eliminated when proper system sharing
	mechanisms are implemented.  Users should not depend on the memory
	sharing semantics of "vfork" as it will, in that case, be made
	synonymous to "fork".

>The disadvantage seems to be that returning to the parent context while
>the childs context still exists does not work.  Does this mean that
>spawning an asynchronous process via vfork() is not possible?

Unless the asynchronous process is going to be running a different
program - i.e., it's going to do an "exec" - yes.  "vfork" was
specifically intended to be used when the subprocess was going to do a
few things - things like shuffle file descriptors, change current
directory, etc. - and then "exec".  None of those things should modify
any global data structures whatsoever, except for those in the kernel/U
area....

>My application wants to spawn children to:
>(1) execute adhoc subtasks (like `system("command")' ).
>(2) execute adhoc subtasks asynchronously (like `system("command &")' ).
>(3) execute cooperative subtasks for data sharing (like `popen("command")' ).
>
>My feeling is that vfork() is less appropo for this application than
>fork().  Am I offbase about this?

If in the "like ..." examples you mean the child process really will do
the equivalent of that - which means doing an "exec" of the program in
question - "vfork()" is appropriate.  If you mean that the child will be
running the *same* code as the parent - and not simply by virtue of
doing an "exec" of the same program - "vfork()" is completely
inappropriate.

>Can someone provide concrete examples of where I'd want to use vfork(),
>rather than fork()?

1) The "system()" library routine could use it, since it just "exec"s
   "/bin/sh" after the "vfork()".  (In fact, in 4.xBSD, it *does* use
   "vfork()".)

2) The "popen()" library routine could use it, since it just shuffles
   file descriptors and "exec"s "/bin/sh".  (In fact, in 4.xBSD, it
   *does* use "vfork()".)

3) Shells can often use it, since they shuffle file descriptors, etc.
   and then "exec" the command.  If the command is a script in their own
   language, though, and they're going to execute the script by e.g.
   jumping back to their main command-interpretation loop (which is
   basically what the Bourne shell does if the "exec" fails with ENOEXEC
   - if the file has a "#!" line, the "exec" succeeds because it fires
   up a new "/bin/sh"), they can't use it, though, since the child
   process will still be running the same program.

4) "make" can use it, since it just "exec"s the program or "/bin/sh".

5) Etc..

klee@gilroy.pa.dec.com (Ken Lee) (08/18/89)

In article <1989Jun19.013230.16107@marob.masa.com>, daveh@marob.masa.com (Dave Hammond) writes:
> Can someone provide concrete examples of where I'd want to use vfork(),
> rather than fork()?

vfork is intended specifically for the case where the child process
will exec soon after the vfork.  The parent process is suspended in the
interim.  A quick exec is common (most of the time), so this
performance hack is useful.

In their book, Leffler, et al, say:  "Although allowing modification of
the parent's address space is bad programming practice, some programs
have been known to take advantage of this quirk."  You can play games
with the parent during a vfork, but this is rarely worthwhile.

Ken Lee
DEC Western Software Laboratory, Palo Alto, Calif.
Internet: klee@decwrl.dec.com
uucp: uunet!decwrl!klee

dwc@cbnewsh.ATT.COM (Malaclypse the Elder) (08/18/89)

in unix system v release 4, fork will have all the advantages
of vfork with none of the disadvantages (well almost).

danny chen
att!hocus!dwc

hutch@lzaz.ATT.COM (R.HUTCHISON) (08/22/89)

From article <3161@cbnewsh.ATT.COM>, by dwc@cbnewsh.ATT.COM (Malaclypse the Elder):
> 
> in unix system v release 4, fork will have all the advantages
> of vfork with none of the disadvantages (well almost).
> 
> danny chen
> att!hocus!dwc

I think that SVR3 has these advantages already plus more.  
V.3 has copy-on-write (COW) pages, allowing parent and child to 
change the same image (by default).  So, if the child does an 
exec() right away, the two are similar (in the amount of work the OS
has to do).  But... V.3 has extra goodies...

1) The SVR3 child does not have to obey the rules a vfork() child does - it
can change the process image - whenever a change is made, the changing
process (whomever it might be) gets its own copy of the page it
changed - the rest remains shared.  If a parent creates several
children (through fork()s) they will all share the same image until
one of them wants to change a page - then it will get its own copy and
the rest will still share the original page.

2) Unrelated processes share data pages as well as (the traditional)
text pages.  This is great if you have large static tables - they are
shared by all using the program.  The same COW principle applies.

Is there more that I'm missing?

Bob Hutchison
att!lzaz!hutch