Greg A. Woods wrote:
[[ I'm digging through old mail -- my summer has
been preoccupied by
things that kept me from most everything else, including computing. ]]
At Sun, 1 Aug 2021 18:13:18 -0600, Andrew Warkentin <andreww591(a)gmail.com> wrote:
Subject: Re: [TUHS] Systematic approach to command-line interfaces
There's a third kind of primitive that is superior to either spawn()
or fork() IMO, specifically one that creates a completely empty child
process and returns a context that lets the parent set up the child's
state using normal APIs.
That's actually what fork(2) is, effectively -- it sets up a new process
that then effectively has control over its own destiny, but only by
using code supplied by the parent process, and thus it is also working
within the limits of the Unix security model.
The original post above made me think of the TENEX (later TOPS-20)
primatives for fork (a noun, aka process) control:
SFORK -- create an empty fork/process (halted)
GET -- map executable
SFORK -- start fork
HFORK -- halt a running fork
KFORK -- kill a fork
SPJFN -- set primary file job file numbers (stdin/stdout)
SPLFK -- splice a fork into tree
TENEX, like UNIX was created with with knowledge of the Berkeley
Timesharing System (SDS 940) and MULTICS. Like MULTICS, TENEX was
designed from square one as a VM system, and I believe the 4.2BSD
specified mmap call was inspired by the TENEX PMAP call (which can map
file pages into a process AND map process pages into a file, and map
process pages from another process).
The "halted" process state was also used when a user typed CTRL/C. A
halted process could be debugged (either in-process, entering a newly
mapped debugger, or one already linked in, or out-of-process by
splicing a debugger into the process tree). Threads were easily
implemented by mapping (selected pages of) the parent process (leaving
others copy-on-write, or zero-fill for thread-local stoage).
Starting on small machines (an 8KW PDP-7, and a (28KW?) PDP-11) UNIX
placed a premium on maximum usefulness in the minimum space.
The PDP-7 source we have implements fork (implemented, as on the
PDP-11 by swapping out the forking process) but not exec!
The Plan9 rfork unbundles traditional Unix descriptor and memory
inheritance behaviors.
For all the VM generality, a sore place (for me) in TENEX/TOPS-20, a
single file descriptor (job file number) was shared by all processes
in a login session ("job"). "Primary" input and output streams were
however per-process, but, ISTR there was nothing to stop another
process from closing a stream another process was using.
And like MULTICS, TENEX had byte-stream I/O, implemented day-one for
disk files (I'd have to look, but system code may well have
implemented it by issuing PMAP calls (monitor call code could invoke
monitor calls)), and most simple user programs used it, since it was
simpler to program than file mapping.
refs:
https://opost.com/tenex/tenex72.txt
https://www.opennet.ru/docs/BSD/design-44bsd-eng/x312.html
http://www.bitsavers.org/pdf/dec/pdp10/TOPS20/AA-4166E-TM_TOPS-20_Monitor_C…
P.S.
And on the ORIGINAL topic, TOPS-20 started with code from the TENEX
EXEC (shell) that implemented command completion and incremental, and
made it the COMND system call (tho it could well have been a shared library,
since almost all of the COMND code called other system calls to do the work).