mirror of
https://github.com/PDP-10/its.git
synced 2026-01-11 23:53:12 +00:00
These were all files included in MIT's 1999 release of SYSDOC and SYSTEM, so they need the license header. CHAORD is an XGP text file; XGP processors should ignore unknown directives so ;comment should work.
827 lines
36 KiB
Plaintext
Executable File
827 lines
36 KiB
Plaintext
Executable File
Copyright (c) 1999 Massachusetts Institute of Technology
|
||
See the COPYING file at the top-level directory of this project.
|
||
------------------------------
|
||
|
||
JOBS IN ITS
|
||
|
||
|
||
@. ABSTRACT.
|
||
|
||
In ITS, a "job" is an entity that consists mainly of memory to hold
|
||
a program, registers to run it with, and I/O channels for it to do
|
||
I/O on through the system. Whenever a program is
|
||
running, it must be running "in" some job. Jobs are structured
|
||
into trees; the root of a tree is a "top-level" job, and for any
|
||
job, the job one step closer to the root is the first job's superior;
|
||
the first job is one of its inferiors. Normally, each user has
|
||
one tree of jobs, but he may also have a few other secondary trees.
|
||
|
||
Jobs may read anything associated with any job, but usually may write
|
||
only their direct inferiors.
|
||
|
||
TABLE OF CONTENTS
|
||
|
||
A. OVERVIEW OF JOBS.
|
||
|
||
B. CREATING AND DELETING INFERIORS, AND OTHER METHODS OF CHANGING THE
|
||
0. OPENING THE USR: DEVICE - A BASIC TOOL.
|
||
1. CREATION
|
||
2. DELETION
|
||
3. DISOWNING
|
||
4. REOWNING
|
||
5. DETACHING
|
||
6. ATTACHING
|
||
7. LOGGING IN
|
||
8. LOGGING OUT AND GUNNING
|
||
|
||
C. CONTROL OF INFERIORS.
|
||
1. READING AND WRITING
|
||
2. SHARING MEMORY BETWEEN JOBS
|
||
3. LOADING
|
||
a. Resetting
|
||
4. DUMPING
|
||
a. Pure dumping
|
||
b. Impure dumping
|
||
5. STARTING AND STOPPING
|
||
6. HANDLING INTERRUPTS
|
||
7. DEBUGGING CONTROLS.
|
||
8. TTY PASSING
|
||
|
||
D. SYSTEM JOBS AND WHAT THEY DO
|
||
1. THE SYSTEM JOB.
|
||
2. THE CORE JOB.
|
||
3. DEMON JOBS.
|
||
|
||
A. OVERVIEW OF JOBS.
|
||
|
||
Each ITS job has an address space, the slots of which may be filled
|
||
with various types of memory, perhaps shared with other jobs; its own
|
||
set of accumulators (copied temporarily into the real ones when the
|
||
job is running); a program counter (PC); sixteen I/O channels, each of
|
||
which may be used to handle a device or file; system "user variables"
|
||
with which the program in the job may communicate with the system;
|
||
and other variables used by the system in scheduling
|
||
or swapping the job, or as temporaries for system call routines.
|
||
|
||
The word "user" has two meanings on ITS: one is the human or other being
|
||
using a terminal; the other is an individual "user job". In specific
|
||
contexts either "job" or "user" sounds better for their common meaning.
|
||
A "program", however, is a more abstract entity; the same program may
|
||
be running in several jobs (but using different files, etc. in each).
|
||
|
||
Each job is identified by two names, the UNAME and the JNAME, each of
|
||
which is up to six SIXBIT characters, left justified in a PDP-10 word.
|
||
They are available in the .UNAME and .JNAME user variables of the job.
|
||
These two names uniquely identify the job.
|
||
All the jobs in a tree must have the same uname. Two trees may have
|
||
the same uname; that usually means that they really correspond to the
|
||
same user.
|
||
|
||
Each job is also uniquely identified by its "job number" (or
|
||
"user number"), which is a small positive number. This number
|
||
is the usual way to specify a job in a system call. A job may find
|
||
out its own number by reading its .UIND user variable; its superior's
|
||
is in its own .SUPPRO user variable. The term "user index"
|
||
may mean, loosely, the job number, but more strictly it means the
|
||
job number times LUBLK, the length of the system's per-job data block
|
||
(the "user variable block"). Supported communications paths
|
||
between the user and the system use the job number, not the user index
|
||
itself, even if the term "user index" is used.
|
||
|
||
A job has several "user variables" which are really variables in the
|
||
system that pertain to it, and are readable by that job or others
|
||
using the .USET and .SUSET UUO's (see ITS UUOS). Each user variable
|
||
has a name, which starts with ".". User variables can be opened in
|
||
DDT just like memory locations, although what DDT does to access them
|
||
is a .USET. Some user variables, such as .UIND, .SUPPRO, .UNAME and
|
||
.JNAME mentioned above, exist solely to be read by programs. Others
|
||
also allow the program to tell the system how to treat it; examples
|
||
are .OPTION, which contains bits that enable various system features,
|
||
and .MASK, which is used to enable user interrupts (see ITS INTRUP).
|
||
A complete list of user variables and what they contain is in the
|
||
file ITS USETS.
|
||
|
||
When a user connects to ITS by typing ^Z or CALL on a terminal, he is
|
||
supplied with a single top-level job using that terminal, running the
|
||
program "DDT" (on DM, "MONIT" is used instead). The jname of that
|
||
job is always "HACTRN" (pronounced "hack-tran"),
|
||
and the job is called "a HACTRN". The uname
|
||
will be three backarrows followed by three digits, identifying the tree
|
||
as non-logged-in. "Logging in" is nothing other than altering the uname
|
||
of the hactrn to a more meaningful name. It makes little direct
|
||
difference.
|
||
DDT and MONIT both provide facilities for creating other jobs for the
|
||
user, loading programs into them, and running them. There are no user
|
||
commands per se for controlling jobs built into ITS; instead, the
|
||
user gives commands to DDT or MONIT telling them to execute the system
|
||
calls to control his other jobs.
|
||
|
||
The two main types of job trees are the console-controlled trees and
|
||
the non-console-controlled (or "disconsolate") trees. A console
|
||
controlled tree has one terminal which is "in use as a console" by
|
||
the whole tree. All the jobs in the tree can refer to that terminal as
|
||
device TTY:. The number of that terminal can be found in the .CNSL
|
||
variable of any job of the tree.
|
||
At any time, only one of the jobs in the tree has
|
||
permission to do I/O to the console; that job is said to "own"
|
||
the console. Ownership is transferred by means of .ATTY and .DTTY
|
||
UUO's executed by jobs in the tree (see ITS TTY). If ^Z (or CALL on
|
||
TV's) is typed on a console, the job that owns it gets a fatal
|
||
interrupt. The jobs may also have other terminals open "as devices",
|
||
but those can be in use only by a single job, not the whole tree.
|
||
The console-controlled trees are usually the ones with hactrn's at the
|
||
top.
|
||
|
||
Disconsolate trees do not have any console, but in all other respects
|
||
bahave just like console-controlled trees. They may or may not be
|
||
"disowned". If they are, they get worse treatment from the scheduler
|
||
and swapper, and also may be more conveniently "reowned" (made into a
|
||
subtree of another tree - see below). Usually only system demons and
|
||
job-device handlers are disconsolate non-disowned trees.
|
||
Job-devices will have a .CNSL equal to that of the tree of the
|
||
job using the job-device. Other disconsolate jobs will have a .CNSL
|
||
of -1 if they are scheduled as part of the system, or -2 if scheduled
|
||
as disowned jobs.
|
||
|
||
Jobs often refer to each other using a device, the "USR" device. A job
|
||
may be opened on the USR device by specifying its uname and jname as the
|
||
opened filenames. It is then possible to examine or deposit the job's
|
||
memory or user variables, etc. This is why DDT, when it starts up,
|
||
mentions its uname and jname by saying "USR:<uname> <jname>".
|
||
The USR device should not be confused
|
||
with the JOB device, which is a mechanism for creating software devices
|
||
which enables the system calls that manipulate the device to be
|
||
simulated and handled by a user program, the job-device handler program
|
||
(See ITS JOBDEV).
|
||
|
||
The remainder of this file is devoted to desribing the ITS system calls
|
||
with which jobs may create, delete, sense and control other jobs.
|
||
|
||
B. CREATING AND DELETING INFERIORS, AND OTHER METHODS OF CHANGING THE
|
||
TREE STRUCTURE OF JOBS.
|
||
|
||
0. OPENING THE USR: DEVICE - A BASIC TOOL.
|
||
|
||
Unfortunately, many different things are done by opening the
|
||
USR device in different ways in different situations. They
|
||
include creation of inferiors, reowning disowned jobs, selection
|
||
of existing jobs (inferiors or not), and testing for the existence
|
||
of a job. Opening USR is the ONLY way to do those things. What's
|
||
more, a job's memory cannot be read or written without having a USR
|
||
channel open in the appropriate direction, and a job's user variables
|
||
cannot be read or written without at least one USR channel open in
|
||
either direction. Thus, opening USR: is very important. It is intended
|
||
that this mechanism will be made more rational in the future.
|
||
|
||
This section will describe what opening the USR device will do,
|
||
organised by how it is done. Later sections will say what
|
||
to do to achieve a specific goal.
|
||
|
||
By convention, "USRI" and "USRO" are the canonical names in MIDAS
|
||
programs for the I/O channels used for opening the USR device for
|
||
input and output, respectively. Their use in an inferior-handling
|
||
program is a sort of comment.
|
||
|
||
A USR: open always specifies two filenames. Normally they are
|
||
the uname and jname of the job to be opened. However, 0 may
|
||
be used as the first filename to specify your own uname.
|
||
If the second filename is 0, then the first is not really a
|
||
name but a job spec; this crock makes it possible to open a
|
||
job known only by its number.
|
||
|
||
A USR: open must also ask for either block mode or unit mode.
|
||
Right now SIOT on unit mode USR channels is not as efficient as
|
||
IOT on block mode channels, so it is usually better to open in
|
||
block mode. In any case, this choice is orthogonal to everything
|
||
else.
|
||
|
||
All USR: opens should specify image mode. Ascii mode doesn't now
|
||
exist for the USR device, and if you ask for it you will get image
|
||
mode instead, so for compatibility with the future you should ask
|
||
for image mode.
|
||
|
||
There are four things specified in each USR open that affect the
|
||
actions taken in important ways. They are the two filenames,
|
||
the direction, and the device-dependent bit 1.4 of the open-mode,
|
||
known here (and inside ITS) as UBPFJ.
|
||
|
||
If UBPFJ is set, the open may be for reading only, and will fail with
|
||
code 4 if the job specified by the uname and jname does not exist.
|
||
If the job does exist, it will be opened as a "foreign job", which
|
||
means that the opening job may not modify it at all using the
|
||
channel opened in this way. Also, the process of opening the job
|
||
with UBPFJ is guaranteed not to alter it. This style of open is
|
||
good for asking whether a job exists with particular names.
|
||
|
||
Without UBPFJ, if the open is for writing, then
|
||
if a job with the specified uname and jname exists and is the
|
||
inferior of the job doing the open, it will be opened for
|
||
writing, with no special side effects.
|
||
If a job with the specified names exists and can be reowned
|
||
(it is a top-level disowned job), it will be reowned, and
|
||
opened for writing. Reowning may change its uname or jname,
|
||
so whenever an open might reown a job the program should
|
||
read back the uname and jname of the opened job just in case.
|
||
If no job with the specified names exists, then an attempt is
|
||
made to create an inferior by that name. If the specified
|
||
uname isn't the same as yours, that is impossible, and the open
|
||
fails with code 20. If you already have the maximum number of
|
||
inferiors, it fails with code 5. If there are no job slots available,
|
||
it fails with code 6. If the attempt succeeds, the new inferior
|
||
is opened for writing.
|
||
Otherwise (a job with the specified names exists, but isn't
|
||
an inferior of the running job already and can't be made one
|
||
by reowning it), the open fails with code 12.
|
||
Note that if an open for writing succeeds, you know the job that
|
||
is open is your inferior (thought it might not have been so before).
|
||
|
||
An open for reading, without UBPFJ, is like an open for writing
|
||
except that when the job exists but isn't an inferior and can't
|
||
be reowned, it will be opened as a foreign job (as if UBPFJ were 1).
|
||
|
||
To understand these possibilities better, think of the FOO$J command in
|
||
DDT, which means, essentially, "open the job named FOO". That command
|
||
will reselect a job named FOO if there is one; if not, it will create
|
||
one. If there is a job named FOO that isn't a direct inferior of DDT,
|
||
it will be selected, but will be unwriteable (DDT will type a "#"). If
|
||
there is a disowned job named FOO, it will be reowned (made into an
|
||
inferior of DDT), and DDT will type ":$REOWNED$").
|
||
|
||
There is no easy way to tell after the fact what has happened when
|
||
an open without UBPFJ has succeeded. You know you have an inferior,
|
||
if an open for writing succeeds,
|
||
but whether it is new, reowned or old is forgotten. If you care,
|
||
you should find out in advance what is going to happen by doing
|
||
an open with UBPFJ set. If it fails, you will get a newly created
|
||
inferior. If it succeeds, look at the .APRC and .SUPPRO user variables.
|
||
If both are negative, you have a top-level disowned job which
|
||
would be reowned. If .SUPPRO equals your .UIND variable, the
|
||
job is your inferior already. Otherwise, an open for writing
|
||
would fail, and an open for reading would open it as a foreign job.
|
||
|
||
Some information is still available after an open.
|
||
The job's .UPC variable will be nonzero iff the job has ever run
|
||
(because the user-mode bit, %PCUSR, will be 1).
|
||
If the job has been run, then it certainly wasn't just created.
|
||
Also, if the job's uname or jname was changed by the open, then
|
||
it must have been reowned.
|
||
|
||
1. CREATION
|
||
|
||
In order to create an inferior, one must choose a jname for it.
|
||
Its uname will have to be the same as its creator's, and together
|
||
the uname and jname must be unique among all jobs in existence.
|
||
An attempt to create an inferior looks just like an attempt to
|
||
open an existing job, so if the would-be creator is mistaken about
|
||
the uniqueness of the jname it may get confused (a way out of this
|
||
problem is described later).
|
||
|
||
Given a jname which isn't in use, an inferior of that name may be
|
||
created by simply opening the USR device with the uname and jname
|
||
as filenames, as in section 0. You should open a channel in each
|
||
direction (call the input channel USRI and the output channel USRO).
|
||
If you are unwilling to try to live with a foreign job, do the
|
||
output open first.
|
||
|
||
One way to make sure of getting a newly created job is to check
|
||
in advance that the names are not in use, by opening them with
|
||
UBPFJ (see section 0) before actually trying to create the job.
|
||
If the test open succeeds, close the channel again and
|
||
pick a new jname.
|
||
|
||
The new inferior will have 1K of zeroed unshared core,
|
||
and will not be running (its .USTP will be nonzero).
|
||
|
||
Then, if you wish to handle interrupts from the inferior,
|
||
read the inferior's interrupt bit, which may be found in
|
||
the inferior's .INTB variable, and remember it somewhere.
|
||
That is the bit .IFPIR on which YOU will be interrupted,
|
||
if the inferior gets a fatal interrupt.
|
||
|
||
2. DELETION
|
||
|
||
Inferiors do not need to remain open to continue to exist. Simply
|
||
closing the channels one is open on does not delete it; it is
|
||
merely hard to refer to until it is opened again. This is so
|
||
that it is possible to have many inferiors without tying up many
|
||
I/O channels. When it IS desired to delete an inferior, the
|
||
.UCLOSE uuo should be used:
|
||
|
||
.UCLOSE <channel>,
|
||
|
||
This uuo kills the inferior open on <channel>. All the channels
|
||
it is open on are closed. The uuo does not skip.
|
||
If a foreign job instead of an inferior is open, all the channels
|
||
in this job that it is open on are closed, but it is not killed.
|
||
If there isn't a job open on the specified channel, an ILOPR
|
||
interrupt happens.
|
||
|
||
3. DISOWNING
|
||
|
||
Disowning an inferior causes it to continue to exist, but no longer
|
||
as your inferior. This can be useful for two reasons:
|
||
1) you wish to log out but want the inferior to remain, or
|
||
2) you want the job to become someone else's inferior.
|
||
|
||
Disowning is done with the DISOWN system call, as follows:
|
||
|
||
.CALL [ SETZ ? 'DISOWN
|
||
401000,,<job spec>]
|
||
.VALUE
|
||
|
||
It fails if the specified job isn't an inferior of the executing one.
|
||
If it succeeds, the specified job and its inferiors become
|
||
a separate disowned tree, of which the specified job is the top.
|
||
All channels on which the running job had that job open are closed.
|
||
See the DISOWN symbolic system call for more details and features.
|
||
|
||
4. REOWNING
|
||
|
||
A top-level disowned job may be "reowned" (made one's inferior)
|
||
by opening it with bit 1.4 of the mode set to 0. The uname of
|
||
every job in the reowned tree will be changed to equal that of
|
||
the reowning job, if necessary. If as a result the uname/jname
|
||
pair of one of the reowned jobs is no longer unique, the jname
|
||
will be altered until the uname/jname pair is unique.
|
||
|
||
Another way to reown a job is to use the REOWN symbolic system
|
||
call. The job to be reowned should already be open on an I/O
|
||
channel as a foreign user; the REOWN will cause it to be open
|
||
as an inferior instead on the same channel. An example is:
|
||
|
||
.CALL [ SETZ ? SIXBIT/REOWN/ ? 401000,,USRI]
|
||
.VALUE
|
||
|
||
In DDT, selecting a job that may be reowned will always reown it.
|
||
DDT will type ":$REOWNED$" when that happens. If the uname or
|
||
jname changes, DDT will type the new names.
|
||
|
||
5. DETACHING
|
||
|
||
An entire tree may be made disowned, have its console taken
|
||
away from it, or both, with the DETACH system call. The goal might
|
||
be to free the console for other use, or to make the tree into
|
||
a subtree of another tree by reowning it.
|
||
|
||
6. ATTACHING
|
||
|
||
Attaching is the operation of connecting a terminal to a tree
|
||
as the tree's console. The simplest kind of attachment takes
|
||
a free console and a disowned tree and connects them. A top-level
|
||
console-controlled job may also attach one of its inferiors to
|
||
its console; this has the same effect as if it were to disown
|
||
the inferior, detach itself, and then attach the erstwhile inferior
|
||
to the now free console, except that it happens more smoothly.
|
||
DDT's :ATTACH command uses the second flavor of ATTACH. See the
|
||
ATTACH system call for more details.
|
||
|
||
7. LOGGING IN
|
||
|
||
When the system creates a top-level job (such as a HACTRN), its uname
|
||
will be three "_"'s followed by three unique digits. The job may
|
||
change its uname to one that gives more information to humans by
|
||
"logging in", which simply sets the uname. The job must not have any
|
||
inferiors at the time; the new uname must not start with "___" and
|
||
must not be in use. A logged-in job may not log in again, but it may
|
||
change its uname with a .SUSET of .UNAME.
|
||
Logging in is done with the LOGIN symbolic system call, as follows:
|
||
|
||
.CALL [ SETZ ? SIXBIT/LOGIN/
|
||
SETZ [<new uname in sixbit>]]
|
||
.VALUE
|
||
|
||
The system call takes an optional third argument which now should be
|
||
used only by network server telnet jobs. For them, its hould be the
|
||
sixbit string "HSTnnn", where nnn is the octal number of the foreign
|
||
host.
|
||
|
||
8. LOGGING OUT AND GUNNING
|
||
|
||
A top-level job may delete itself, and all its inferiors, by "loggin
|
||
out". This is done with the .LOGOUT UUO, as follows:
|
||
|
||
.LOGOUT
|
||
|
||
The UUO returns only if it fails (the job isn't top level); it does not
|
||
skip. Programs that do not normally run in top-level jobs might
|
||
nevertheless be run in disowned jobs sometimes, so they should always
|
||
try to log out before requesting another command string or trying to ask
|
||
DDT to kill them.
|
||
|
||
A job may force any top-level job to log out by "gunning" it, using the
|
||
.GUN UUO. The user index of the job to be gunned must be known. The
|
||
way to do it is:
|
||
|
||
MOVEI AC,<usr idx>
|
||
.GUN AC,
|
||
JRST LOSE ;FAILED - JOB DIDN'T EXIST OR WASN'T TOP LEVEL.
|
||
... ;SUCCEEDED.
|
||
|
||
Gunning should go on only between consenting adults.
|
||
|
||
C. CONTROL OF INFERIORS.
|
||
|
||
Jobs can control their inferiors by means of several special-purpose
|
||
system calls. The more specific of them are documented below under
|
||
their uses. One more general one is .USET, which allows the inferior's
|
||
"user variables" to be read or set. For example, when section C.5.
|
||
speaks of "setting the job's .USTP variable", a .USET is meant. The
|
||
way to set the .FOO variable with a .USET is this:
|
||
.USET <channel>,[.SFOO,,[<new value>]]
|
||
Thus, .USET <channel>,[.SUSTP,,[0]] will stop the job open on channel
|
||
<channel>.
|
||
.USET <channel>,[.RFOO,,TEMP] will read the value of the .FOO
|
||
variable into TEMP.
|
||
For a complete description of the available .USET variables, and more
|
||
features of .USET, see the file ITS .USETS.
|
||
|
||
1. READING AND WRITING
|
||
|
||
Reading or writing the contents of another job requires having the job
|
||
open on a USR device channel. It is done by .IOT'ing on that channel;
|
||
thus, reading requires an input channel and output requires an output
|
||
channel. Selection of the region to read or write is done by setting
|
||
the channel's access pointer with .ACCESS. At the moment, SIOT on unit
|
||
mode USR channels is not very efficient, so it is best to open a job in
|
||
block mode. That requires one extra instruction when transferring a
|
||
single word, which is a slight cost when compared with the ease of
|
||
transferring several words.
|
||
Note that ascii mode does not exist for the USR device - all channels
|
||
should be opened in image mode.
|
||
|
||
For example, to read the word at 500 into A, do
|
||
|
||
.ACCESS USRI,[500]
|
||
HRROI B,A
|
||
.IOT USRI,B
|
||
|
||
assuming that USRI is the USR input channel. This clobbers B.
|
||
To write A into the word at 500, do
|
||
|
||
.ACCESS USRO,[500]
|
||
HRROI B,A
|
||
.IOT USRO,B
|
||
|
||
assuming that USRO is the USR output channel. This clobbers B.
|
||
|
||
If a non-existent location in another job is read or written
|
||
with an IOT, an MPV interrupt results. The .MPVA variable
|
||
of the job doing the reading will point at the non-existent
|
||
page of the other job. (Actually, in ITS before version 1017,
|
||
when a non-existent page is written, the system may give an MPV,
|
||
or may do a .CORE on the inferior so that it has enough core
|
||
to make the IOT succeed. ITS version 1017 and up will
|
||
always MPV).
|
||
|
||
2. SHARING MEMORY BETWEEN JOBS
|
||
|
||
Another way to refer to the core of other jobs is to share
|
||
memory with them. The slots of a job's page map should be
|
||
understood to be pointers to pages; one page may be pointed
|
||
to independently by several slots in several jobs' page maps.
|
||
The CORBLK call can be used to copy other jobs' pointers to pages
|
||
into one's own job, resulting in shared memory. Of course,
|
||
the memory will not have the same address in both slots
|
||
unless that is specificaly arranged for.
|
||
Unfortunately, other jobs' accumulators cannot be referred to
|
||
via memory sharing, since they are not stored anywhere in
|
||
the job's memory even when the job isn't running.
|
||
|
||
3. LOADING
|
||
|
||
Loading a binary file into a job is not actually a fundamental
|
||
operation, since it could be done by a program that understood
|
||
the format of the binary file and deposited in appropriate
|
||
locations in the job being loaded. However, for convenience'
|
||
sake, the LOAD system call exists for loading a binary file
|
||
into an inferior, or into the running job itself. Both types
|
||
of ITS binary files may be loaded with LOAD; it is not necessary
|
||
to know which type of file is being loaded. Unfortunately, this
|
||
call works only for disk files. For other devices, the program
|
||
must do it the hard way. Code may be copied from DDT for that
|
||
purpose.
|
||
|
||
The LOAD system call takes two arguments: the job to be loaded,
|
||
and the file to load. The first is expressed by a job spec; the
|
||
second, by a channel number. For example,
|
||
|
||
.CALL [ SETZ ? SIXBIT /LOAD/
|
||
1000,,-1 ;into myself
|
||
401000,,DISKC] ;the file open on DISKC
|
||
.VALUE
|
||
|
||
The LOAD will leave the disk channel set up to read the file's
|
||
start instruction, which is a jump to the starting address, or
|
||
zero if there is no starting address. After that word in the
|
||
file should come the symbol table and another copy of the start
|
||
instruction; see DDT ORDER for their format.
|
||
|
||
Loading a PDUMP file (pure file) inserts pages into the job
|
||
as specified by the file. It does not alter the pages of the
|
||
job that the file has no data for. It also does not alter the
|
||
accumulators, even if page 0 is loaded. Loading an SBLK file
|
||
(impure file) alters only the words of the job that the file
|
||
specifies data for. The other words are NOT cleared. If data
|
||
are specified in a nonexistent page, fresh memory will be
|
||
put there, and also in all nonexistent pages below it in the
|
||
address space! Thus, if an impure dump is made of a job containing
|
||
nonzero data only at address 100000, the resulting file when
|
||
loaded will create core up through address 101777, even though
|
||
only the last page of that is actually being loaded. This
|
||
unfortunately cannot be changed, but often causes trouble. For
|
||
that reason (and many others), it is hoped that there will be
|
||
a new, more versatile binary format some day.
|
||
|
||
a. Resetting
|
||
|
||
Loading per se modifies only the locations that the binary file
|
||
specifies data for. It does NOT clear the rest of core. If you
|
||
want to do that, chances are that you really want to RESET the
|
||
inferior. To do that, use the .RESET UUO or the RESET symbolic system
|
||
call on an I/O channel with the inferior open.
|
||
|
||
RESETting a job deletes all of its core, provides it with a single
|
||
page of unshared writeable core, closes all the job's channels,
|
||
kills all of its inferiors, and re-initializes most of the job's
|
||
system variables. Most notably not cleared out are the job's
|
||
translation lists for filenames.
|
||
|
||
4. DUMPING
|
||
a. Pure dumping
|
||
b. Impure dumping
|
||
5. STARTING AND STOPPING
|
||
|
||
An inferior may be started (caused to run) by setting its .USTP
|
||
variable to zero. It will continue with whatever PC it has.
|
||
To set the PC, store the desired new PC in the .UPC variable.
|
||
|
||
An inferior may be stopped by setting the .USTP variable to
|
||
nonzero. The exact value deposited in .USTP will be forgotten
|
||
since it corresponds only to a single bit of real storage.
|
||
This is how the system stops a job which gets a fatal interrupt.
|
||
|
||
DDT has another way of stopping a job, which it uses in executing
|
||
the ^X command: it turns on bit %PIC.Z of the job's .PIRQC, causing
|
||
a fatal ^Z-typed interrupt in that job.
|
||
This not only makes the system set the job's .USTP, but causes
|
||
DDT's interrupt handler to find out about the stoppage of the
|
||
job and be properly faked out.
|
||
|
||
6. HANDLING INTERRUPTS
|
||
|
||
Every job has the ability to enable interrupts on several conditions
|
||
(see ITS INTRUP). Among those conditions is the occurrence of a fatal
|
||
error interrupt in an inferior. This is the mechanism that enables
|
||
a job to "return to DDT" deliberately - it simply causes a fatal
|
||
interrupt in itself. This is also how DDT knows when an illegal
|
||
instruction is executed by an inferior.
|
||
|
||
Whenever a job acquires an inferior (by creation or reowning), one
|
||
of the job's interrupt bits is assigned to that inferior. Each
|
||
inferior has its own interrupt bit. There are exactly eight
|
||
interrupt bits which can be used for that purpose, which is why a
|
||
job can have at most eight inferiors at a time. Those eight are
|
||
all located in the left half of the .IFPIR variable.
|
||
|
||
The superior should find out which interrupt bit was assigned by reading
|
||
the inferior's .INTB variable, in which that bit alone will be 1.
|
||
|
||
See ITS INTRUP for more details.
|
||
|
||
The two system calls .VALUE and .BREAK exist solely so that a job can
|
||
cause a fatal interrupt to signal its superior. DDT has standard
|
||
interpretations for those instructions; see .INFO.;DDT ORDER.
|
||
|
||
7. DEBUGGING CONTROLS.
|
||
|
||
These features exist to facilitate debugging. They work currently on
|
||
KA-10's only, though they will be extended to KL-10's eventually.
|
||
They are generally used and controlled only by the superior of the
|
||
job on which they are acting, to which they are generally transparent.
|
||
|
||
a: One-proceed.
|
||
|
||
If appropriate bits in a job's PC are set, that job will be
|
||
able to execute one more instruction and then will get a fatal
|
||
%PI1PR interrupt. This feature is used by DDT's "single step"
|
||
command (^N). Which bits to use depends on the processor type:
|
||
for KA's, %PC1PR is the right bit (it is an 18 bit quantity, to
|
||
be OR'ed into the flags); for KL's, %PS1PR is right. On any
|
||
machine, the symbol OIPBIT will be defined in the ITS symbol
|
||
table as either %PC1PR,, or %PS1PR,, , whichever is appropriate.
|
||
|
||
b: Address-stop (MAR).
|
||
|
||
The MAR feature makes it possible to trap all references to a
|
||
particular address. When the specified location is referred to
|
||
("the MAR is hit"), the inferior will get a fatal %PIMAR
|
||
interrupt, which may or may not allow the instruction that
|
||
tripped the MAR to finish. The MAR is turned off when it is
|
||
hit and must be turned on again explicitly or it will stay
|
||
off forever.
|
||
|
||
The MAR is controlled by the .MARA user variable. Its RH
|
||
contains the address to be traced. Its LH contains the control
|
||
code, which is 0 to turn the MAR off, 1 to trap instruction
|
||
fetches only, 2 to trap writes only, and 3 to trap all
|
||
references. There is also a variable .MARPC which, after
|
||
the MAR is hit, contains the address of the instruction that
|
||
hit it. In addition, the indirect bit will be set on KA's
|
||
if the instruction that hit the MAR was completed (on KL's,
|
||
the instruction is always aborted).
|
||
On KL's, after a MAR, the job's PC (.UPC) will have %PSINH
|
||
set, which will inhibit MAR hitting for one instruction
|
||
when the job is continued.
|
||
The job's PC in .UPC should NOT be used to locate the
|
||
instruction that hit the MAR, since if the instruction was
|
||
not aborted and was a jump, the PC will be the address
|
||
jumped to. Even if it wasn't a jump, it might have skipped.
|
||
|
||
c: .JPC - Last Jump Address.
|
||
|
||
The user variable .JPC always contains the address of the last
|
||
jump instruction executed in the job. It can be used, for
|
||
example, to trace a job backward from the point of failure by
|
||
putting in a breakpoint, examining the .JPC when the breakpoint
|
||
is hit, and running the program again with the breakpoint now
|
||
located at the previous jump, etc. Unfortunately, subroutine
|
||
calls (including user-trapping UUOs) alter the JPC, even though
|
||
the information is redundant for them, but returnable UUO's and
|
||
interrupts do not. For that reason, after a returnable UUO
|
||
or interrupt a program should always read .JPC before jumping
|
||
anywhere, for debugging purposes. The canonical names UUOJPC
|
||
and INTJPC exist for the locations .JPC is saved in. Also,
|
||
error-handling uuos used by the program should be returnable
|
||
uuos rather than direct user-trapping uuos, so that the JPC
|
||
will be meaningful. The vectored interrupt mechanism has the
|
||
ability to store .JPC automatically on each interrupt (see
|
||
ITS INTRUP).
|
||
|
||
8. TTY PASSING
|
||
|
||
For now, see under .ATTY and .DTTY in ITS TTY.
|
||
|
||
D. SYSTEM JOBS AND WHAT THEY DO
|
||
|
||
There are two jobs built into the system, that run in exec mode
|
||
and perform housekeeping tasks; they are the system job and
|
||
the core job. There are also various "demon" jobs that exist
|
||
at times which, though receiving no special treatment from the
|
||
system, may be regarded as part of it in that they provide a
|
||
system-wide service.
|
||
|
||
1. THE SYSTEM JOB.
|
||
|
||
This job, whose full name is SYS SYS, provides a great many
|
||
independent services; it is really a timesharing system for
|
||
many trusting processes, each of which is controlled by a
|
||
single bit in the system variable SUPCOR. Setting the bit for
|
||
a process causes the process to run, and clear the bit. The
|
||
process should never run for very long, or it may tie up the
|
||
system by making the services of the other processes
|
||
unobtainable. If a process wishes to run continually, it does
|
||
so by setting its bit in SUPCOP. SUPCOP is or'ed into SUPCOR
|
||
every second, so a process whose bit in SUPCOP is set will be
|
||
run again that often. The process is always started the same
|
||
way, but it can of course have state variables.
|
||
|
||
The reasons why a given activity may involve the system job are
|
||
1) it may wish to print a message on the system log terminal, or
|
||
2) it may need to run in a job (eg, do system calls), but not be
|
||
associated with any one job, or
|
||
3) it may need to be able to hang up for short periods of time,
|
||
but the need to do it may be noticed at a time when that is
|
||
impossible, or
|
||
4) it needs to be done once every two minutes or every two hours.
|
||
The routines for those "very slow" and "super slow" clocks are in
|
||
the system job.
|
||
|
||
Re-initialising the connection to the IMP is an example of reasons 1
|
||
and 2. Typing "console free" messages is an example of reason 3 - it
|
||
involves doing I/O to the terminal, but it isn't done until the last
|
||
stage of killing a tree, when waiting of any sort would allow PCLSR'ing,
|
||
which would leave things in a screwed-up state. An example of reason 4
|
||
is the detection of core-link files which have not been used for more
|
||
than 2 minutes.
|
||
|
||
A complete list of the system job's functions follows:
|
||
|
||
a: Allocating or Deallocating Memory for Job Slots.
|
||
|
||
Most of the memory occupied by the system is marked as belonging to
|
||
the system job. For that reason, the way more is allocated for user
|
||
variable blocks is by having the system job do a .CORE UUO. This is
|
||
somewhat of a historical crock. Creating a job does not require such
|
||
allocation if there are free slots in the memory already allocated.
|
||
However, it may need to. For that reason, if the system job is hung
|
||
up, often jobs cannot be created.
|
||
|
||
b: Printing Various Messages on All Terminals.
|
||
|
||
Sometimes, messages such as "ITS GOING DOWN IN ..." or "ITS BEING
|
||
DEBUGGED" are printed on all the terminals in the world. It is the
|
||
system job that prints them on terminals which are free. Consoles have
|
||
them printed by DDT, however.
|
||
|
||
c: Checksumming the Constant Areas of the System.
|
||
|
||
The system job is always checksumming parts of the system and comparing
|
||
the checksums with those previously calculated. This mechanism causes
|
||
the clobberage of a word in the code of the system to be detected. If
|
||
only a single word in an area is clobbered, which word it is and the
|
||
original contents can be detarmined. In any case, a message is printed
|
||
on the system log terminal when clobberage is found.
|
||
|
||
d: Determining the Date and Time.
|
||
|
||
e: Detaching Trees.
|
||
|
||
When a top-level job is halted by a fatal interrupt, it is the system
|
||
job which executes the DETACH system call to detach it. Similarly, it
|
||
is the system job which detaches trees controlled by TV terminals when
|
||
the TV system crashes, and trees controlled by dialup lines whose
|
||
connections are broken (only when the hardware can detect that).
|
||
|
||
f: Depositing in the System.
|
||
|
||
When a job deposits in the system using .SETLOC or .IFSET, the system
|
||
job is informed so that it can update its checksums and avoid a system
|
||
clobbered" message. It also makes the change.
|
||
|
||
This used to be a great screw, in that if the system job were hung, it
|
||
could not be fixed by depositing in the system. Now, .SETLOC will do
|
||
the work itself without calling the system job, if the system job
|
||
appears to be hung.
|
||
|
||
g: Printing "Console-free" Messages.
|
||
|
||
When a terminal ceases to be in use, the system job is signalled to look
|
||
at all terminals and print console-free messages on all those which have
|
||
recently stopped being in use.
|
||
|
||
h: Logging Out.
|
||
|
||
The final stages of killing a job must be run by some other job. When a
|
||
top-level job is being killed, it does some of the work itself (kills
|
||
its inferiors and closes its channels). That is to make sure the
|
||
system job never hangs up trying to do it. The rest of the work is
|
||
then done by the system job, which can afford to wait for short peiods
|
||
of time when the job is almost killed.
|
||
|
||
i: Reinitialising the NCP.
|
||
|
||
When the connection to the ARPA network goes down, the system job gives
|
||
interrupts to all the jobs using the network, and also checks every so
|
||
often whether the network is useable again.
|
||
|
||
j: Printing of Various Messages on the System Log Terminal.
|
||
|
||
Events which cause messages on the log terminal include logging in,
|
||
logging out, writing on a directory whose name starts with "SYS",
|
||
garbage-collecting a disk directory, creating a disk directory,
|
||
gunning, parity errors, NXM errors.
|
||
|
||
l: Spooling the LPT.
|
||
|
||
On the AI KA-10 and the ML KA-10, the system job checks periodically for
|
||
spooled files and prints them.
|
||
|
||
m: Starting Other Demons.
|
||
|
||
On DM, the system job checks for any domon programs which have been
|
||
signaled. If there are any, it loads them into newly created jobs
|
||
and starts them.
|
||
|
||
n: Reinitialising the TV System, or Noticeing that it is Down.
|
||
|
||
2. THE CORE JOB.
|
||
|
||
This job, whose full name is CORE JOB, allocates core to jobs that
|
||
request it, and also frees up memory for use as user variable blocks,
|
||
which have to be allocated consecutively, by relocating the old
|
||
contents. Before there was pageing, the core job used to do shuffling.
|
||
|
||
3. DEMON JOBS.
|
||
|
||
a: The Comsat.
|
||
|
||
This demon, always named after some spacecraft or rocket, is responsible
|
||
for handling mail. Requests to send mail are placed in the .MAIL.
|
||
directory, and are eventually processed by the demon. The demon is
|
||
necessary because it may not be possible to send mail to other machines
|
||
right away, and in any case the user should not have to wait the time
|
||
it takes. It also provides other services such as forwarding.
|
||
|
||
b: NAMDRG.
|
||
|
||
This demon maintains the list of logged in users which appears on all
|
||
free TV consoles. It also updates a file saying when every user
|
||
logged out last. It exists on the AI KA-10 only.
|
||
|
||
c: PFTHMG DRAGON.
|
||
|
||
This demon updates the logout times file and keeps track of each user's
|
||
total CPU time. This demon originated on the ML KA-10, but has run on all
|
||
ITS machines at one time or another.
|
||
|
||
|