🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

18 total messages Started by Donald Lewine Thu, 20 Dec 1990 21:13
qfork()
#672
Author: Donald Lewine
Date: Thu, 20 Dec 1990 21:13
33 lines
1733 bytes
Submitted-by: lewine@cheshirecat.webo.dg.com (Donald Lewine)

[[I hope that this has not been covered in detail on comp.std.unix.  
  Delivery of the newsgroup has been uneven for the last few weeks.]]

[It's not been so much delivery as posting, due to lessened attention
on my part because of lack of funding, and also because of no snitch
reports.  -mod]

Draft 5 of POSIX.1a defines qfork() by saying:
"The qfork() function shall be identical to the fork() function with
 the following exception: behavior is undefined if the child process
 executes any code between the return from qfork() and the succeeding
 call to one of the exec functions or _exit()."

This seems to be a very harsh restriction.  The following code seems
like it would be undefined:
	status = qfork();
	if (status == 0) execve(...);

I would propose replacing the phrase: "executes any code" with "calls
any function defined in this standard or the C standard {8}"  I think
that does what you mean.

--------------------------------------------------------------------
Donald A. Lewine                (508) 870-9008 Voice
Data General Corporation        (508) 366-0750 FAX
4400 Computer Drive. MS D112A
Westboro, MA 01580  U.S.A.

uucp: uunet!dg!lewine   Internet: lewine@cheshirecat.webo.dg.com

Volume-Number: Volume 22, Number 35
Re: qfork()
#675
Author: Jason Zions
Date: Mon, 24 Dec 1990 16:57
34 lines
2039 bytes
Submitted-by: jason@cnd.hp.com (Jason Zions)

>"The qfork() function shall be identical to the fork() function with
> the following exception: behavior is undefined if the child process
> executes any code between the return from qfork() and the succeeding
> call to one of the exec functions or _exit()."
>
>This seems to be a very harsh restriction.  The following code seems
>like it would be undefined:
>	status = qfork();
>	if (status == 0) execve(...);
>
>I would propose replacing the phrase: "executes any code" with "calls
>any function defined in this standard or the C standard {8}"  I think
>that does what you mean.

I think that loosens the restriction too much.  The intent of the text, I
believe, is that *doing* anything between qfork() and exec*() results in
undefined behavior. Checking a variable doesn't *do* anything in this sense.
The text tries to sidestep the issue of "is qfork() a 4.2BSD-style
share-memory pseudo-fork or is it a real fork or what?" An application which
takes an action after qfork() and before exec*() that depends upon the
implementation of qfork() being any one of those things is inherently
unportable.

Instead of replacing "executes any code", I think you could just add the
phrase "which modifies memory or calls any function" and maintain the
intent. Examining variables doesn't depend upon the virtual memory
relationship between child and parent, but munging a stack for a function
call might behave differently and hence must be rendered undefined.

Jason Zions

Volume-Number: Volume 22, Number 39
Re: qfork()
#678
Author: Paul Eggert
Date: Wed, 26 Dec 1990 21:22
19 lines
1221 bytes
Submitted-by: eggert@twinsun.uucp (Paul Eggert)

jason@cnd.hp.com (Jason Zions) writes:

  The intent of the [Posix.1a draft 5] text, I believe, is that *doing* anything
  between qfork() and exec*() [or _exit()] results in undefined behavior.

I hope this is not the intent.  Current applications often do the following
actions between forking and execing in a child process:

	Redirect file descriptors using open(), close(), dup2().
	Call write() and _exit() if the exec*() fails.
	Change signal handling, uid/gid/pgid/session, working/root directory.
	Call user-defined functions that modify their local variables.

Both fork() and vfork() permit these actions.  Why should qfork() prohibit them?


Volume-Number: Volume 22, Number 42
Re: qfork()
#676
Author: terri_watson
Date: Wed, 26 Dec 1990 22:42
21 lines
1046 bytes
Submitted-by: terri_watson@cis.ohio-state.edu

Of course assuming that the parent doesn't care about the return value
of qfork(), then one could manage to conform to the restrictions by:

	if (qfork() == 0) exit(execve(...));

or for the truly sick-at-heart:

	(status = qfork()) ? 1 : exit(execve(...));

(Of course it _could_ be argued that, in the second example, the very
assignment of status = qfork() violates the rules, but I thought the
humor value was high.)

But _I'm_ not writing code like that! <grin>

Terri


Volume-Number: Volume 22, Number 40
Re: qfork()
#677
Author: Barry Margolin
Date: Wed, 26 Dec 1990 22:54
22 lines
1554 bytes
Submitted-by: barmar@think.uucp (Barry Margolin)

In article <16213@cs.utexas.edu> jason@cnd.hp.com (Jason Zions) writes:
>Instead of replacing "executes any code", I think you could just add the
>phrase "which modifies memory or calls any function" and maintain the
>intent. Examining variables doesn't depend upon the virtual memory
>relationship between child and parent, but munging a stack for a function
>call might behave differently and hence must be rendered undefined.

Rather than "modifies memory" I suggest it be "modifies any variables" or
something like it that refers to high-level objects created by the C
program.  Just examining a variable may modify memory; on a stack machine,
comparing a variable with zero generally requires pushing the variable onto
the stack, and even on a register machine loading the variable into a
register might force the register's old value to be written to memory.
--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

Volume-Number: Volume 22, Number 41
Re: qfork()
#694
Author: Donald Lewine
Date: Thu, 27 Dec 1990 14:31
46 lines
2826 bytes
Submitted-by: lewine@cheshirecat.rtp.dg.com (Donald Lewine)

In article <16213@cs.utexas.edu>, jason@cnd.hp.com (Jason Zions) writes:
|> 
|> I think that loosens the restriction too much.  The intent of the text, I
|> believe, is that *doing* anything between qfork() and exec*() results in
|> undefined behavior. Checking a variable doesn't *do* anything in this sense.
|> The text tries to sidestep the issue of "is qfork() a 4.2BSD-style
|> share-memory pseudo-fork or is it a real fork or what?" An application which
|> takes an action after qfork() and before exec*() that depends upon the
|> implementation of qfork() being any one of those things is inherently
|> unportable.
|> 
|> Instead of replacing "executes any code", I think you could just add the
|> phrase "which modifies memory or calls any function" and maintain the
|> intent. Examining variables doesn't depend upon the virtual memory
|> relationship between child and parent, but munging a stack for a function
|> call might behave differently and hence must be rendered undefined.
|> 

	I think I would vote "NO" on qfork().  I think that there are 
	two better solutions:
	(1) Just use fork() and require the implementation to do it
        in an efficient manner.
    (2) Add some new functions (fexec() ?) which do the fork() and
        exec() in one call.  I know that this is not existing practice
        but neither was sigemptyset() or tcgetispeed().  This may be
        another case where it is better to define a new interface than
        to try to describe the existing practice.  [[Also, qfork() is
        not quite vfork() so it can be shot down on the same basis.]]

    As I think about it, (2) is a much nicer solution to the problem
    than qfork().  The library can then implement fexecl() as a vfork()
    followed by an execl() or a fork() followed by an execl().  The 
    error handling is clean and the semantics are obvious.


--------------------------------------------------------------------
Donald A. Lewine                (508) 870-9008 Voice
Data General Corporation        (508) 366-0750 FAX
4400 Computer Drive. MS D112A
Westboro, MA 01580  U.S.A.

uucp: uunet!dg!lewine   Internet: lewine@cheshirecat.webo.dg.com

Volume-Number: Volume 22, Number 58
Re: qfork()
#679
Author: Peter da Silva
Date: Thu, 27 Dec 1990 18:56
26 lines
1332 bytes
Submitted-by: peter@ficc.ferranti.com (Peter da Silva)

In article <16066@cs.utexas.edu> lewine@cheshirecat.webo.dg.com (Donald Lewine) writes:
> I would propose replacing the phrase: "executes any code" with "calls
> any function defined in this standard or the C standard {8}"  I think
> that does what you mean.

How about "executes any code that changes the state of the program". So,
for example:

	static int child;

	child = 0;
	if(qfork() == 0) {
		child = 1;
		exec...;
	}

At this point, unless I'm confused about legal interpretations of "qfork()",
the value of "child" is indeterminate.
-- 
Peter da Silva.   `-_-'    "Eat hot digital death, mainframe scum!"
+1 713 274 5180.   'U`          -- Attack of the Killer Micros.
peter@ferranti.com

Volume-Number: Volume 22, Number 43
Re: qfork()
#680
Author: marc
Date: Fri, 28 Dec 1990 14:24
26 lines
1597 bytes
Submitted-by: marc@arnor.uucp

It would be useful to know why the function is being proposed.  One
assumes an efficiency improvement, which implies that the specifiers
have an implementation in mind.

Also, it should be remembered that unix systems don't execute C - they
execute machine instructions generated by the C compiler.  So it is
necessary to specify the behavior in machine terms if the compiler
writers are going to comply.  In particular, there is nothing to
prevent the compiler from moving certain computations to the space
between the qfork and the exec!  Does a compiler need to recognize
qfork and exec as special?

Finally - if the intent is to "bundle" fork and exec together,
assuming only that the fork succeeds, would it not be better to
propose fexec* - a set of exec calls which fork first?  Of course,
this makes it absolutely clear that nothing can happen between fork
and exec.  If the combined function is then deemed useless, how can
the qfork/exec idiom be better?
--

Marc Auslander       <marc@ibm.com>


Volume-Number: Volume 22, Number 44
Re: qfork()
#683
Author: John F Haugh II
Date: Fri, 28 Dec 1990 20:54
24 lines
1695 bytes
Submitted-by: jfh@rpp386.cactus.org (John F Haugh II)

In article <16271@cs.utexas.edu> peter@ficc.ferranti.com (Peter da Silva) writes:
>How about "executes any code that changes the state of the program". So,
>for example:

executing =any= code changes the state of the program.  that's the whole
problem with this restriction - how much code is too much.

>At this point, unless I'm confused about legal interpretations of "qfork()",
>the value of "child" is indeterminate.

what is probably needed is a "spawn()" function (god, i never thought i'd
advocate such a critter) which can be responsible for understanding the
legalese.  if the only thing you can do after "qfork()" is "exec()", why
not merge the two steps into a single function?  sounds like the only way
to get it right anyhow.
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org
"While you are here, your wives and girlfriends are dating handsome American
 movie and TV stars. Stars like Tom Selleck, Bruce Willis, and Bart Simpson."

Volume-Number: Volume 22, Number 47
Re: qfork() (The Spawn of spawn())
#684
Author: Peter da Silva
Date: Sun, 30 Dec 1990 03:11
27 lines
1857 bytes
Submitted-by: peter@ficc.ferranti.com (Peter da Silva)

In article <16307@cs.utexas.edu> jfh@rpp386.cactus.org (John F Haugh II) writes:
> what is probably needed is a "spawn()" function (god, i never thought i'd
> advocate such a critter) which can be responsible for understanding the
> legalese.

Wow, this is the same man who ever so politely flamed me for daring to make
such a suggestion. fork can be implemented on a large number of O/Ses, but
it's rather expensive. If the POSIX standard includes something like a
spawn(), that'll sure increase the efficiency of a lot of POSIX software on
systems that have been shoehorned into the model.

Yes, fork() is a cleaner method of creating new processes. Yes, it takes
a fairly complex calling sequence to get spawn() to have anything like
the functionality of fork()...exec(). But I think it'd be worthwhile to
let a little heresy in in exchange for making POSIX more palatable to
folks in poorer environments.

The few cases where spawn() won't fit would usually be better addressed by
something like threads anyway...
-- 
Peter da Silva.   `-_-'    "Eat hot digital death, mainframe scum!"
+1 713 274 5180.   'U`          -- Attack of the Killer Micros.
peter@ferranti.com

Volume-Number: Volume 22, Number 48
Re: qfork()
#685
Author: Dave Mason
Date: Sun, 30 Dec 1990 16:17
44 lines
2656 bytes
Submitted-by: mason@tmsoft.uucp (Dave Mason)

In article <16307@cs.utexas.edu> jfh@rpp386.cactus.org (John F Haugh II) writes:
>Submitted-by: jfh@rpp386.cactus.org (John F Haugh II)
>In article <16271@cs.utexas.edu> peter@ficc.ferranti.com (Peter da Silva) writes:
>>How about "executes any code that changes the state of the program". So,
>>for example:
>executing =any= code changes the state of the program.  that's the whole
>problem with this restriction - how much code is too much.

The real requirement is presumably: ``Must not execute any code that
changes MEMORY.'' As both the parent and child have their own register
sets.  Now, expressing that in a high-level way that is portable may
be quite a trick.  (Think of SPARC vs. 386 vs. HP/3000!)

>>At this point, unless I'm confused about legal interpretations of "qfork()",
>>the value of "child" is indeterminate.

Not if it's a register variable.

>what is probably needed is a "spawn()" function (god, i never thought i'd
>advocate such a critter) which can be responsible for understanding the
>legalese.  if the only thing you can do after "qfork()" is "exec()", why
>not merge the two steps into a single function?  sounds like the only way
>to get it right anyhow.

Not really.  Assuming qfork in the parent can make sure there is
nothing on its stack (that it needs to retrieve later) before it
executes the system call instruction, and the child doesn't do
anything except:
  a) make system calls that change its KERNEL state (open files, UID, etc.)
  b) change register variables
qfork can do everything useful that vfork can. (And because there's no
memory being changed by the child that can be inspected by the parent, a
fork implementation of qfork is still legal.)

(Personally I think the whole vfork/qfork/spawn thing is a horrible hack,
but if we're going to be stuck with it, lets at least do it right!)

-- 
"Don't break it if you can't fix it."                             ../Dave Mason
                                                  <mason%tmsoft@cs.toronto.edu>

Volume-Number: Volume 22, Number 49
Re: qfork()
#689
Author: John F Haugh II
Date: Wed, 02 Jan 1991 13:17
21 lines
1703 bytes
Submitted-by: jfh@rpp386.cactus.org (John F Haugh II)

In article <16370@cs.utexas.edu> mason@tmsoft.uucp (Dave Mason) writes:
>The real requirement is presumably: ``Must not execute any code that
>changes MEMORY.'' As both the parent and child have their own register
>sets.  Now, expressing that in a high-level way that is portable may
>be quite a trick.  (Think of SPARC vs. 386 vs. HP/3000!)

Yes, that is the essence of the problem - there are CPUs out there
which have a very small number of CPU registers (perhaps only two
or three) available to the user.  As I recall, the TI 9900 has one
register which points to a location in memory where the rest of the
"registers" exist, and of course older HP CPU's have their own ideas
about where data is stored.
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org
"While you are here, your wives and girlfriends are dating handsome American
 movie and TV stars. Stars like Tom Selleck, Bruce Willis, and Bart Simpson."

Volume-Number: Volume 22, Number 53
Re: qfork() (The Spawn of spawn())
#691
Author: Guido van Rossum
Date: Thu, 03 Jan 1991 09:42
66 lines
3806 bytes
Submitted-by: guido@cwi.nl (Guido van Rossum)

peter@ficc.ferranti.com (Peter da Silva) writes:

>Yes, fork() is a cleaner method of creating new processes. Yes, it takes
>a fairly complex calling sequence to get spawn() to have anything like
>the functionality of fork()...exec(). But I think it'd be worthwhile to
>let a little heresy in in exchange for making POSIX more palatable to
>folks in poorer environments.

I know of precedents even in OS'es that support fork(): Amoeba and
Topaz support a variant of what you call spawn().  (Note that the
spawn() functions found in Microsoft C for MS-DOS emulate either just
exec() or fork()+exec()+wait(), which is much less powerful, but
all that MS-DOS can support (last time I looked).)

Amoeba's UNIX emulation supports fork(), but since Amoeba has no virtual
memory (yet), it is fairly expensive.  An alternative function is
provided, "newproc()", which creates a child process running a
different program (and, because it is Amoeba, also running on a
different processor, in the average case) just like fork()+exec() would
do, only much cheaper since the parent's address space never gets
copied.

Amoeba's newproc() lets you change the two perhaps most important
bits of "kernel state" that programs fiddle between fork() and exec():
the set of signals to be ignored and the set of open file descriptors.
The interface lets you specify a bitmask of signals that are to be
ignored in the child (or -1 to inherit the parent's ignored signals)
and an array of file descriptors which provides a mapping between file
descriptors in the parent and in the child (also with an option to
inherit all file descriptors from the parent).

Amoeba's library functions popen() and system() have been changed to
use newproc(), and the shell uses newproc() for most simple program
invocations (environment manipulations and a few other things make it
fall back on fork()).  The performance gain was well worth the hacking.

The newproc() interface could also be implemented on UNIX using
[v]fork() and exec(), although extreme cases of file descriptor
permutations could fail if not enough spare file descriptors were
available.

The Topaz operating system (an Ultrix clone for Firefly multiprocessors
developed at DEC's System Research Centre in Palo Alto) has a similar
but more complete feature in its Modula-2+ (and now Modula-3?) version
of the OS interface, not because Topaz doesn't have virtual memory (it
does), but because the average Modula-2+ binary is several megabytes.

In Topaz, you create a descriptor for the new process, which represents
its relevant kernel state.  The descriptor is initialized to inherit
all state from the parent, and you can call library functions that
modify various parts of the descriptor; this is the equivalent of what
you would do between fork() and exec() in real UNIX.  Finally you make
a system call that presents the descriptor to the kernel for creation.
Yes, it's a bit more tedious, but it has all the required
functionality, unlike (it seems to me) the proposed qfork() with its
not-well-understood restrictions on modifying memory.

--Guido

--
Guido van Rossum, CWI, Amsterdam <guido@cwi.nl>
"Well I'm a plumber.  I can't act."

Volume-Number: Volume 22, Number 55
Re: qfork() (The Spawn of spawn())
#695
Author: Lenox H. Brassell
Date: Fri, 04 Jan 1991 18:04
21 lines
1419 bytes
Submitted-by: lenox@media-lab.MEDIA.MIT.EDU (Lenox H. Brassell)

In article <16478@cs.utexas.edu>, guido@cwi.nl (Guido van Rossum) writes:
> (Note that the
> spawn() functions found in Microsoft C for MS-DOS emulate either just
> exec() or fork()+exec()+wait(), which is much less powerful, but
> all that MS-DOS can support (last time I looked).)
> 

Using Microsoft C under OS/2, you can pass P_NOWAIT as the first
argument to the MSC spawn() functions, and the child process will run
asynchronously.  The spawn() functions return the child process's PID
in this case.

Although MSC is certainly not a UNIX compiler, this "prior art" might
be a good place to start if POSIX needs a "safe" qfork()+exec() service.


--lenox (lenox@media-lab.mit.edu)

Volume-Number: Volume 22, Number 59
Re: qfork() (The Spawn of spawn())
#697
Author: Peter da Silva
Date: Fri, 04 Jan 1991 19:17
14 lines
1176 bytes
Submitted-by: peter@ficc.ferranti.com (Peter da Silva)

( Guido lists a couple of systems where a function with spawn() type
  semantics (create a new process and load a program)... )

Also, most DEC operating systems use this sort of call for process creation.
AmigaOS does things in the opposite order: you load a segment and then use
CreateProc to start executing it.
-- 
Peter da Silva.   `-_-'    "Eat hot digital death, mainframe scum!"
+1 713 274 5180.   'U`          -- Attack of the Killer Micros.
peter@ferranti.com

Volume-Number: Volume 22, Number 61
Re: qfork() (The Spawn of spawn())
#700
Author: Loren L. Hart
Date: Sat, 05 Jan 1991 00:43
41 lines
2235 bytes
Submitted-by: loren@Eng.Sun.COM (Loren L. Hart)

In article <16478@cs.utexas.edu> guido@cwi.nl (Guido van Rossum) writes:
>Submitted-by: guido@cwi.nl (Guido van Rossum)
>
>peter@ficc.ferranti.com (Peter da Silva) writes:
>
>>Yes, fork() is a cleaner method of creating new processes. Yes, it takes
>>a fairly complex calling sequence to get spawn() to have anything like
>>the functionality of fork()...exec(). But I think it'd be worthwhile to
>>let a little heresy in in exchange for making POSIX more palatable to
>>folks in poorer environments.
>
>I know of precedents even in OS'es that support fork(): Amoeba and
>Topaz support a variant of what you call spawn().  (Note that the
>spawn() functions found in Microsoft C for MS-DOS emulate either just
>exec() or fork()+exec()+wait(), which is much less powerful, but
>all that MS-DOS can support (last time I looked).)

The Ada POSIX Draft currently has some sort of spawn command, since
fork is not necessicarily safe with respect to Ada Tasks.  I don't rember
the specific routine, but it is likely to go through some change before
the Ada version of the standard is finalized.  I would hope that this 
spawn capability will be merged back into the 1003.1 standard at some
point in the future.

------------------------------------------------------------
Mr. Loren L. Hart
The Ada Ace Group, Inc.
PO Box 36195
San Jose, CA  95158
loren@cup.portal.com

--
-----------------------------------------------------------------------------
Loren L. Hart			The Ada Ace Group, Inc
loren@cup.portal.com		P.O. Box 36195
				San Jose, CA  95158


Volume-Number: Volume 22, Number 62
Re: qfork()
#699
Author: Doug Gwyn
Date: Mon, 07 Jan 1991 22:15
15 lines
1337 bytes
Submitted-by: gwyn@smoke.brl.mil (Doug Gwyn)

In article <16213@cs.utexas.edu> jason@cnd.hp.com (Jason Zions) writes:
>I think that loosens the restriction too much.  The intent of the text, I
>believe, is that *doing* anything between qfork() and exec*() results in
>undefined behavior. Checking a variable doesn't *do* anything in this sense.
>The text tries to sidestep the issue of "is qfork() a 4.2BSD-style
>share-memory pseudo-fork or is it a real fork or what?"

We (IEEE P1003) deliberately omitted vfork() from the POSIX spec
because it was not necessary, given a decent implementation of fork().
Why is this notion being reintroduced (quite carelessly so far as I can
tell from the quotes so far) for 1003.1a?

Volume-Number: Volume 22, Number 66
Re: qfork() (the spawn of Spawn())
#704
Author: Peter da Silva
Date: Mon, 14 Jan 1991 14:19
51 lines
2510 bytes
Submitted-by: peter@ficc.ferranti.com (Peter da Silva)

In article <16875@cs.utexas.edu> gwyn@smoke.brl.mil (Doug Gwyn) writes:
> We (IEEE P1003) deliberately omitted vfork() from the POSIX spec
> because it was not necessary, given a decent implementation of fork().

POSIX is not supposed to be a standard for UNIX only. In many non-UNIX
environments a "decent implementation of fork" is quite difficult and
may even be impossible. A poor implementation of fork() is likely to
clobber performance, given how common it is in UNIX code.

I suspect that in practice most implementations will use an efficient
call in the internals of system() and similar library routines. Either
direct spawns or an implementatio of qfork that looks something like:

	qfork()
	{
		Save stack context.
		Vector open(), exit(), etc to pseudo routines that
			save flags (either adjust jump table or set
			a flag that tells open we're "in a qchild".
		Return 0;
	}

	qopen() /* new version of open */
	{
		open file, save descriptor
	}
	...

	qexec() /* new version of exec */
	{
		call spawn, passing it the info for the new execution
			environment (juggling fds, signals, etc).
		Return execution environment to the one set up back
			at the qfork (juggle fds, etc)
		longjump back to saved stack context, returning child pid.
	}

This gets around the cost of creating a new execution context that will
simply be juggled briefly and discarded.

Something like this will be needed to get decent performance out of systems
like VMS where creating a new process is quite expensive. Why not standardise
this so portable programs can take advantage of it?
-- 
Peter da Silva.   `-_-'   "Have you hugged your wolf today?"
+1 713 274 5180.   'U`
peter@ferranti.com

Volume-Number: Volume 22, Number 68
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads