The pymdl book
25. MDL as a system process
This chapter treats MDL considered as executing in an operating-system process, and interactions between MDL and other operating-system processes. See also section 21.8.13.
pymdl's own. Process information such as
TIMErefers to the host Python process. IPC is implemented with Unix domain datagram sockets, so pymdl instances on the same host can exchange messages. This preserves MDL's naming and handler interface without an ITS installation. Section 23.4 explains the historical interface and the setup required here.
23.1. TIME
TIME takes any number of arguments, which are evaluated but ignored, and
returns a FLOAT giving the number of seconds of CPU time the MDL process has
used so far. TIME is often used in machine-level debugging to examine the
values of its arguments, by having MDL's superior process (say, DDT) plant a
breakpoint in the code for TIME.
<TYPE <TIME>> ⇒ FLOAT
<TYPE <TIME 1 2 3>> ⇒ FLOAT
The arguments really are evaluated and really are ignored, which is the whole of
the debugging trick described: a breakpoint in TIME gets you a look at whatever
you cared to pass it.
pymdl's own.
TIMEanswers this process's CPU seconds, which is a real number about a real process -- it is simply a much faster process than a KA-10. Chapter 31's measurements use it, and chapter 32'sMATprints it in listings. The one thing it is not is comparable with a 1979 figure.
23.2. Names
<UNAME>
returns a STRING which is the "user name" of MDL's process. This is the
"uname" process-control variable in the ITS version and the logged-in directory
in the Tenex and Tops-20 versions.
<XUNAME>
returns a STRING which is the "intended user name" of MDL's process. This is
the "xuname" process-control variable in the ITS version and identical to
<UNAME> in the Tenex and Tops-20 versions.
<JNAME>
returns a STRING which is the "job name" of MDL's process. This is the
"jname" process-control variable in the ITS version and the SETNM name in the
Tenex and Tops-20 versions. The characters belong to the "sixbit" or "printing"
subset of ASCII, namely those between <ASCII *40*> and <ASCII *137*>
inclusive.
<XJNAME>
returns a STRING which is the "intended job name" of MDL's process. This is
the "xjname" process-control variable in the ITS version and identical to
<JNAME> in the Tenex and Tops-20 versions.
<TYPE <UNAME>> ⇒ STRING
<TYPE <JNAME>> ⇒ STRING
<=? <UNAME> <XUNAME>> ⇒ T
<=? <JNAME> <XJNAME>> ⇒ T
<==? <UNAME> <XUNAME>> ⇒ #FALSE ()
<JNAME> ⇒ "MDL"
The two =? lines are the Tenex behaviour the manual describes, which is what
pymdl follows: there is no distinction here between a name and an intended name,
because nothing can rename the job out from under it. The ==? line is section
8.2.2 rather than this chapter -- each call builds a fresh STRING, and two
STRINGs that read alike are not the same object. <JNAME> is "MDL",
which is what an ITS job running the interpreter would have been called.
<UNAME> is not quoted above because it is not fixed: it reports the user this
process is running as, in the sixbit-safe spelling the section requires, so it
differs from machine to machine exactly as it did on ITS.
23.3. Exits
<LOGOUT>
attempts to log out the process in which it is executed. It will succeed only if
the MDL is the top-level process, that is, it is running disowned or as a daemon.
If it succeeds, it of course never returns. If it does not, it returns
#FALSE ().
<LOGOUT> ⇒ #FALSE ()
#FALSE () is the documented answer for a process that is not top-level, and it
is the answer here: pymdl declines to log anybody out of anything. The
interesting part is that this is a normal return, so the manual's own
idiom -- call it, and carry on if it comes back -- works unchanged.
<QUIT>
causes MDL to stop running, in an orderly manner. In the ITS version, it is
equivalent to a .LOGOUT 1 instruction. In the Tenex and Tops-20 versions, it is
equivalent to a control-C signal, and control passes to the superior process.
<VALRET string-or-fix>
("value return") seldom returns. It passes control back up the process tree to
the superior of MDL, passing its argument as a message to that superior. If it
does return, the value is #FALSE (). If the argument is a STRING, it is
passed to the superior as a command to be executed, via .VALUE in the ITS
version and RSCAN in the Tops-20 version. If the argument is a FIX, it is
passed to the superior as the "effective address" of a .BREAK 16 instruction in
the ITS version and ignored in other versions.
pymdl's own.
<QUIT>ends the session, as it says.<VALRET>has no superior to hand a command to and returns#FALSE (), which is the documented "if it does return" case -- so an era program that tries to hand its shell a command finds out politely instead of silently appearing to succeed. Chapter 2 has the other ways a pymdl session ends, which the era did not have: end of input on a pipe, and^Cat a terminal.
23.4. Inter-process Communication
All of the SUBRs in this section are available only in the ITS version.
The IPC ("inter-process communication") device is treated as an I/O device by ITS
but not explicitly so by MDL: that is, it is never OPENed. It allows MDL to
communicate with other ITS processes by means of sending and receiving messages.
A process identifies itself as sender or recipient of a message with an ordered
pair of "sixbit" STRINGs, which are often but not always <UNAME> and
<JNAME>. A message has a "body" and a "type".
23.4.1. SEND and SEND-WAIT
<SEND othern1 othern2 body type myname1 myname2>
<SEND-WAIT othern1 othern2 body type myname1 myname2>
both send an IPC message to any job that is listening for it as othern1 othern2.
body must be either a STRING, or a UVECTOR of objects of PRIMTYPE WORD.
type is an optional FIX, 0 by default, which is part of the information the
other guy receives. The last two arguments are from whom the message is to be
sent. These are optional, and <UNAME> and <JNAME> respectively are used by
default. SEND returns a FALSE if no one is listening, while SEND-WAIT hangs
until someone wants it. Both return T if someone accepts the message.
<SEND "SOMEBODY" "ELSE" "a message"> ⇒ #FALSE ()
This example assumes that no pymdl instance is listening under the names
SOMEBODY and ELSE. SEND returns T when a recipient accepts the
message. SEND-WAIT retries until delivery succeeds, so it can wait
indefinitely if the recipient never becomes available.
23.4.2. The "IPC" Interrupt
When your MDL process receives an IPC message, "IPC" occurs (chapter 23). A
handler is called with either four or six arguments gleaned from the message.
body, type, othern1, and othern2 are supplied only if they are not this process's
<UNAME> and <JNAME>.
There is a built-in HANDLER for the "IPC" interrupt, with a handler named
IPC-HANDLER and 0 in the PROCESS slot. The handler prints out on the
terminal the body, whom it is from, the type if not 0, and whom it is to if not
<UNAME> <JNAME>. If the type is 1 and the body is a STRING, then, after
the message information is printed out, the STRING is PARSEd and EVALuated.
That last sentence deserves to be read twice. A message of type 1 arriving
from another job is parsed and evaluated, by default, with no further ceremony --
which is to say ITS MDL shipped with remote code execution enabled and documented
as a feature. It is a fair picture of how much a 1979 timesharing machine
trusted the people on it.
23.4.3. IPC-OFF
<IPC-OFF> stops all listening on the IPC device.
23.4.4. IPC-ON
<IPC-ON myname1 myname2>
causes listening on the IPC device as myname1 myname2. If no arguments are
provided, listening is on <UNAME> <JNAME>. When a message arrives, "IPC"
occurs.
MDL is initially listening as <UNAME> <JNAME> with the built-in HANDLER set
up on the "IPC" interrupt with a priority of 1.
<IPC-OFF> ⇒ T
<IPC-ON> ⇒ T
pymdl's own. A fresh ITS-personality interpreter installs the default
IPC-HANDLER, but socket listening starts only when<IPC-ON>is called.<IPC-OFF>closes the socket. Instances communicate through the same rendezvous directory, selected byPYMDL_IPC_DIRor, by default,pymdl-ipcunder the host temporary directory. Give each listener its own pair of names.tests/test_mudinq.pychecks message and acknowledgement exchange between interpreters.
23.4.5. DEMSIG
<DEMSIG daemon:string>
signals to ITS (directly, not via the IPC device) that the daemon named by its
argument should run now. It returns T if the daemon exists, #FALSE ()
otherwise.
<DEMSIG "NO-SUCH-DAEMON"> ⇒ #FALSE ()
pymdl's own.
DEMSIGaddresses an ITS daemon, not an IPC listener. Its behavior should not be inferred fromSEND: the two use different operating-system mechanisms in the original implementation.