1
0
mirror of https://github.com/PDP-10/its.git synced 2026-03-26 02:05:51 +00:00

KCC - C compiler.

Binary-only compiler and library, plus documentation and include files
for compiling new programs.
This commit is contained in:
Lars Brinkhoff
2017-02-15 13:54:43 +01:00
parent c2242636b6
commit 53f2a2eba9
47 changed files with 15667 additions and 3 deletions

View File

@@ -7,9 +7,9 @@ NETMASK=255,255,255,248
SRC = system syseng sysen1 sysen2 sysen3 sysnet kshack dragon channa \
midas _teco_ emacs emacs1 rms klh syshst sra mrc ksc eak gren \
bawden _mail_ l lisp libdoc comlap lspsrc nilcom rwk \
inquir acount gz sys decsys ecc alan sail kcc
DOC = info _info_ sysdoc sysnet kshack _teco_ emacs emacs1
BIN = sys2 device emacs _teco_ lisp liblsp alan inquir sail comlap
inquir acount gz sys decsys ecc alan sail kcc kcc_sy c
DOC = info _info_ sysdoc sysnet kshack _teco_ emacs emacs1 c kcc
BIN = sys2 device emacs _teco_ lisp liblsp alan inquir sail comlap c
# These directories are put on the minsys tape.
MINSYS = _ sys

View File

@@ -163,6 +163,7 @@ A list of [known ITS machines](doc/machines.md).
- INSTAL, install executables on other ITS machines.
- ITSDEV, ITS device server.
- JOBS, list jobs by category.
- KCC, C compiler (binary only).
- LISP, lisp interpreter and runtime library (autoloads only).
- LOADP, displays system load.
- LOCK, shut down system.

BIN
bin/c/[clib].11 Executable file

Binary file not shown.

BIN
bin/c/[clib].14 Executable file

Binary file not shown.

BIN
bin/c/[clib].16 Executable file

Binary file not shown.

BIN
bin/c/[clib].9 Normal file

Binary file not shown.

BIN
bin/c/[crel].16 Executable file

Binary file not shown.

BIN
bin/c/ts.cc Executable file

Binary file not shown.

BIN
bin/c/}c.bin Executable file

Binary file not shown.

BIN
bin/c/}lp.bin Executable file

Binary file not shown.

BIN
bin/c/}m.bin Executable file

Binary file not shown.

53
doc/_info_/cc.recent Executable file
View File

@@ -0,0 +1,53 @@
18 April 1977
--- C ---
C is an implementation language, similar to BCPL except with data
types. Further information is be available from Alan Snyder (AS@DM).
C is currently available only on DM and MC.
--- Compiling ---
CC is the C compiler command. Usage is
:CC file1.name file2.name ...
where the arguments are the path names of C source files which are to
be compiled. Each file will be compiled in turn, and if the
compilation is successful, the resulting relocatable file will be
placed in the file file?.rel. Arguments beginning with the '-'
character are taken to be compiler options. Available options include:
-c compile only, do not assemble
-g do not delete MIDAS file
-x syntax check only
-s produce a symbol table listing
-b compile big function (FUNCTION TOO LARGE)
For example, the command
:cc foo.c
would compile the C program in the file FOO C in the current
directory, and place the resulting relocatable program in the file
FOO REL.
--- Loading ---
Relocatable programs produced by the C compiler are loaded together
with the C support routines by using the STINKR loader. In order
to load files FOO REL, BAR REL, and BLETCH REL and produce a
runnable file TS FOO, type the following to STINKR:
x c/clib
l foo
l bar
l bletch
o ts.foo
^@
The ^@ (ASCII NUL) terminates the teletype input file. These
commands (minus the ^@) could also be written in a file, say
FOO STINKR, in which case one could invoke STINKR with FOO
as a JCL argument and STINKR would read the commands from the
command file.

249
doc/c/c.info Executable file
View File

@@ -0,0 +1,249 @@
C Info (26 August 1980)
--- C ---
C is an implementation language, similar to BCPL except with
data types. It is the primary language used on Unix systems.
This implementation runs under the ITS and TOPS-20 operating
systems. This implementation is moderately compatible with
the Unix C implementation. However, the Unix system calls
are NOT implemented.
Some portions of the UNIX Standard I/O library are
implemented by C10STD. See C10STD.C (in <C.LIB> on XX,
and in ITS machines in the C; directory) for details.
Further information is available from Eliot Moss (EBM @ XX).
--- Compiling ---
CC is the C compiler command. Usage is
:cc file1.c file2.c ...
(more on pathnames below in I/O discussion)
where the arguments are the path names of C source files which
are to be compiled. Each file will be compiled in turn, and if
the compilation is successful, the resulting relocatable file
will be placed in the file "file*.stk". Arguments beginning
with the '-' character are taken to be compiler options.
Available options include:
-c compile only, do not assemble
-g do not delete MIDAS file
-x syntax check only
-s produce symbol table (not very useful)
-b compile big function (FUNCTION TOO LARGE)
For example, the command
:cc foo.c
would compile the C program in the file "foo.c" in the current
directory, and place the resulting relocatable program in the
file "foo.stk".
--- Loading ---
Relocatable programs produced by the C compiler are loaded
together with the C support routines using the STINKR loader.
To load program files "foo", "bar", and "bletch" and produce a
runnable file "foo", type the following to STINKR:
x c/clib
l foo
l bar
l bletch
o ts.foo
^@
The ^@ (ASCII NUL) terminates the terminal input file. These
commands (minus the ^@) could also be written in a file, say
"foo.stinkr", in which case one could invoke STINKR by saying
:stinkr foo
and STINKR would read the commands from the command file.
--- Library ---
The above STINKR commands will load in a set of library routines
for performing I/O, etc. Here is an introduction to that
library (the source files, which are in <C.LIB> on XX, are the
definitive documentation).
Here are some handly declarations for use below:
char c; /* an ASCII character */
int i, n, cc; /* an integer */
int *p; /* an integer pointer */
int b; /* a boolean */
char *s, *s1, *s2; /* strings */
char *fn; /* a file name or a path name (defined below) */
FILE *fd; /* a "file descriptor" (can be declared INT) */
/* I/O routines -- see also C10IO, C10MIO */
/* COPEN - opens an I/O channel */
fd = copen (fn, mode, options); /* open file */
char *fn; /* file name */
char mode; /* 'r', 'w', or 'a' (append) */
char *options; /* 0 (char I/O), "s" (string file), "b" (binary) */
/* for string file, pass string as fn */
/* returns -<ITS error code> if open fails */
/* Other routines: */
cprint (fd, s, a1, a2, ...); /* print s on fd */
/* s is printed on the output file fd. If fd is not supplied,
it defaults to cout, the standard output, i.e.,
cprint ("foo", ...) defaults fd to cout. s may contain
format descriptors, of the following forms:
%c - print a character
%d - print an integer in decimal
%o - print an integer in octal
%s - print a string
%z - print N copies of a character (N
supplied via field width - read on)
These use the other arguments, a1, a2, etc., in order.
For example,
cprint (fd, "%c plus %d equals %s.\n", '2', 1+1, "4")
results in
2 plus 2 equals 4.
The format letter may be preceded by a number, giving
the minimum field width. The output is normally right
justified in the field, but is left justified in a field
of size at least N if -N is given as the width. Spaces
are the normal padding character, used to fill out if
the argument does not fill the specified number of
columns. If a '0' character immediately follows the
'%', then '0' will be used as the padding character.
If the character following the '0' is not a digit, then
it will be used as the padding character instead of '0'.
Here are some examples of cprint (s, 312):
s = "%d" ==> 312
s = "%9d" ==> 312
s = "%09d" ==> 000000312
s = "%0*9d" ==> ******312
s = "%-0*9d" ==> 312******
s = "%o" ==> 470
For a more complete explanation, read CPRINT.C. It is
even possible to define your own formats, etc. */
c = cgetc (fd); /* get character (text input) */
c = cputc (c, fd); /* put character (text output) */
/* Note: these are redundant because cgetc and cputc do the
right thing for binary files */
i = cgeti (fd); /* get integer (binary input) */
i = cputi (i, fd); /* put integer (binary output) */
ungetc (c, fd); /* push unit back on input stream */
/* Several (but not very many) units may be pushed back
on any channel. */
b = ceof (fd); /* indicates whether the channel is at
end of file; always FALSE for output. */
cflush (fd); /* flush the buffer -- writes any not
yet written output */
cclose (fd); /* close channel, after doing a cflush
for any buffered output */
c = getchar (); /* cgetc (cin); */
s = gets (s); /* reads from cin until a newline,
storing into s. Returns the original
argument; does not store the newline. */
putchar (c); /* cputc (c, cout); */
puts (s); /* writes all of s to cout, and a
newline afterwards */
/* FILENAMES -- see also C10FNM */
/* The standard ITS format filenames are supported, with the
following terminology:
dev:dir;name type
dev - device
dir - directory
name - first file name
type - second file name
All these components are stored WITHOUT punctuation, as sixbit
words, once parsed. UNIX format ("pathnames") is also supported,
for ease in designing programs to run on more than one of TOPS20,
ITS, UNIX, and VAX/VMS. The interpretation is as follows:
/dev/dir1/name.type converts to
dev:dir;name type
If there is no leading /, there is no dev part. The available
routines are described below. */
fnparse (old, dev, dir, nm, typ, gen, attr)
char *old, *dev, *dir, *nm, *typ, *gen, *attr;
/* parses a name into its components; the gen and attr
components will always be null, but are there for
generality of interface to other operating systems. */
char *fngdv (old, buf) char *old, *buf;
char *fngdr (old, buf) char *old, *buf;
char *fngnm (old, buf) char *old, *buf;
char *fngtp (old, buf) char *old, *buf;
char *fnggn (old, buf) char *old, *buf;
char *fngat (old, buf) char *old, *buf;
/* extract the relevant component only */
fncons (buf, dev, dir, nm, typ, gen, attr)
char *buf, *dev, *dir, *nm, *typ, *gen, *attr;
/* construct a filename (ITS format) from its components */
char *fnsdf (buf, old, dv, dir, nm, typ, gen, attr)
char *old, *buf, *dv, *dir, *nm, *typ, *gen, *attr;
/* buf is set to contain a new filename with the
supplied components substituted for null components of
the filename in old */
char *fnsfd (buf, old, dv, dir, nm, typ, gen, attr)
char *old, *buf, *dv, *dir, *nm, *typ, *gen, *attr;
/* buf is set to contain a new filename with the
supplied components substituted for components of the
filename in old. This is different from fnsdf in that
non-zero component arguments (dv, dir, etc.) are
substituted even if old is not null in the corresponding
field. */
/* a FILESPEC is a structure containing the 4 components
as sixbit integers ... */
fparse (old, fs) char *old; filespec *fs;
/* parse a filename, handles both ITS and UNIX formats */
prfile (fs, buf) filespec *fs; char *buf;
/* converts the filespec to a string, inserting standard
punctuation */
/* STORAGE ALLOCATION */
p = salloc (n); /* allocate n words, return pointer to it */
sfree (p); /* free storage allocated by salloc */
s = calloc (n); /* allocate n characters, return ptr to it */
cfree (s); /* free storage allocated by calloc */
/* In this implementation words and chars are the same; but it
is bad style to depend on it, for some day packed strings might
be implemented ... */

229
doc/c/c.mail Executable file
View File

@@ -0,0 +1,229 @@
Received: from grape.ARPA by MC.LCS.MIT.EDU 6 Jun 86 02:07:00 EDT
Date: Thu, 5 Jun 86 23:06:03 pdt
From: jeff@aids-unix (Jeff Dean)
To: -s@ads.ARPA, jeff@ads.ARPA, c@mc
#ifdef HEADER
From dan@rna Sat Jan 26 10:38:50 1985
Received: from usenet by BRL-TGR.ARPA id a002453; 26 Jan 85 12:09 EST
From: Dan Ts'o <dan@rna.uucp>
Newsgroups: net.sources
Subject: Multiple column filter
Message-ID: <355@rna.UUCP>
Date: 26 Jan 85 01:59:08 GMT
Xref: seismo net.sources:2469
To: unix-sources@BRL-TGR.ARPA
Here is a filter "mc" which rearranges input lines to multicolumned
output. That is,
ls | mc
is like
ls -C (On Berkeley systems)
There are other ways of producing multicolumned output, of course.
Two string to mind:
1)
ls | pr -t -4 -l1
2)
ls | paste - - - -
However, neither of these filters duplicates the "ls -C" output,
where the columns proceed downward first, then on to the next column, which
is what "mc" does.
The original code came from the old Harvard UNIX V6 systems, but I
had to modify it a bit to move out of the V6 PDP-11 world.
To compile it,
cc -O mc.c -ltermlib
although, if you don't have libtermlib.a, commenting out three lines
would do fine. In addition,
mc -132
specifies a 132-column output. Normally, columns is taken from TERMCAP.
I find mc useful for all sorts of general purpose re-formatting, like
directory listing of other OS's and long columns of numbers.
Cheers,
Dan Ts'o
Dept. Neurobiology
Rockefeller Univ.
1230 York Ave.
NY, NY 10021
212-570-7671
...cmcl2!rna!dan
#endif
/*
* mc - Multiple column filter
* Transform lines of input into listing of multiple columns
* Original code from Harvard V6 Unix
* Updated and reworked by Dan Ts'o, Rockefeller Univ.
* Now has cat-like syntax:
* mc [-] [file ...]
*/
#include <stdio.h>
#define MEMINCR 1024L /* Memory buffer increments */
#define ZSTACK1 (-1) /* An impossible (char *) (Sorry) */
char *nodename;
int width;
char *malloc(), **stack1();
char *getenv();
main(c,v)
char **v;
{
register int i,f;
register char *cp;
FILE *fd;
char tbuf[1024];
/* Uncomment if your stdio doesn't buffer stdout
char buf[BUFSIZ];
setbuf(stdout, buf);
*/
f = 0;
nodename = *v;
cp = getenv("TERM");
if (cp == NULL || tgetent(tbuf, cp) <= 0
|| (width = tgetnum("co")-1) < 8)
width = 79;
while (c > 1 && v[1][0] == '-') {
c--;
v++;
switch (v[0][1]) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
width = atoi(&v[0][1]);
break;
default:
error("%s: Bad option\n", *v);
}
}
if (--c == 0)
exit(xfer(stdin));
else {
while (c--) {
v++;
if (**v == '-' && v[0][1] == 0) {
xfer(stdin);
clearerr(stdin);
}
else {
if ((fd = fopen(*v, "r")) == NULL) {
fprintf(stderr, "%s: %s: Can't open\n",
nodename, *v);
f++;
}
else {
xfer(fd);
fclose(fd);
}
}
}
}
exit(f ? -1 : 0);
}
xfer(fin)
FILE *fin;
{
register int i;
register char *cp;
char line[1024];
int max, items, columns;
int row_p, index, rows, col_p;
char **bot;
items = max = 0;
while(fgets(line, sizeof line, fin) != NULL) {
i = strlen(line);
if (line[--i] == '\n')
line[i] = 0;
else
i++;
if(i >= width) {
error("Line of length=%d is too long for width=%d\n",
i, width);
}
if((cp = (char *)malloc(i+1)) == NULL)
error("Out of memory\n");
strcpy(cp, line);
bot = stack1(cp);
if(i > max) max = i;
items++;
}
columns = width / (max+1);
rows = (items + columns - 1) / columns;
for(row_p = 0; row_p < rows; row_p++) {
for(col_p = 0; col_p < columns; col_p++) {
index = (col_p * rows) + row_p;
if(index >= items)
continue;
if((col_p + 1) * rows + row_p >= items)
printf("%s", bot[items - index - 1]);
else
printf("%-*s ", max, bot[items - index - 1]);
}
printf("\n");
}
fflush(stdout);
stack1(ZSTACK1);
return ferror(fin);
}
error(a, b, c, d, e)
{
fprintf(stderr, "%s: ", nodename);
fprintf(stderr, a, b, c, d, e);
exit (1);
}
char **stack1(s)
char *s;
{
static char **s_beg, **s_end;
static long nbuf = 0;
register char **v, **u;
register long n;
if (s == (char *) ZSTACK1) {
if (nbuf > 0)
free(s_beg);
nbuf = 0;
return 0;
}
if (nbuf == 0 || s_end <= s_beg) {
n = MEMINCR * (nbuf+1);
v = (char **)malloc(n*(sizeof (char *)));
if (v == NULL)
error("mc: Out of memory\n");
s_beg = v;
v += n;
if (nbuf > 0) {
u = s_end+(MEMINCR*nbuf);
while (u > s_end)
*--v = *--u;
free(s_end);
}
nbuf++;
s_end = v;
}
*--s_end = s;
return s_end;
}

Date: Wed, 4 Jun 86 07:59:50 EDT
From: "R. P. Miller" <ARPEE%MX.LCS.MIT.EDU@MC.LCS.MIT.EDU>
To: C%MX.LCS.MIT.EDU@MC.LCS.MIT.EDU
Message-ID: <[MX.LCS.MIT.EDU].924252.860604.ARPEE>
mail


2292
doc/c/c.refman Executable file

File diff suppressed because it is too large Load Diff

48
doc/c/cctty.info Executable file
View File

@@ -0,0 +1,48 @@
The following library routines are available ON ITS ONLY:
Buffered I/O:
Input: there is a default prompt string (settable), which is
printed when ^L in typed; if the default prompt string is not set,
then any partial (buffered) output line is used; delete deletes a
character as usual; CR completes the reading of a buffered line.
Output: nothing happens until the buffer is full, a CR is
sent, or a tyo_flush is done.
char tyi (); reads one buffered character; CR is changed to LF
tyo (c) char c; outputs a buffered char; ^P changed to ^
followed by P; full buffer or CR causes buffer to be
sent
tyo_flush (); forces buffer to be sent
tyos (s) char *s; calls tyo repeatedly, changing CR to LF
setprompt (s) char *s; sets the default prompt string
Unbuffered I/O:
char utyi (); flushes the output buffer and reads a char;
no mapping or echoing performed
utyo (c) char c; flushes the output buffer and send the
char; no mapping done EXCEPT ^P changed to ^ followed
by P
spctty (c) char c; flushes the output buffer then sends
^P followed by the argument; for ITS display codes.
Interrupts:
^G and ^S are set to interrupt; they result in signals
of ctrlg_interrupt and ctrls_interrupt, respectively. To
associate a routine with them (one which does nothing is a good
way to ignore the interrupts) you do:
on (ctrlg_interrupt, f) (likewise for ^S)
where f is a function taking no arguments and returning no
results. The interrupt character will have been read at
interrupt level. If you want to handle TTY interrupts yourself,
you can do
on (ttyi_interrupt, fn) and fn will be called on a
tty input interrupt; ityic (tty_input_channel) will return
an interrupt char (-1 means it went away); tty_input_channel
is an int defined in one of the library routines. To set
which chars will interrupt, you can use:
ttyget (tty_input_channel, block)
and ttyset (tty_input_channel, block)
where block is an array of 4 ints; these 4 words are the
results and the arguments of the corresponding ITS .call's,
in the same order. Initially all chars activate, and ^G and ^S
interrupt.

1607
doc/c/cdoc.91 Executable file

File diff suppressed because it is too large Load Diff

3
doc/kcc/-read-.-this- Executable file
View File

@@ -0,0 +1,3 @@
This directory contains files for the KCC PDP-10 C compiler. Currently
there is just this one directory, but as the port progresses I'm sure there
will be others. -- Alan

96
doc/kcc/agree.txt Normal file
View File

@@ -0,0 +1,96 @@
KCC DISTRIBUTION POLICY
This file describes the general KCC distribution policy --
licensing, restrictions, and that sort of thing. If you're not sure
how it applies to your particular situation, just get in touch.
First, note that the files are copyrighted. However, we
consider them "quasi-public" and distribute them freely; the problem
is that sometimes true public-domain stuff is acquired by private
parties and modified slightly to produce a licensed, costly product.
We wish to prevent this by keeping the sources available to everyone
who wants to use KCC, but unavailable to those who have ideas of
selling it; hence the copyright. This applies to all modifications as
well.
Second, since the software is provided free of charge, there
is absolutely NO WARRANTY on anything in this distribution, nor any
obligation to provide maintenance, and all of the usual software
disclaimers apply to everything. If we were to be held responsible
for any problems, we could not distribute KCC at all.
The situation with respect to including KCC as a component of
commercial software packages is fuzzy. Our current inclination is to
allow this as a convenience to the ultimate end users, provided they
are given ALL of the distribution, including sources and this notice.
However, certain cirumstances may force re-assessment of this
position; e.g. extensive modifications, huge numbers of users,
time-consuming maintenance requirements... people with such
applications in mind should contact us.
People may be tempted to modify and "improve" the software.
This is natural and to some extent desirable, but can quickly lead to
chaos without some rules governing these additions and modifications.
So we simply state that the use of KCC automatically implies agreement
with the following policies:
General:
1. KCC is maintained as a primary software tool for SRI-NIC,
and ensuring that it remains reliable and useful for this purpose must
necessarily have our highest priority.
2. Next most important is conformance to the C language
defined by Harbison and Steele, plus the forthcoming ANSI C standard
(currently a X3J11 committee draft). This includes library functions.
3. Software portability, particularly to 4.3BSD-type UN*X,
is slightly more important than TOPS-20 efficiency.
4. Licensed UN*X software sources will never be used or
distributed, and such contributions cannot be accepted.
People making changes to KCC or the library should:
1. Retain the copyright notice for each module, and add a
history notice comment describing the change.
2. Relay your improvements to the maintainers of the canonical
version, so that they can be incorporated into new releases!
Otherwise both you and the rest of the world will lose.
3. Realize that your changes may not be adopted exactly as
provided, if they conflict with one of the general policies. New
library functions are particularly prone to this problem. As a
solution we will probably collect such things into a separate library
or two (e.g. for TOPS-20 specific functions).
Finally:
If at all possible, ask people who want copies of KCC to
get it from the canonical source. If you must give
them a copy, keep all of the original distribution
intact in some form so that the baseline is constant.
KCC is still under active development, and new releases (with
all accumulated bug fixes, improvements, or new features) can be
expected frequently. At all times there will exist only one canonical
version of the software, from which all distributions are made. If
you can make an Internet FTP connection to SRI-NIC.ARPA, you can
retrieve it whenever you wish.
Canonical version: KCCDIST: directory on SRI-NIC.ARPA
Maintainer mailbox: <BUG-KCC@SRI-NIC.ARPA>
Information list: <INFO-KCC@SRI-NIC.ARPA>
(to get on:) <INFO-KCC-REQUEST@SRI-NIC.ARPA>
BUG-KCC is for bug and problem reports and is sometimes used for
discussion of esoteric internal issues. INFO-KCC members basically
receive announcements of new releases and developments, and every site
which has installed KCC should have at least one representative on
that list. If enough users express interest, a user discussion group
could also be started (probably this would deal with C on TOPS-20 in
general rather than just KCC).
Good luck! Feel free to contact me about any problems or questions
you have.
Ken Harrenstien Internet: <KLH@SRI-NIC.ARPA> Phone: (415) 859-6552
Room EJ200
SRI International
333 Ravenswood Ave.
Menlo Park, CA 94025

963
doc/kcc/calls.intro Executable file
View File

@@ -0,0 +1,963 @@
From Sun Release 3.2 Last change: 16 July 1986
Liberated 4/15/88 by ALAN
INTRO(2) SYSTEM CALLS INTRO(2)
NAME
intro - introduction to system calls and error numbers
SYNOPSIS
#include <errno.h>
DESCRIPTION
This section describes all of the system calls. A "(2V)"
heading indicates that the system call performs differently
when called from programs that use the System V libraries
(programs compiled using /usr/5bin/cc). On these pages,
both the regular behavior and the System V behavior is
described.
Most of these calls have one or more error returns. An
error condition is indicated by an otherwise impossible
return value. This is almost always -1; the individual
descriptions specify the details. Note that a number of
system calls overload the meanings of these error numbers,
and that the meanings must be interpreted according to the
type and circumstances of the call.
As with normal arguments, all return codes and values from
functions are of type integer unless otherwise noted. An
error number is also made available in the external variable
errno, which is not cleared on successful calls. Thus errno
should be tested only after an error has occurred.
Each system call description attempts to list all possible
error numbers. The following is a complete list of the
errors and their names as given in <errno.h>.
0 Error 0
Unused.
1 EPERM Not owner
Typically this error indicates an attempt to modify a
file in some way forbidden except to its owner or
super-user. It is also returned for attempts by ordi-
nary users to do things allowed only to the super-user.
2 ENOENT No such file or directory
This error occurs when a filename is specified and the
file should exist but doesn't, or when one of the
directories in a pathname does not exist.
3 ESRCH No such process
The process or process group whose number was given
does not exist, or any such process is already dead.
4 EINTR Interrupted system call
An asynchronous signal (such as interrupt or quit),
which the user has elected to catch, occurred during a
system call. If execution is resumed after processing
the signal, and the system call is not restarted, it
will appear as if the interrupted system call returned
this error condition.
5 EIO I/O error
Some physical I/O error occurred. This error may in
some cases occur on a call following the one to which
it actually applies.
6 ENXIO No such device or address
I/O on a special file refers to a subdevice which does
not exist, or beyond the limits of the device. It may
also occur when, for example, a tape drive is not on-
line or a disk pack is not loaded on a drive.
7 E2BIG Arg list too long
An argument list longer than 10240 bytes is presented
to execve.
8 ENOEXEC Exec format error
A request is made to execute a file which, although it
has the appropriate permissions, does not start with a
valid magic number (see a.out(5)).
9 EBADF Bad file number
Either a file descriptor refers to no open file, or a
read (respectively, write) request is made to a file
which is open only for writing (respectively, reading).
10 ECHILD No children
A wait was executed by a process that had no existing
or unwaited-for child processes.
11 EAGAIN No more processes
A fork failed because the system's process table is
full or the user is not allowed to create any more
processes.
12 ENOMEM Not enough memory
During an execve, brk, or sbrk, a program asks for more
address space or swap space than the system is able to
supply, or a process size limit would be exceeded. A
lack of swap space is normally a temporary condition;
however, a lack of address space is not a temporary
condition. The maximum size of the text, data, and
stack segments is a system parameter. Soft limits may
be increased to their corresponding hard limits.
13 EACCES Permission denied
An attempt was made to access a file in a way forbidden
by the protection system.
14 EFAULT Bad address
The system encountered a hardware fault in attempting
to access the arguments of a system call.
15 ENOTBLK Block device required
A file which is not a block device was mentioned where
a block device was required, for example, in mount.
16 EBUSY Device busy
An attempt to mount a file system that was already
mounted or an attempt was made to dismount a file sys-
tem on which there is an active file (open file,
current directory, mounted-on file, or active text seg-
ment).
17 EEXIST File exists
An existing file was mentioned in an inappropriate con-
text, for example, link.
18 EXDEV Cross-device link
A hard link to a file on another file system was
attempted.
19 ENODEV No such device
An attempt was made to apply an inappropriate system
call to a device (for example, an attempt to read a
write-only device) or an attempt was made to use a dev-
ice not configured by the system.
20 ENOTDIR Not a directory
A non-directory was specified where a directory is
required, for example, in a pathname or as an argument
to chdir.
21 EISDIR Is a directory
An attempt was made to write on a directory.
22 EINVAL Invalid argument
A system call was made with an invalid argument; for
example, dismounting a non-mounted file system, men-
tioning an unknown signal in sigvec or kill, reading or
writing a file for which lseek has generated a negative
pointer, or some other argument inappropriate for the
call. Also set by math functions, see intro(3).
23 ENFILE File table overflow
The system's table of open files is full, and tem-
porarily no more opens can be accepted.
24 EMFILE Too many open files
A process tried to have more open files than the system
allows a process to have. The customary configuration
limit is 30 per process.
25 ENOTTY Inappropriate ioctl for device
The code used in an ioctl call is not supported by the
object that the file descriptor in the call refers to.
26 ETXTBSY Text file busy
An attempt to execute a pure-procedure program which is
currently open for writing. Also an attempt to open
for writing a pure-procedure program that is being exe-
cuted.
27 EFBIG File too large
The size of a file exceeded the maximum file size
(1,082,201,088 bytes).
28 ENOSPC No space left on device
A write to an ordinary file, the creation of a direc-
tory or symbolic link, or the creation of a directory
entry failed because no more disk blocks are available
on the file system, or the allocation of an inode for a
newly created file failed because no more inodes are
available on the file system.
29 ESPIPE Illegal seek
An lseek was issued to a socket or pipe. This error
may also be issued for other non-seekable devices.
30 EROFS Read-only file system
An attempt to modify a file or directory was made on a
file system mounted read-only.
31 EMLINK Too many links
An attempt to make more than 32767 hard links to a
file.
32 EPIPE Broken pipe
An attempt was made to write on a pipe or socket for
which there is no process to read the data. This con-
dition normally generates a signal; the error is
returned if the signal is caught or ignored.
33 EDOM Math argument
The argument of a function in the math library (as
described in section 3M) is out of the domain of the
function.
34 ERANGE Result too large
The value of a function in the math library (as
described in section 3M) is unrepresentable within
machine precision.
35 EWOULDBLOCK Operation would block
An operation which would cause a process to block was
attempted on an object in non-blocking mode (see
ioctl(2)).
36 EINPROGRESS Operation now in progress
An operation which takes a long time to complete (such
as a connect(2)) was attempted on a non-blocking object
(see ioctl(2)).
37 EALREADY Operation already in progress
An operation was attempted on a non-blocking object
which already had an operation in progress.
38 ENOTSOCK Socket operation on non-socket
Self-explanatory.
39 EDESTADDRREQ Destination address required
A required address was omitted from an operation on a
socket.
40 EMSGSIZE Message too long
A message sent on a socket was larger than the internal
message buffer.
41 EPROTOTYPE Protocol wrong type for socket
A protocol was specified which does not support the
semantics of the socket type requested. For example,
you cannot use the ARPA Internet UDP protocol with type
SOCK_STREAM.
42 ENOPROTOOPT Option not supported by protocol
A bad option was specified in a getsockopt(2) or set-
sockopt(2) call.
43 EPROTONOSUPPORT Protocol not supported
The protocol has not been configured into the system or
no implementation for it exists.
44 ESOCKTNOSUPPORT Socket type not supported
The support for the socket type has not been configured
into the system or no implementation for it exists.
45 EOPNOTSUPP Operation not supported on socket
For example, trying to accept a connection on a
datagram socket.
46 EPFNOSUPPORT Protocol family not supported
The protocol family has not been configured into the
system or no implementation for it exists.
47 EAFNOSUPPORT Address family not supported by protocol
family
An address incompatible with the requested protocol was
used. For example, you shouldn't necessarily expect to
be able to use PUP Internet addresses with ARPA Inter-
net protocols.
48 EADDRINUSE Address already in use
Only one usage of each address is normally permitted.
49 EADDRNOTAVAIL Can't assign requested address
Normally results from an attempt to create a socket
with an address not on this machine.
50 ENETDOWN Network is down
A socket operation encountered a dead network.
51 ENETUNREACH Network is unreachable
A socket operation was attempted to an unreachable net-
work.
52 ENETRESET Network dropped connection on reset
The host you were connected to crashed and rebooted.
53 ECONNABORTED Software caused connection abort
A connection abort was caused internal to your host
machine.
54 ECONNRESET Connection reset by peer
A connection was forcibly closed by a peer. This nor-
mally results from the peer executing a shutdown(2)
call.
55 ENOBUFS No buffer space available
An operation on a socket or pipe was not performed
because the system lacked sufficient buffer space.
56 EISCONN Socket is already connected
A connect request was made on an already connected
socket; or, a sendto or sendmsg request on a connected
socket specified a destination other than the connected
party.
57 ENOTCONN Socket is not connected
An request to send or receive data was disallowed
because the socket is not connected.
58 ESHUTDOWN Can't send after socket shutdown
A request to send data was disallowed because the
socket had already been shut down with a previous
shutdown(2) call.
59 unused
60 ETIMEDOUT Connection timed out
A connect request failed because the connected party
did not properly respond after a period of time. (The
timeout period is dependent on the communication proto-
col.)
61 ECONNREFUSED Connection refused
No connection could be made because the target machine
actively refused it. This usually results from trying
to connect to a service which is inactive on the
foreign host.
62 ELOOP Too many levels of symbolic links
A pathname lookup involved more than 8 symbolic links.
63 ENAMETOOLONG File name too long
A component of a pathname exceeded 255 characters, or
an entire pathname exceeded 1023 characters.
64 EHOSTDOWN Host is down
A socket operation failed because the destination host
was down.
65 EHOSTUNREACH Host is unreachable
A socket operation was attempted to an unreachable
host.
66 ENOTEMPTY Directory not empty
An attempt was made to remove a directory with entries
other than . and .. by performing a rmdir system call
or a rename system call with that directory specified
as the target directory.
67 unused
68 unused
69 EDQUOT Disc quota exceeded
A write to an ordinary file, the creation of a direc-
tory or symbolic link, or the creation of a directory
entry failed because the user's quota of disk blocks
was exhausted, or the allocation of an inode for a
newly created file failed because the user's quota of
inodes was exhausted.
70 ESTALE Stale NFS file handle
A client referenced a an open file, when the file has
been deleted.
71 EREMOTE Too many levels of remote in path
An attempt was made to remotely mount a file system
into a path which already has a remotely mounted com-
ponent.
72 unused
73 unused
74 unused
75 ENOMSG No message of desired type
An attempt was made to receive a message of a type that
does not exist on the specified message queue; see
msgop(2).
76 unused
77 EIDRM Identifier removed
This error is returned to processes that resume execu-
tion due to the removal of an identifier from the IPC
system's name space (see msgctl(2), semctl(2), and
shmctl(2)).
DEFINITIONS
Descriptor
An integer assigned by the system when a file is referenced
by open(2V), dup(2), or pipe(2) or a socket is referenced by
socket(2) or socketpair(2) which uniquely identifies an
access path to that file or socket from a given process or
any of its children.
Directory
A directory is a special type of file which contains entries
which are references to other files. Directory entries are
called links. By convention, a directory contains at least
two links, . and .., referred to as dot and dot-dot respec-
tively. Dot refers to the directory itself and dot-dot
refers to its parent directory.
Effective User ID, Effective Group ID, and Access Groups
Access to system resources is governed by three values: the
effective user ID, the effective group ID, and the group
access list.
The effective user ID and effective group ID are initially
the process's real user ID and real group ID respectively.
Either may be modified through execution of a set-user-ID or
set-group-ID file (possibly by one of its ancestors) (see
execve(2)).
The group access list is an additional set of group ID's
used only in determining resource accessibility. Access
checks are performed as described below in ``File Access
Permissions''.
File Access Permissions
Every file in the file system has a set of access permis-
sions. These permissions are used in determining whether a
process may perform a requested operation on the file (such
as opening a file for writing). Access permissions are
established at the time a file is created. They may be
changed at some later time through the chmod(2) call.
File access is broken down according to whether a file may
be: read, written, or executed. Directory files use the
execute permission to control if the directory may be
searched.
File access permissions are interpreted by the system as
they apply to three different classes of users: the owner of
the file, those users in the file's group, anyone else.
Every file has an independent set of access permissions for
each of these classes. When an access check is made, the
system decides if permission should be granted by checking
the access information applicable to the caller.
Read, write, and execute/search permissions on a file are
granted to a process if:
The process's effective user ID is that of the super-
user.
The process's effective user ID matches the user ID of
the owner of the file and the owner permissions allow
the access.
The process's effective user ID does not match the user
ID of the owner of the file, and either the process's
effective group ID matches the group ID of the file, or
the group ID of the file is in the process's group
access list, and the group permissions allow the
access.
Neither the effective user ID nor effective group ID
and group access list of the process match the
corresponding user ID and group ID of the file, but the
permissions for ``other users'' allow access.
Otherwise, permission is denied.
File Name
Names consisting of up to 255 characters may be used to name
an ordinary file, special file, or directory.
These characters may be selected from the set of all ASCII
character excluding \0 (null) and the ASCII code for /
(slash). (The parity bit, bit 8, must be 0.)
Note that it is generally unwise to use *, ?, [, or ] as
part of filenames because of the special meaning attached to
these characters by the shell. See sh(1). Although permit-
ted, it is advisable to avoid the use of unprintable charac-
ters in filenames.
Message Queue Identifier
A message queue identifier (msqid) is a unique positive
integer created by a msgget(2) system call. Each msqid has
a message queue and a data structure associated with it.
The data structure is referred to as msqid_ds and contains
the following members:
struct ipc_perm msg_perm; /* operation permission struct */
ushort msg_qnum; /* number of msgs on q */
ushort msg_qbytes; /* max number of bytes on q */
ushort msg_lspid; /* pid of last msgsnd operation */
ushort msg_lrpid; /* pid of last msgrcv operation */
time_t msg_stime; /* last msgsnd time */
time_t msg_rtime; /* last msgrcv time */
time_t msg_ctime; /* last change time */
/* Times measured in secs since */
/* 00:00:00 GMT, Jan. 1, 1970 */
msg_perm is an ipc_perm structure that specifies the message
operation permission (see below). This structure includes
the following members:
ushort cuid; /* creator user id */
ushort cgid; /* creator group id */
ushort uid; /* user id */
ushort gid; /* group id */
ushort mode; /* r/w permission */
msg_qnum is the number of messages currently on the queue.
msg_qbytes is the maximum number of bytes allowed on the
queue. msg_lspid is the process id of the last process that
performed a msgsnd operation. msg_lrpid is the process id
of the last process that performed a msgrcv operation.
msg_stime is the time of the last msgsnd operation,
msg_rtime is the time of the last msgrcv operation, and
msg_ctime is the time of the last msgctl(2) operation that
changed a member of the above structure.
Message Operation Permissions
In the msgop(2) and msgctl(2) system call descriptions, the
permission required for an operation is given as "{token}",
where "token" is the type of permission needed interpreted
as follows:
00400 Read by user
00200 Write by user
00060 Read, Write by group
00006 Read, Write by others
Read and Write permissions on a msqid are granted to a pro-
cess if one or more of the following are true:
The effective user ID of the process is super-user.
The effective user ID of the process matches
msg_perm.[c]uid in the data structure associated with
msqid and the appropriate bit of the ``user'' portion
(0600) of msg_perm.mode is set.
The effective user ID of the process does not match
msg_perm.[c]uid and the effective group ID of the pro-
cess matches msg_perm.[c]gid and the appropriate bit of
the ``group'' portion (060) of msg_perm.mode is set.
The effective user ID of the process does not match
msg_perm.[c]uid and the effective group ID of the pro-
cess does not match msg_perm.[c]gid and the appropriate
bit of the ``other'' portion (06) of msg_perm.mode is
set.
Otherwise, the corresponding permissions are denied.
Parent Process ID
A new process is created by a currently active process (see
fork(2)). The parent process ID of a process is the process
ID of its creator.
Path Name and Path Prefix
A pathname is a null-terminated character string starting
with an optional slash (/), followed by zero or more direc-
tory names separated by slashes, optionally followed by a
filename. The total length of a pathname must be less than
{MAXPATHLEN} (1024) characters.
More precisely, a pathname is a null-terminated character
string constructed as follows:
<path-name>::=<file-name>|<path-prefix><file-name>|/
<path-prefix>::=<rtprefix>|/<rtprefix>
<rtprefix>::=<dirname>/|<rtprefix><dirname>/
where <file-name> is a string of 1 to 255 characters other
than the ASCII slash and null, and <dirname> is a string of
1 to 255 characters (other than the ASCII slash and null)
that names a directory.
If a pathname begins with a slash, the search begins at the
root directory. Otherwise, the search begins at the current
working directory.
A slash, by itself, names the root directory. A dot (.)
names the current working directory.
A null pathname also refers to the current directory. How-
ever, this is not true of all UNIX systems. (On such sys-
tems, accidental use of a null pathname in routines that
don't check for it may corrupt the current working direc-
tory.) For portable code, specify the current directory
explicitly using ".", rather than "".
Process Group ID
Each active process is a member of a process group that is
identified by a positive integer called the process group
ID. This is the process ID of the group leader. This
grouping permits the signaling of related processes (see
killpg(2)) and the job control mechanisms of csh(1).
Process ID
Each active process in the system is uniquely identified by
a positive integer called a process ID. The range of this
ID is from 0 to 30000.
Real User ID and Real Group ID
Each user on the system is identified by a positive integer
termed the real user ID.
Each user is also a member of one or more groups. One of
these groups is distinguished from others and used in imple-
menting accounting facilities. The positive integer
corresponding to this distinguished group is termed the real
group ID.
All processes have a real user ID and real group ID. These
are initialized from the equivalent attributes of the pro-
cess which created it.
Root Directory and Current Working Directory
Each process has associated with it a concept of a root
directory and a current working directory for the purpose of
resolving path name searches. A process's root directory
need not be the root directory of the root file system.
Semaphore Identifier
A semaphore identifier (semid) is a unique positive integer
created by a semget(2) system call. Each semid has a set of
semaphores and a data structure associated with it. The
data structure is referred to as semid_ds and contains the
following members:
struct ipc_perm sem_perm; /* operation permission struct */
ushort sem_nsems; /* number of sems in set */
time_t sem_otime; /* last operation time */
time_t sem_ctime; /* last change time */
/* Times measured in secs since */
/* 00:00:00 GMT, Jan. 1, 1970 */
sem_perm is an ipc_perm structure that specifies the sema-
phore operation permission (see below). This structure
includes the following members:
ushort cuid; /* creator user id */
ushort cgid; /* creator group id */
ushort uid; /* user id */
ushort gid; /* group id */
ushort mode; /* r/a permission */
The value of sem_nsems is equal to the number of semaphores
in the set. Each semaphore in the set is referenced by a
positive integer referred to as a sem_num. sem_num values
run sequentially from 0 to the value of sem_nsems minus 1.
sem_otime is the time of the last semop(2) operation, and
sem_ctime is the time of the last semctl(2) operation that
changed a member of the above structure.
A semaphore is a data structure that contains the following
members:
ushort semval; /* semaphore value */
short sempid; /* pid of last operation */
ushort semncnt; /* # awaiting semval > cval */
ushort semzcnt; /* # awaiting semval = 0 */
semval is a non-negative integer. sempid is equal to the
process ID of the last process that performed a semaphore
operation on this semaphore. semncnt is a count of the
number of processes that are currently suspended awaiting
this semaphore's semval to become greater than its current
value. semzcnt is a count of the number of processes that
are currently suspended awaiting this semaphore's semval to
become zero.
Semaphore Operation Permissions
In the semop(2) and semctl(2) system call descriptions, the
permission required for an operation is given as "{token}",
where "token" is the type of permission needed interpreted
as follows:
00400 Read by user
00200 Alter by user
00060 Read, Alter by group
00006 Read, Alter by others
Read and Alter permissions on a semid are granted to a pro-
cess if one or more of the following are true:
The effective user ID of the process is super-user.
The effective user ID of the process matches
sem_perm.[c]uid in the data structure associated with
semid and the appropriate bit of the ``user'' portion
(0600) of sem_perm.mode is set.
The effective user ID of the process does not match
sem_perm.[c]uid and the effective group ID of the pro-
cess matches sem_perm.[c]gid and the appropriate bit of
the ``group'' portion (060) of sem_perm.mode is set.
The effective user ID of the process does not match
sem_perm.[c]uid and the effective group ID of the pro-
cess does not match sem_perm.[c]gid and the appropriate
bit of the ``other'' portion (06) of sem_perm.mode is
set.
Otherwise, the corresponding permissions are denied.
Shared Memory Identifier
A shared memory identifier (shmid) is a unique positive
integer created by a shmget(2) system call. Each shmid has
a segment of memory (referred to as a shared memory segment)
and a data structure associated with it. The data structure
is referred to as shmid_ds and contains the following
members:
struct ipc_perm shm_perm; /* operation permission struct */
int shm_segsz; /* size of segment */
ushort shm_cpid; /* creator pid */
ushort shm_lpid; /* pid of last operation */
short shm_nattch; /* number of current attaches */
time_t shm_atime; /* last attach time */
time_t shm_dtime; /* last detach time */
time_t shm_ctime; /* last change time */
/* Times measured in secs since */
/* 00:00:00 GMT, Jan. 1, 1970 */
shm_perm is an ipc_perm structure that specifies the shared
memory operation permission (see below). This structure
includes the following members:
ushort cuid; /* creator user id */
ushort cgid; /* creator group id */
ushort uid; /* user id */
ushort gid; /* group id */
ushort mode; /* r/w permission */
shm_segsz specifies the size of the shared memory segment.
shm_cpid is the process id of the process that created the
shared memory identifier. shm_lpid is the process id of the
last process that performed a shmop(2) operation.
shm_nattch is the number of processes that currently have
this segment attached. shm_atime is the time of the last
shmat operation, shm_dtime is the time of the last shmdt
operation, and shm_ctime is the time of the last shmctl(2)
operation that changed one of the members of the above
structure.
Shared Memory Operation Permissions
In the shmop(2) and shmctl(2) system call descriptions, the
permission required for an operation is given as "{token}",
where "token" is the type of permission needed interpreted
as follows:
00400 Read by user
00200 Write by user
00060 Read, Write by group
00006 Read, Write by others
Read and Write permissions on a shmid are granted to a pro-
cess if one or more of the following are true:
The effective user ID of the process is super-user.
The effective user ID of the process matches
shm_perm.[c]uid in the data structure associated with
shmid and the appropriate bit of the ``user'' portion
(0600) of shm_perm.mode is set.
The effective user ID of the process does not match
shm_perm.[c]uid and the effective group ID of the pro-
cess matches shm_perm.[c]gid and the appropriate bit of
the ``group'' portion (060) of shm_perm.mode is set.
The effective user ID of the process does not match
shm_perm.[c]uid and the effective group ID of the pro-
cess does not match shm_perm.[c]gid and the appropriate
bit of the ``other'' portion (06) of shm_perm.mode is
set.
Otherwise, the corresponding permissions are denied.
Sockets and Address Families
A socket is an endpoint for communication between processes.
Each socket has queues for sending and receiving data.
Sockets are typed according to their communications proper-
ties. These properties include whether messages sent and
received at a socket require the name of the partner,
whether communication is reliable, the format used in naming
message recipients, etc.
Each instance of the system supports some collection of
socket types; consult socket(2) for more information about
the types available and their properties.
Each instance of the system supports some number of sets of
communications protocols. Each protocol set supports
addresses of a certain format. An Address Family is the set
of addresses for a specific group of protocols. Each socket
has an address chosen from the address family in which the
socket was created.
Special Processes
The processes with a process ID's of 0, 1, and 2 are spe-
cial. Process 0 is the scheduler. Process 1 is the ini-
tialization process init, and is the ancestor of every other
process in the system. It is used to control the process
structure. Process 2 is the paging daemon.
Super-user
A process is recognized as a super-user process and is
granted special privileges if its effective user ID is 0.
Tty Group ID
Each active process can be a member of a terminal group that
is identified by a positive integer called the tty group ID.
This grouping is used to arbitrate between multiple jobs
contending for the same terminal (see csh(1), and tty(4)).
SEE ALSO
intro(3), perror(3)
LIST OF SYSTEM CALLS
Name Appears on Page Description
_exit exit(2) terminate a process
accept accept(2) accept a connection on a socket
access access(2) determine accessibility of file
acct acct(2) turn accounting on or off
adjtime adjtime(2) correct the time to allow synchronization of the system clock
async_daemon nfssvc(2) NFS daemons
bind bind(2) bind a name to a socket
brk brk(2) change data segment size
chdir chdir(2) change current working directory
chmod chmod(2) change mode of file
chown chown(2) change owner and group of a file
chroot chroot(2) change root directory
close close(2) delete a descriptor
connect connetc(2) initiate a connection on a socket
creat creat(2) create a new file
dup dup(2) duplicate a descriptor
dup2 dup(2) duplicate a descriptor
execve execve(2) execute a file
fchmod chmod(2) change mode of file
fchown chown(2) change owner and group of a file
fcntl fcntl(2) file control
flock flock(2) apply or remove an advisory lock on an open file
fork fork(2) create a new process
fstat stat(2) get file status
fsync fsync(2) synchronize a file's in-core state with that on disk
ftruncate truncate(2) truncate a file to a specified length
getdirentries getdirentries(2) gets directory entries in a filesystem independent format
getdomainname getdomainname(2) get name of current domain
getdtablesize getdtablesize(2) get descriptor table size
getegid getgid(2) get group identity
geteuid getuid(2) get effective user identity
getgid getgid(2) get group identity
getgroups getgroups(2) get group access list
gethostid gethostid(2) get unique identifier of current host
gethostname gethostname(2) get name of current host
getitimer getitimer(2) get value of interval timer
getpagesize getpagesizename(2) get system page size
getpeername getpeername(2) get name of connected peer
getpgrp setpgrp(2V) set and/or return the process group of a process
getpid getpid(2) get parent process identification
getppid getpid(2) get process identification
getpriority getpriority(2) get program scheduling priority
getrlimit getrlimit(2) control maximum system resource consumption
getrusage getrusage(2) get information about resource utilization
getsockname getsockname(2) get socket name
getsockopt getsockopt(2) get options on sockets
gettimeofday gettimeofday(2) get date and time
getuid getuid(2) get user identity
ioctl ioctl(2) control device
kill kill(2) send signal to a process
killpg killpg(2) send signal to a process group
link link(2) make a hard link to a file
listen listen(2) listen for connections on a socket
lseek lseek(2) move read/write pointer
lstat stat(2) get file status
mkdir mkdir(2) make a directory file
mknod mknod(2) make a special file
mmap mmap(2) map or unmap pages of memory
mount mount(2) mount file system
msgctl msgctl(2) message control operations
msgget msgget(2) get message queue
msgop msgop(2) message operations
msgrcv msgop(2) message operations
msgsnd msgop(2) message operations
munmap munmap(2) map or unmap pages of memory
nfssvc nfssvc(2) NFS daemons
open open(2V) open or create a file for reading or writing
pipe pipe(2) create an interprocess communication channel
profil profil(2) execution time profile
ptrace ptrace(2) process trace
quotactl quotactl(2) manipulate disk quotas
read read(2V) read input
readlink readlink(2) read value of a symbolic link
readv read(2V) read input
reboot reboot(2) reboot system or halt processor
recv recv(2) receive a message from a socket
recvfrom recv(2) receive a message from a socket
recvmsg recv(2) receive a message from a socket
rename rename(2) change the name of a file
rmdir rmdir(2) remove a directory file
sbrk brk(2) change data segment size
select select(2) synchronous I/O multiplexing
semctl semctl(2) semaphore control operations
semget semget(2) get set of semaphores
semop semop(2) semaphore operations
send send(2) send a message from a socket
sendmsg send(2) send a message from a socket
sendto send(2) send a message from a socket
setdomainname getdomainname(2) set name of current domain
setgroups getgroups(2) set group access list
sethostname gethostname(2) set name of current host
setitimer getitimer(2) set value of interval timer
setpgrp setpgrp(2V) set and/or return the process group of a process
setpriority getpriority(2) set program scheduling priority
setregid setregid(2) set real and effective group IDs
setreuid setreuid(2) set real and effective user IDs
setrlimit getrlimit(2) control maximum system resource consumption
setsockopt getsockopt(2) set options on sockets
settimeofday gettimeofday(2) set date and time
shmat shmop(2) shared memory operations
shmctl shmctl(2) shared memory control operations
shmdt shmop(2) shared memory operations
shmget shmget(2) get shared memory segment
shmop shmop(2) shared memory operations
shutdown shutdown(2) shut down part of a full-duplex connection
sigblock sigblock(2) block signals
sigpause sigpause(2) atomically release blocked signals and wait for interrupt
sigsetmask sigsetmask(2) set current signal mask
sigstack sigstack(2) set and/or get signal stack context
sigvec sigvec(2) software signal facilities
socket socket(2) create an endpoint for communication
socketpair socketpair(2) create a pair of connected sockets
stat stat(2) get file status
statfs statfs(2) get file system statistics
swapon swapon(2) add a swap device for interleaved paging/swapping
symlink symlink(2) make symbolic link to a file
sync sync(2) update super-block
syscall syscall(2) indirect system call
tell lseek(2) locate read/write pointer
truncate truncate(2) truncate a file to a specified length
umask umask(2) set file creation mode mask
uname uname(2V) get name of current UNIX system
unlink unlink(2) remove directory entry
unmount umount(2) remove a file system
utimes utimes(2) set file times
vadvise vadvise(2) give advice to paging system
vfork vfork(2) spawn new process in a virtual memory efficient way
vhangup vhangup(2) virtually ``hangup'' the current control terminal
wait wait(2) wait for process to terminate or stop
wait3 wait(2) wait for process to terminate or stop
write write(2V) write output
writev write(2V) write output

330
doc/kcc/calls.open Executable file
View File

@@ -0,0 +1,330 @@
OPEN(2V) SYSTEM CALLS OPEN(2V)
NAME
open - open or create a file for reading or writing
SYNOPSIS
#include <sys/file.h>
int open(path, flags [ , mode ] )
char *path;
int flags, mode;
DESCRIPTION
path points to the pathname of a file. open opens the named
file for reading and/or writing, as specified by the flags
argument, and returns a descriptor for that file. The flags
argument may indicate the file is to be created if it does
not already exist (by specifying the O_CREAT flag), in which
case the file is created with mode mode as described in
chmod(2) and modified by the process' umask value (see
umask(2)). If the path is a null string, the kernel maps
this null pathname to ., the current directory. flags
values are constructed by ORing flags from the following
list (only one of the first three flags below may be used):
O_RDONLY Open for reading only.
O_WRONLY Open for writing only.
O_RDWR Open for reading and writing.
O_NDELAY When opening a FIFO with O_RDONLY or O_WRONLY set:
If O_NDELAY is set:
An open for reading-only will return without
delay. An open for writing-only will return
an error if no process currently has the file
open for reading.
If O_NDELAY is clear:
An open for reading-only will block until a
process opens the file for writing. An open
for writing-only will block until a process
opens the file for reading.
When opening a file associated with a communication
line:
If O_NDELAY is set:
The open will return without waiting for car-
rier. The first time the process attempts to
Sun Release 3.2 Last change: 16 July 1986 1
OPEN(2V) SYSTEM CALLS OPEN(2V)
perform I/O on the open file it will block
(not currently implemented).
If O_NDELAY is clear:
The open will block until carrier is present.
O_APPEND If set, the file pointer will be set to the end of
the file prior to each write.
O_CREAT If the file exists, this flag has no effect. Oth-
erwise, the owner ID of the file is set to the
effective user ID of the process, the group ID of
the file is set to the group ID of the directory in
which the file is created, and the low-order 12
bits of the file mode are set to the value of mode
modified as follows (see creat(2)):
All bits set in the file mode creation mask of
the process are cleared. See umask(2).
The ``save text image after execution'' bit of
the mode is cleared. See chmod(2).
O_TRUNC If the file exists, its length is truncated to 0
and the mode and owner are unchanged.
O_EXCL If O_EXCL and O_CREAT are set, open will fail if
the file exists. This can be used to implement a
simple exclusive access locking mechanism. If
O_EXCL is set and the last component of the path-
name is a symbolic link, the open will fail even if
the symbolic link points to a non-existent name.
The file pointer used to mark the current position within
the file is set to the beginning of the file.
The new descriptor is set to remain open across execve sys-
tem calls; see close(2) and fcntl(2).
There is a system enforced limit on the number of open file
descriptors per process, whose value is returned by the
getdtablesize(2) call.
SYSTEM V DESCRIPTION
If the O_NDELAY flag is set on an open, that flag is set for
that file descriptor (see fcntl) and may affect subsequent
reads and writes. See read(2V) and write(2V).
RETURN VALUE
The value -1 is returned if an error occurs, and external
variable errno is set to indicate the cause of the error.
Sun Release 3.2 Last change: 16 July 1986 2
OPEN(2V) SYSTEM CALLS OPEN(2V)
Otherwise a non-negative numbered file descriptor for the
new open file is returned.
ERRORS
Open fails if:
ENOTDIR A component of the path prefix of path is not
a directory.
EINVAL path contains a character with the high-order
bit set.
ENAMETOOLONG The length of a component of path exceeds 255
characters, or the length of path exceeds
1023 characters.
ENOENT O_CREAT is not set and the named file does
not exist.
ENOENT A component of the path prefix of path does
not exist.
ELOOP Too many symbolic links were encountered in
translating path.
EACCES Search permission is denied for a component
of the path prefix of path.
EACCES The required permissions (for reading and/or
writing) are denied for the file named by
path.
EACCES The file referred to by path does not exist,
O_CREAT is specified, and the directory in
which it is to be created does not permit
writing.
EISDIR The named file is a directory, and the argu-
ments specify it is to be opened for writing.
ENXIO O_NDELAY is set, the named file is a FIFO,
O_WRONLY is set, and no process has the file
open for reading.
EMFILE The system limit for open file descriptors
per process has already been reached.
ENFILE The system file table is full.
ENOSPC The file does not exist, O_CREAT is speci-
fied, and the directory in which the entry
for the new file is being placed cannot be
Sun Release 3.2 Last change: 16 July 1986 3
OPEN(2V) SYSTEM CALLS OPEN(2V)
extended because there is no space left on
the file system containing the directory.
ENOSPC The file does not exist, O_CREAT is speci-
fied, and there are no free inodes on the
file system on which the file is being
created.
EDQUOT The file does not exist, O_CREAT is speci-
fied, and the directory in which the entry
for the new file is being placed cannot be
extended because the user's quota of disk
blocks on the file system containing the
directory has been exhausted.
EDQUOT The file does not exist, O_CREAT is speci-
fied, and the user's quota of inodes on the
file system on which the file is being
created has been exhausted.
EROFS The named file does not exist, O_CREAT is
specified, and the file system on which it is
to be created is a read-only file system.
EROFS The named file resides on a read-only file
system, and the file is to be opened for
writing.
ENXIO The file is a character special or block spe-
cial file, and the associated device does not
exist.
EINTR A signal was caught during the open system
call.
ETXTBSY The file is a pure procedure (shared text)
file that is being executed and the open call
requests write access.
EIO An I/O error occurred while reading from or
writing to the file system.
EFAULT path points outside the process's allocated
address space.
EEXIST O_EXCL and O_CREAT were both specified and
the file exists.
EOPNOTSUPP An attempt was made to open a socket (not
currently implemented).
Sun Release 3.2 Last change: 16 July 1986 4
OPEN(2V) SYSTEM CALLS OPEN(2V)
SEE ALSO
chmod(2), close(2), dup(2), fcntl(2), lseek(2), read(2V),
write(2V), umask(2)
Sun Release 3.2 Last change: 16 July 1986 5

198
doc/kcc/calls.read Executable file
View File

@@ -0,0 +1,198 @@
READ(2V) SYSTEM CALLS READ(2V)
NAME
read, readv - read input
SYNOPSIS
cc = read(d, buf, nbytes)
int cc, d;
char *buf;
int nbytes;
#include <sys/types.h>
#include <sys/uio.h>
cc = readv(d, iov, iovcnt)
int cc, d;
struct iovec *iov;
int iovcnt;
DESCRIPTION
read attempts to read nbytes of data from the object refer-
enced by the descriptor d into the buffer pointed to by buf.
readv performs the same action, but scatters the input data
into the iovcnt buffers specified by the members of the iov
array: iov[0], iov[1], ..., iov[iovcnt-1].
For readv, the iovec structure is defined as
struct iovec {
caddr_t iov_base;
int iov_len;
};
Each iovec entry specifies the base address and length of an
area in memory where data should be placed. readv will
always fill an area completely before proceeding to the
next.
On objects capable of seeking, the read starts at a position
given by the pointer associated with d (see lseek(2)). Upon
return from read, the pointer is incremented by the number
of bytes actually read.
Objects that are not capable of seeking always read from the
current position. The value of the pointer associated with
such an object is undefined.
Upon successful completion, read and readv return the number
of bytes actually read and placed in the buffer. The system
guarantees to read the number of bytes requested if the
descriptor references a normal file which has that many
bytes left before the end-of-file, but in no other case.
Sun Release 3.4 Last change: 25 July 1986 1
READ(2V) SYSTEM CALLS READ(2V)
If the returned value is 0, then end-of-file has been
reached.
When attempting to read from a descriptor associated with an
empty pipe, socket, or FIFO:
If O_NDELAY is set, the read will return a -1 and errno
will be set to EWOULDBLOCK.
If O_NDELAY is clear, the read will block until data is
written to the pipe or the file is no longer open for
writing.
When attempting to read from a descriptor associated with a
tty that has no data currently available:
If O_NDELAY is set, the read will return a -1 and errno
will be set to EWOULDBLOCK.
If O_NDELAY is clear, the read will block until data
becomes available.
If O_NDELAY is set, and less data are available than are
requested by the read or readv, only the data that are
available are returned, and the count indicates how many
bytes of data were actually read.
SYSTEM V DESCRIPTION
When an attempt is made to read a descriptor which is in
no-delay mode, and there is no data currently available,
read will return a 0 instead of returning a -1 and setting
errno to EWOULDBLOCK. Note that this is indistinguishable
from end-of-file.
RETURN VALUE
If successful, the number of bytes actually read is
returned. Otherwise, a -1 is returned and the global vari-
able errno is set to indicate the error.
ERRORS
read and readv will fail if one or more of the following are
true:
EBADF d is not a valid file descriptor open for
reading.
EISDIR d refers to a directory which is on a file
system mounted using the NFS.
EFAULT buf points outside the allocated address
space.
Sun Release 3.4 Last change: 25 July 1986 2
READ(2V) SYSTEM CALLS READ(2V)
EIO An I/O error occurred while reading from or
writing to the file system.
EINTR A read from a slow device was interrupted
before any data arrived by the delivery of a
signal.
EINVAL The pointer associated with d was negative.
EWOULDBLOCK The file was marked for non-blocking I/O, and
no data were ready to be read. In addition,
readv may return one of the following errors:
EINVAL Iovcnt was less than or equal to 0, or
greater than 16.
EINVAL One of the iov_len values in the iov array
was negative.
EINVAL The sum of the iov_len values in the iov
array overflowed a 32-bit integer.
EFAULT Part of iov points outside the process's
allocated address space.
SEE ALSO
dup(2), fcntl(2), open(2), pipe(2), select(2), socket(2),
socketpair(2)
Sun Release 3.4 Last change: 25 July 1986 3

198
doc/kcc/calls.stat Executable file
View File

@@ -0,0 +1,198 @@
STAT(2) SYSTEM CALLS STAT(2)
NAME
stat, lstat, fstat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
stat(path, buf)
char *path;
struct stat *buf;
lstat(path, buf)
char *path;
struct stat *buf;
fstat(fd, buf)
int fd;
struct stat *buf;
DESCRIPTION
_s_t_a_t obtains information about the file named by _p_a_t_h.
Read, write or execute permission of the named file is not
required, but all directories listed in the path name lead-
ing to the file must be searchable.
_l_s_t_a_t is like _s_t_a_t except in the case where the named file
is a symbolic link, in which case _l_s_t_a_t returns information
about the link, while _s_t_a_t returns information about the
file the link references.
_f_s_t_a_t obtains the same information about an open file refer-
enced by the argument descriptor, such as would be obtained
by an _o_p_e_n call.
_b_u_f is a pointer to a _s_t_a_t structure into which information
is placed concerning the file. The contents of the struc-
ture pointed to by _b_u_f include the following members:
dev_t st_dev; /* device inode resides on */
ino_t st_ino; /* this inode's number */
u_short st_mode;/* protection */
short st_nlink;/* number of hard links to the file */
short st_uid; /* user ID of owner */
short st_gid; /* group ID of owner */
dev_t st_rdev;/* the device type, for inode that is device */
off_t st_size;/* total size of file, in bytes */
time_t st_atime;/* file last access time */
time_t st_mtime;/* file last modify time */
time_t st_ctime;/* file last status change time */
long st_blksize;/* optimal blocksize for file system i/o ops */
long st_blocks;/* actual number of blocks allocated */
Sun Release 3.2 Last change: 16 July 1986 1
STAT(2) SYSTEM CALLS STAT(2)
st_atime Time when file data was last read or modified.
Changed by the following system calls: _m_k_n_o_d(2),
_u_t_i_m_e_s(2), _r_e_a_d(2V), _w_r_i_t_e(2V), and _t_r_u_n_c_a_t_e(2).
For reasons of efficiency, st_atime is not set
when a directory is searched, although this
would be more logical.
st_mtime Time when data was last modified. It is not set
by changes of owner, group, link count, or mode.
Changed by the following system calls: _m_k_n_o_d(2),
_u_t_i_m_e_s(2), _w_r_i_t_e(2V).
st_ctime Time when file status was last changed. It is
set both both by writing and changing the i-
node. Changed by the following system calls:
_c_h_m_o_d(2) _c_h_o_w_n(2), _l_i_n_k(2), _m_k_n_o_d(2), _r_e_n_a_m_e(2),
_u_n_l_i_n_k(2), _u_t_i_m_e_s(2), _w_r_i_t_e(2V), _t_r_u_n_c_a_t_e(2).
The status information word _s_t__m_o_d_e has bits:
#define S_IFMT 0170000/* type of file */
#define S_IFIFO 0010000/* fifo special */
#define S_IFCHR 0020000/* character special */
#define S_IFDIR 0040000/* directory */
#define S_IFBLK 0060000/* block special */
#define S_IFREG 0100000/* regular file */
#define S_IFLNK 0120000/* symbolic link */
#define S_IFSOCK 0140000/* socket */
#define S_ISUID 0004000/* set user id on execution */
#define S_ISGID 0002000/* set group id on execution */
#define S_ISVTX 0001000/* save swapped text even after use */
#define S_IREAD 0000400/* read permission, owner */
#define S_IWRITE 0000200/* write permission, owner */
#define S_IEXEC 0000100/* execute/search permission, owner */
The mode bits 0000070 and 0000007 encode group and others
permissions (see _c_h_m_o_d(2)).
RETURN VALUE
Upon successful completion a value of 0 is returned. Other-
wise, a value of -1 is returned and _e_r_r_n_o is set to indicate
the error.
ERRORS
_s_t_a_t and _l_s_t_a_t will fail if one or more of the following are
true:
ENOTDIR A component of the path prefix of _p_a_t_h is not
a directory.
EINVAL _p_a_t_h contains a character with the high-order
bit set.
Sun Release 3.2 Last change: 16 July 1986 2
STAT(2) SYSTEM CALLS STAT(2)
ENAMETOOLONG The length of a component of _p_a_t_h exceeds 255
characters, or the length of _p_a_t_h exceeds
1023 characters.
ENOENT The file referred to by _p_a_t_h does not exist.
EACCES Search permission is denied for a component
of the path prefix of _p_a_t_h.
ELOOP Too many symbolic links were encountered in
translating _p_a_t_h.
EFAULT _b_u_f or _p_a_t_h points to an invalid address.
EIO An I/O error occurred while reading from or
writing to the file system.
_f_s_t_a_t will fail if one or both of the following are true:
EBADF _f_d is not a valid open file descriptor.
EFAULT _b_u_f points to an invalid address.
EIO An I/O error occurred while reading from or
writing to the file system.
CAVEAT
The fields in the stat structure currently marked _s_t__s_p_a_r_e_1,
_s_t__s_p_a_r_e_2, and _s_t__s_p_a_r_e_3 are present in preparation for
inode time stamps expanding to 64 bits. This, however, can
break certain programs which depend on the time stamps being
contiguous (in calls to _u_t_i_m_e_s(2)).
SEE ALSO
chmod(2), chown(2), readlink(2), utimes(2)
Sun Release 3.2 Last change: 16 July 1986 3

198
doc/kcc/calls.write Executable file
View File

@@ -0,0 +1,198 @@
WRITE(2V) SYSTEM CALLS WRITE(2V)
NAME
write, writev - write output
SYNOPSIS
cc = write(d, buf, nbytes)
int cc, d;
char *buf;
int nbytes;
#include <sys/types.h>
#include <sys/uio.h>
cc = writev(d, iov, iovcnt)
int cc, d;
struct iovec *iov;
int iovcnt;
DESCRIPTION
_w_r_i_t_e attempts to write _n_b_y_t_e_s of data to the object refer-
enced by the descriptor _d from the buffer pointed to by _b_u_f.
_w_r_i_t_e_v performs the same action, but gathers the output data
from the _i_o_v_c_n_t buffers specified by the members of the _i_o_v
array: iov[0], iov[1], ..., iov[iovcnt-1].
For _w_r_i_t_e_v, the _i_o_v_e_c structure is defined as
struct iovec {
caddr_t iov_base;
int iov_len;
};
Each _i_o_v_e_c entry specifies the base address and length of an
area in memory from which data should be written. _w_r_i_t_e_v
will always write a complete area before proceeding to the
next.
On objects capable of seeking, the _w_r_i_t_e starts at a posi-
tion given by the pointer associated with _d, see _l_s_e_e_k(2).
Upon return from _w_r_i_t_e, the pointer is incremented by the
number of bytes actually written.
Objects that are not capable of seeking always write from
the current position. The value of the pointer associated
with such an object is undefined.
If the O_APPEND flag of the file status flags is set, the
file pointer will be set to the end of the file prior to
each write.
If the real user is not the super-user, then _w_r_i_t_e clears
the set-user-id bit on a file. This prevents penetration of
system security by a user who "captures" a writable set-
Sun Release 3.2 Last change: 16 July 1986 1
WRITE(2V) SYSTEM CALLS WRITE(2V)
user-id file owned by the super-user.
When using non-blocking I/O on objects that are subject to
flow control, such as sockets, pipes (or FIFOs), or termi-
nals, _w_r_i_t_e and _w_r_i_t_e_v may write fewer bytes than requested;
the return value must be noted, and the remainder of the
operation should be retried when possible. If such an
object's buffers are full, so that it cannot accept any
data, then _w_r_i_t_e and _w_r_i_t_e_v will return -1 and set _e_r_r_n_o to
EWOULDBLOCK. Otherwise, they will block until space becomes
available.
SYSTEM V DESCRIPTION
A _w_r_i_t_e (but not a _w_r_i_t_e_v) on an object that cannot accept
any data will return a count of 0, rather than returning-1
and setting _e_r_r_n_o to EWOULDBLOCK.
RETURN VALUE
Upon successful completion the number of bytes actually wri-
ten is returned. Otherwise a -1 is returned and the global
variable _e_r_r_n_o is set to indicate the error.
ERRORS
_w_r_i_t_e and _w_r_i_t_e_v will fail and the file pointer will remain
unchanged if one or more of the following are true:
EBADF _d is not a valid descriptor open for writing.
EPIPE An attempt is made to write to a pipe that is
not open for reading by any process (or to a
socket of type SOCK_STREAM that is connected
to a peer socket.) Note: an attempted write
of this kind will also cause you to recieve a
SIGPIPE signal from the kernel. If you've
not made a special provision to catch or
ignore this signal, your process will die.
EFBIG An attempt was made to write a file that
exceeds the process's file size limit or the
maximum file size.
EFAULT Part of _i_o_v or data to be written to the file
points outside the process's allocated
address space.
a signal whose.SM SV_INTERRUPT
The call is forced to terminate prematurely due to the arrival of
bit in sv_flags is set (see _s_i_g_v_e_c(2)).
_s_i_g_n_a_l(3V), in the System V compatibility
library, sets this bit for any signal it
catches.
Sun Release 3.2 Last change: 16 July 1986 2
WRITE(2V) SYSTEM CALLS WRITE(2V)
EINVAL The pointer associated with _d was negative.
ENOSPC There is no free space remaining on the file
system containing the file.
EDQUOT The user's quota of disk blocks on the file
system containing the file has been
exhausted.
EIO An I/O error occurred while reading from or
writing to the file system.
EWOULDBLOCK The file was marked for non-blocking I/O, and
no data could be written immediately.
In addition, _w_r_i_t_e_v may return one of the following errors:
EINVAL _I_o_v_c_n_t was less than or equal to 0, or
greater than 16.
EINVAL One of the _i_o_v__l_e_n values in the _i_o_v array
was negative.
EINVAL The sum of the _i_o_v__l_e_n values in the _i_o_v
array overflowed a 32-bit integer.
SEE ALSO
fcntl(2), lseek(2), open(2V), pipe(2), select(2)
Sun Release 3.2 Last change: 16 July 1986 3

1526
doc/kcc/cc.doc Executable file

File diff suppressed because it is too large Load Diff

123
doc/kcc/coding.doc Executable file
View File

@@ -0,0 +1,123 @@
KCC Runtime Library Coding
This file is oriented towards KCC implementors and describes
some general rules for writing C library functions, along with a more
detailed explanation of certain crucial files in the library.
The source for all library routines is kept in <xx.LIB> where
"xx" depends on your system; on the distribution it is usually something
like "KCC-4". Since that doesn't matter here, it will be left out of
any filenames mentioned.
<.LIB*> Runtime library sources: Documented in:
<.LIB> General-purpose library routines. (LIBC.DOC)
<.LIB.STDIO> Standard I/O package routines. (LIBC.DOC)
<.LIB.MATH> Math library routines. (LIBC.DOC)
<.LIB.USYS> Unix simulation routines. (USYS.DOC)
<.LIB.NETWORK> A stab at a couple BSD net routines. (LIBC.DOC)
<.LIB.PML> Unused "portable math library" routines.
<.LIB.TEST> Unused testing routines.
Guidelines for writing C library modules:
ALWAYS #include "c-env.h" before anything else, unless the
code is truly portable and completely in C. Note this is "c-env.h",
not <c-env.h>, so that it is easy to test variations.
All source files for KCC and the LIBC routines should refer to
their header files with "" instead of <>, so that different versions
of the .H files can be tested easily in the source directory before
installation in the system-wide standard location. Normal compilation
can simply point to the standard include-file location with the -I
switch. However, note that user programs, unlike the library sources,
should always use <>.
Keep all versions of a function together in the same file,
rather than having a different file for each version depending on the
system. Just conditionalize any system-dependent code appropriately.
If trying to assemble for an unsupported system or CPU, invoke
the #error preprocessor command to cause a compilation error with an
appropriate message. Alternatively, if it is important that a
function symbol exist even though it is unsupported, you can code for
a function that always fails with an error printout to stderr.
In general each specific library function should have its own
individual file, although several functions can be collected in the
same file if they are really tightly bound together. Any routine that
needs to use a system call should consider using #asm for efficiency,
instead of the jsys() or syscal() functions. (This is not normally
recommended, but since library routines are heavily used and rarely
modified, it's somewhat more acceptable.)
ASSEMBLER HACKERS:
.FAI or .MAC source modules should never exist. Functions which
require assembly code should use the #asm or asm() feature of KCC.
See the KCC user documentation for details on this.
Use $ or % for runtime-only externals, switches, and macros,
to avoid possible conflict with C symbols. Remember "_" in a C symbol is
equivalent to "." in an assembler symbol.
The C runtime support has the following symbol conventions:
$$$xxx Major module entry name.
$$xxxx Global symbol value, internal to runtimes.
$xxxxx Global label, internal to runtimes.
%xxxxx Macro-type instruction.
%%xxxx Miscellaneous macro function.
USYS routines:
If writing a UNIX system-call simulation routine (which should
go into <.USYS>), there are additional things to be careful of, and the
file USYS.DOC should be consulted.
IMPORTANT FILES:
C-ENV.H - C Environment defs. Contains all system/CPU configuration defs.
Copy kept in standard include dir.
Should be included by every LIBC routine which has any system
or environment dependencies. Different versions of this file exist
for different systems/machines/configurations. Can also be included
by user programs. IFNDEFs allow testing temporary changes by using
the -D switch, although this should be done in conjunction with the
appropriate -x= switches.
CPU.C - Load-time CPU definitions for target machine, determined by C-ENV.H.
Entry point: $$$CPU (a dummy)
This module is part of the C library and defines the values for
several symbols which depend on the specific processor that the program
is being loaded for. The primary usefulness of this module is that it
allows the user to defer until load time the decision of whether to build
a program for extended or non-extended operation. It also sets the right
symbols to ensure that all loaded modules are compatible with the CPU type
being loaded for.
CRT.C - Standard C Run Time support for KCC.
Entry point: $$$CRT (a dummy)
Globals: $START Startup
__EXIT Exit
_END,_ETEXT,_EDATA,_EALLOC Hack: Unix simul (shd move)
$RET,$RETF,$RETZ,$RETT,$RETP,$RETN Return points
$ZERO Handy zero constant
$ADJBP ADJBP simulation
$Bxxxx Various byte-pointer tables
All C programs start here. CRT is responsible for setting up
the C environment so that C code can execute properly. It specifically
does not do anything about setting up a UNIX environment; that is up to
whatever it is loaded with. When the C environment is ready, it calls
the routine _runtm() which should perform any remaining setup and then
call main(). Normally this routine is found in URT.C, the Unix-simulation
Run Time module.
URT.C - UNIX-simulation Run Time support (in <.LIB.USYS>)
Entry points: _RUNTM EXIT .EXIT ERRNO
This module is written in C, and is called by CRT once the C
environment is set up. URT then sets up the UNIX simulation
environment, parsing the command line and setting up stdin, stdout,
and stderr. When ready, it calls the user's main() function with the
parsed command line as a normal "argc,argv" array of char pointers.

469
doc/kcc/codsig.doc Executable file
View File

@@ -0,0 +1,469 @@
UN*X SIGNAL SIMULATION - IMPLEMENTATION NOTES
This file documents some of the unholy and intimate details of
how the KCC USYS library routines simulate the Un*x signal mechanism.
It does not explain everything. To seriously understand what is going
on, you need to read the exhaustive comments in the source files
(SIGVEC.C and <signal.h>) as well as the user-oriented file
SIGNAL.DOC.
KCC Implementation:
We try to implement 4.3BSD, since with that the older, cruder
mechanisms can be emulated also.
ITS has a very powerful software interrupt system and can
readily handle the BSD scheme. T20 has more trouble. T10 as far as
known is simply out of it altogether. This document is primarily about
the T20 implementation (the only one currently existing).
First, a note on what "a/synchronous" means:
A SYNCHRONOUS interrupt is one that happens at a specific PC
due to the instruction at that location. Typical examples: illegal
instruction interrupts (which can include JSYS calls), floating-point
exceptions. For these types of interrupts the PC is significant and
it or the contents it points to may need to be checked to determine
what to do, because simply continuing the process at that PC will
very likely just generate another such interrupt.
An ASYNCHRONOUS interrupt is one that may happen at ANY time,
regardless of place; these are generated by events external to the
program. Typical examples: TTY input interrupts, timer interrupts.
For these, the PC is unimportant except that it should be preserved
and restored if the interrupt handler wishes to continue whatever was
interrupted.
No UN*X C signal handler has the capability of returning from
handling a synchronous interrupt. In fact there is no mechanism
provided for a signal handler to find out what its return PC is.
(it's possible, with trickery, but I've never seen an example).
4.3BSD (as opposed to 4.2 or any other Un*x) now makes this possible
by providing the handler with a pointer to a saved-context structure!
Note that some signal handlers return to normal code by
means of longjmp(); this is particularly true for alarm() handlers.
ANSI specifies that longjmp should restore the environment properly
even from within a signal handler, but is not required to do anything
meaningful if called from a nested signal handler. KCC supports this
use of longjmp().
T20 Problems:
(1) T20 PSIs have 3 priority levels. While interrupting at
one level, no other interrupts at that level can be serviced (although
they will be deferred). This is unlike UN*X where signals and their
handlers are all completely independent of each other.
(2) The T20 return address may be a "monitor address" which
indicates that a JSYS was interrupted before it completed. This can
only be continued by the first DEBRK at that interrupt level; anything
else aborts that JSYS, with unknown consequences.
To clarify: if the return PC does not have the user-mode bit set,
then it was interrupted out of a JSYS. The PC address however refers to
the user address space, and points to the JSYS return location (that is,
one greater than the location of the JSYS call.) As far as I can tell
from examination of the monitor code, a JSYS which is interrupted just
as it is about to return will have already changed the PC to user mode,
so the fact of a monitor-mode PC should always imply that there is still
something left which the JSYS hasn't yet finished doing. Unfortunately,
the fact that IIC% itself interrupts with a monitor-mode PC implies that
this analysis is bogus and that the PSI system is even more losing than
could possibly be expected.
Doing a DEBRK back to this place will complete the JSYS.
Doing a DEBRK anywhere else (or turning on the user-mode bit) will
abort it and the monitor forgets the saved context. It isn't clear
whether re-starting the JSYS, by backing up the PC by one, will do the
right things; the ACs may not have been properly adjusted. Given the
usual history of T20/10X, they probably haven't. This is the biggest
problem, but can be coped with if user code is careful. I think.
IIC% should NOT be restarted! SIN% and probably SOUT% appear
to update their ACs and can be restarted.
It is possible to execute a signal handler entirely within an
interrupt level even if the handler uses longjmp(), if longjmp conspires
to do a DEBRK when jumping back to the previous context. So the main
problem with handling interrupts in this way is the lock-out of other
interrupts.
FINAL PLAN:
Key aspect: all T20 PSI interrupts are handled IMMEDIATELY
and DEBRK'd as soon as possible. The time spent at interrupt
level is absolutely minimal, and no signal handlers will
be called at interrupt level unless specifically (and non-portably)
requested.
The UN*X signal mechanism is primarily implemented by
the PSI handling code, including the BSD signal block mask, rather
than by trying to use the monitor's PSI Jsys calls.
No USYS (Un*x System call simulation) routine should be interrupted.
If an internal JSYS is interrupted then that system call should
return -1 with errno set to EINTR. Otherwise things run through
to completion and the signal takes effect just before returning
a normal return value.
************************************************************************
NOTE!!!!! THE DETAILS OUTLINED IN THE REST OF THIS FILE ARE NOT
NECESSARILY COMPLETE!!! Read the sources also, namely:
SIGVEC.C - main source, PSI handlers
SIGDAT.C - additional important source
JSYS.C - jsys() function
************************************************************************
Global variables:
int _sigusys; /* Positive if within critical USYS code */
unsigned int _sigpendmask; /* 36-bit mask of pending signals */
/* PSI can add to this during _sigusys. */
unsigned int _sigblockmask; /* 36-bit mask saying which signals to block */
/* PSI cannot change this during _sigusys. */
BSD signal block mask:
This is implemented softwarily, by having the
PSI code check the mask itself and so forth, thus implementing
whatever notion of blocking is needed, rather than trying to defer the
actual PSIs themselves. This doesn't actually turn off the PSI
channels, and it is in theory possible there might be runaway
interrupts, but this seems unlikely. It cannot happen with
synchronous interrupts, and the asynchronous ones all seem fairly
sporadic. Installing the default action or no handler will still
result in turning off the relevant PSI channel.
If a PSI is triggered for a signal which is currently handled by
SIG_DFL (default) or SIG_IGN (ignored) then the actions are
straightforward. Actually no PSI should ever arrive for a SIG_DFL
handler.
If a PSI comes in for which a user signal handler is defined,
there are four cases that must be checked for:
(1) USYS code, user-mode PC - Simple deferred case.
(2) USYS code, JSYS-mode PC - Complex but all planned for.
(3) User code, user-mode PC - Simple immediate case.
(4) User code, JSYS-mode PC - Complex and unpredictable; worst!!
In general, user-mode PCs are simple. For JSYS-mode PCs things are
more complex. In fact, much of the hair in jsys() is due to the need
to coordinate its activities with those of the PSI handling system.
There is one special case: an illegal instruction interrupt (.ICILI)
is ALWAYS delivered with the PC claiming JSYS mode, regardless of
whether the offending instruction was a failing JSYS or a bad word
value. To handle this screw-up, the PSI handler checks
.ICILI interrupts specially and turns back on the user-mode PC bit if
the bad instruction was not a JSYS. This simplifies things for the
rest of the code.
(1) USYS code, user-mode PC - Simple deferred case.
If we are in USYS code we cannot call a handler. What we do
is set the signal's bit in _sigpendmask (for pending ints) and do a
simple DEBRK right back to the place interrupted from, so the USYS
code can run on to completion. Special checking is required for
synchronous interrupts, since those usually cannot be continued.
If the interrupt is .ICAOV or .ICFOV we can simply continue. Otherwise
we must fail with an error message.
(2) USYS code, JSYS-mode PC - Complex but all planned for.
Again, synchronous interrupts are a problem. For a JSYS-mode
synchronous interrupt we can only continue if the PC was within the
jsys() routine, in which case we can cause the jsys() call to abort
(whether or not it was marked as interruptible). Otherwise, our only
recourse is to halt the process with an error message.
The important thing about asynchronous interrupts is that
because the code interrupted from was USYS code, we can always be
assured that whatever form the JSYS invocation took, both the USYS
code and the PSI code agree on how the interrupt will be handled.
The pending signal bit is always set; no handler is ever invoked
from within inside USYS code. Since we always do an immediate DEBRK%, we
always have the option of either fully continuing a JSYS or of aborting it.
The USYS code has four different ways of invoking a JSYS:
Asynch Synch
(a) in-line with ERJMP Continue <imposs, fail w/err>
(b) in-line without ERJMP Continue fail with err msg
(c) jsys() with int flag do intret <imposs, but do intret>
(d) jsys() without flag Continue <imposs, but do intret>
The interesting case here is (c) where an asynchronous interrupt
causes the PSI code to turn on the user-mode bit and then DEBRK% to a
specific interrupt return location within jsys(). Otherwise, execution
merely continues.
A synchronous interrupt within jsys() is very unlikely,
because jsys() always has an ERJMP following a jsys invocation; also,
any reasonable USYS assembler code should have ERJMP to handle
expected errors. But if one happens, then:
b: halt process with error message.
a: should not happen, but halt with error msg anyway.
c,d: fail with an "interrupted" return value.
This is also not supposed to happen, but a reading of the
T20 page fault code seems to indicate it is possible for a
PSI to happen regardless of whether an ERJMP exists.
(3) User code, user-mode PC - Simple immediate case.
This is the simple, straightforward case.
We simply DEBRK to the signal handler, after saving all stuff on stack
such that if the handler returns, control returns to interrupted point.
Note that for synchronous interrupts that have the CF_OPC flag, the saved
PC is that of the guilty instruction, so that continuation will simply
generate another interrupt if the handler failed to remedy the problem!
(4) User code, JSYS-mode PC
This is the biggest problem.
Would be nice to only DEBRK when signal handler returns, cuz then
the JSYS could be continued. But having the priority level stuck will
prevent other signals from being handled, and longjmp() would have to
test for needing to hack DEBRK% itself. If at all possible we want
to avoid running signal handlers at interrupt level.
So we evidently have to do the same thing as for a user-mode
PC, and just call the signal handler with the DEBRK%.
Users can use the interruptable flag bit for jsys() calls, and this
will work. Otherwise, if there was any way of knowing whether it
was safe to re-start a JSYS then we could back up the PC to do this,
but as far as is known there isn't any guaranteed method. So "random"
JSYS calls that don't go through the jsys() facility are subject to
being aborted without any error indication.
Continuation actions for user code, JSYS-mode PC:
Asynch Synch
(a) in-line with ERJMP Restart <imposs, but take ERJMP>
(b) in-line without ERJMP Restart Restart
(c) jsys() with int flag do intret <imposs, but take intret>
(d) jsys() without flag Restart <imposs, but take intret>
There is one exception to the "Restart" action: if the JSYS was IIC% then
we simply "continue" (at the next instruction).
USYS interrupt handling:
We need some macros or functions, one to suspend interrupts at
the start of critical USYS code, and another to reactivate them once
the critical code is done. May also need one which checks for pending
interrupts. Hard part is how to handle an interruptible invocation of
jsys() such that no signal gets missed between the test for pending
signals and actual execution of the JSYS. The best way seems to be
for the PSI code to know about the address range of critical code in
jsys().
USYS_BEG(); - Suspends all signals; used by USYS code to tell
PSI stuff that a usys call is being executed.
#define USYS_BEG() (++_sigusys)
USYS_END(); - Reactivates all signals; used by USYS code to tell
PSI stuff that it's OK to handle signals now, and checks to
see if there are any pending signals that should be handled.
NOTE: the signal suspension is lifted BEFORE we test for pending
signals; if a signal happens after the lift but before the
_sigpendmask test, the worst that happens is we call
_sigtrigpend() unnecessarily.
If the ordering was reversed then we might
get a signal after the _sigpendmask test but before lifting
the suspension; that signal would never be serviced.
#define USYS_END() { if (--_sigusys <= 0 && _sigpendmask) \
_sigtrigpend(); }
USYS_RET(val); - Reactivates all signals; used by USYS code to tell
PSI stuff that a usys call is finished and about to return.
Also must check for pending signals and dispatch to handler if any.
NOTE: the return value is computed into a temporary location
so it cannot change regardless of what a signal handler does.
#define USYS_RET(val) { int tmpret = (val); \
USYS_END(); \
return tmpret; }
USYS_INTRET(-1); - same as above, when USYS code knows that a jsys() has
been interrupted and is returning for this reason. No test
of _sigpendmask is needed. We set errno last in an attempt to avoid
having its value changed by the signal handler; of course another
signal could happen anytime after errno is set and before it is
checked by the user program, but that is a problem with this
stupid mechanism on UN*X too.
#define USYS_INTRET(val) { --_sigusys; _sigtrigpend(); \
errno = EINTR; \
return val; } /* Should always be -1 */
USYS_SIGTST() - Tests for pending signals. Needed?
#define USYS_SIGTST() (_sigpendmask)
USYS code cautions:
The USYS routines need to be careful to always invoke the
signal macros appropriately. But a more important (and more subtle)
problem is that they also have to be careful of calling on other
library routines!
UN*X code assumes, of course, that a system call is executed
entirely within the kernel, and has no effect on anything in the process
address space other than things explicitly requested by the call. This
means that our USYS code must have the same non-effect; the routines
can only call those library functions which are fully re-entrant and
change no static data.
The problem is worse for those USYS calls invoked by a signal
handler. In particular, if any USYS routine calls malloc() then it
runs the risk of enormous unexpected screwage if the main user code
happened to be in the middle of a malloc call! Of course the user's
signal handler itself could call malloc() with similar bad consequences, but
in this case the user has control over what is going on, and presumably
knows what is going on.
PSI code:
All signal PSIs happen at level 2. If we are so unfortunate as to
get a panic PSI within the PSI code, this will cause process
termination, but the PSI code will be extremely minimal and should not
cause any problems.
Levels 1 and 3 can be reserved for the user, thus giving
flexibility of using a level either higher or lower than the Un*x
signal facility; some mechanism would have to be figured out, though
(see next page).
When a PSI interrupt happens:
Monitor saves PC in predefined table, jumps to PSI handler.
Save an AC or two for checking.
If SIG_DFL (default) was in effect, we shouldn't be getting this
PSI at all.
If SIG_IGN was in effect and PSI was enabled for this signal
then the PSI handler will be a do-nothing that just
DEBRK%s immediately.
Otherwise, we must have a handler of some type. "psisig" is the
location of the PSI handler for such signals. It distinguishes
between interrupts from USYS code and user code, as well as
whether the PC is a monitor (JSYS) or user-mode PC.
If the handler is invoked, this is done with a DEBRK%.
More on extensions to sigvec():
For additional flexibility, the "sigvec" structure can be extended
to include additional parameters. Existence of a new bit in sv_flags
would indicate that the additional structure members are significant.
The things we'd like to be able to specify, independently of each other:
SV_XINTLEV: ON If handler should run at interrupt level.
SV_XASMHAN: ON If handler is special assembler routine (ACs not saved,
no args given). Otherwise, normal C handler.
SV_XOS: ON If the OS structure should be checked for:
(1) Exact PSI channel # to use for this signal (0 = existing).
(2) What PSI level to use (0 = existing).
(3) .TICxx code (plus 1) to ATI% to this channel (0 = none).
Some of those are interdependent:
Specification of a positive .TIC code always replaces any existing
code by the new one, and use of -1 always clears any existing code. If
the value is 0, however, then the meaning depends on whether a channel #
was specified. If the channel # was given, 0 is the same as -1. Otherwise,
if no channel # was given, then 0 means leave any existing code alone.
If the handler is an assembly routine, then it MUST run at interrupt
level. Thus, it is an error to specify SV_XASMHAN without SV_XINTLEV.
Currently only SV_XINTLEV is implemented. It should work to use
longjmp() within handlers called with this flag!
Fixing up jsys():
The jsys() function has been fixed up so that it understands
which calls take what kinds of returns, and can guarantee the
following return values:
-1: interrupted
0: error (return error code in acs[0])
1,2,3: success, returned at that location.
The calls SIBE, SOBE, SOBF are weird. Not clear how to distinguish
an error return from a "normal" +1 or +2 return. Same applies to SKPIR.
GFRKH and GFRKS have both +1, +2, and Illeg-Instr PSIs.
Last remaining ambiguities are for the +3 returns, of which only 3
exist: ERSTR, GACTF, and STDIR (10X only). STDIR and GACTF are
simple as only the successes need to be distinguished. ERSTR is hard as
there are two different error returns.
STDIR (10X only) - all 3 returns counted as success. Error happens
if illegal instruction interrupt. Can distinguish success
returns by value 1,2,3.
GACTF - Returns 2 or 3 for success, 0 for failure (+1 return).
ERSTR - We'll have to fudge this one:
Return 0 for interrupt or +1 failure return.
Return 2 for the +2 failure return.
Return 3 for the +3 full winnage return.
So, for those three calls, the caller has to check the exact return value
and cannot just assume a positive return value means winnage.
The jsys() code needs to distinguish skipping from
non-skipping calls in order to return the right stuff.
Normally skips Non-skip
JSYS <E> JSYS <E>
ERJMP ret0 ERJMP ret0
JRST ret2 JRST ret1
JRST ret3
For 10X the normally-skipped ERJMP would have to be replaced by a
ERJMPA ret0, and the PSI handler made to know about this. Different
code sequences may be needed for the weirdos like SIBE/SOBE/SOBF.
Rather than keeping a global table indexed by JSYS value, it would be
possible to have the jsys-number argument to jsys() carry some flags
with it in the high-order bits which indicated what sort of jsys it
was, or what actions jsys() should carry out. The jsys-name macro
definitions in <jsys.h> can include those flags. This also makes it
easy for user programs to examine the flags as well, and they can be
used in #if preprocessor tests. This would involve putting the table
into UNV.C or whatever program is used to generate the <jsys.h> type
files from MONSYM.UNV.
JSYS-related PSI handling:
Some special handling is needed for interrupts from JSYS calls
and from within jsys(). This is discussed in more detail in a previous
part of this documentation.
_SIGTRIGPEND discussion:
Once _sigusys is turned off, any signals which arrived during the
call execution (but were suspended because _sigusys was on) need to be
triggered, and this is the function of _sigtrigpend().
If user handlers never expect to run at interrupt level then we
could "trigger" these signals entirely within our own software, without
fiddling with the T20 PSI system. However, to be most general it is best
if actual PSIs are triggered -- this can be done with IIC%.
While we are checking the pending signal mask, we have to be
careful, because if an asynchronous signal happens just after the code
has decided to trigger that signal, but before doing so, then
the handler could be called twice. We need to ensure that incoming
PSIs/signals are not serviced for the signals in _sigpendmask, even though
_sigusys must be off.
One straightforward method of solving this is to use DIR% to
temporarily disable the PSI system:
DIR% ; Suspend PSIs
<determine bits to give IIC>
IIC% ; Initiate PSIs on chans
EIR% ; Allow PSIs to take effect
However, the overhead of additional monitor calls is a little
annoying. We could also solve this in our software by having the PSI
code NOT service an interrupt if _sigpendmask already indicates a
signal instance is outstanding. Thus, _sigtrigpend() can proceed to
trigger signals on just those bits in _sigpendmask without fear that
an asynchronous interrupt will wrest away control in the middle; if a PSI
does happen for one of those bits, it will see that it is already set in
the mask and will simply DEBRK% right back.
Note that the only place that _sigpendmask bits are turned off
is within the PSI code just before jumping to a handler.
There's a BUG in this scheme, though: how does the signal handler
know when an interrupt on an already outstanding signal should be ignored,
and when it should be handled? _sigtrigpend() is doing an IIC% which
causes an interrupt indistinguishable from the real thing! So, to patch
this up, the PSI code needs to check the PC and see whether it's at the
IIC% in _sigtrigpend(); if it is, then it's OK to handle the signal.
A third solution might be possible such that IIC% is
unnecessary too. If the handler for a signal happens to want
interrupt-level processing (as this would be a special feature, most
handlers won't) then IIC% could be used anyway. This seems unlikely
however since at SOME point PSIs need to be turned off so that
bits can be tested and set without fear of having them changed out from
under, and normally it's the PSI code itself that has this security because
it is running at interrupt level. After all, we need to turn the bit in
_sigpendmask off just before jumping to the handler.
Another idea: don't worry about calling it twice, after all
the interrupt did happen at least twice?
Bad thought: not good to permit interrupts during sigtrigpend
because some of them might want to change things about the signal system,
by calling sigsetmask(), sigvec(), etc! Much safer to just prohibit
any handler calls whatsoever.

59
doc/kcc/codsys.doc Executable file
View File

@@ -0,0 +1,59 @@
CODSYS.DOC - Information on writing USYS routines.
Writing USYS routines:
USYS Header Files
<sys/usysio.h> T20 Defs for USYS I/O routines.
<sys/usysig.h> T20 Defs for USYS Signal stuff.
<sys/usytty.h> T20 Defs for USYS TTY stuff.
In order to implement signal handling correctly, we have to ensure
that no USYS routine has control wrested away from it, leaving internal
data in an inconsistent state. For this reason certain rules
must be followed:
[1] At the START of a USYS routine, invoke the macro USYS_BEG().
This and other USYS_ macros are defined in <sys/usysig.h>.
[2] When RETURNING from a USYS routine, invoke one of the following macros:
USYS_RET(val); Return a local variable or constant value.
USYS_RETVOLATILE(val); Return a volatile (global or function) value.
USYS_RETERR(err); Return -1, setting errno to "err".
USYS_RETINT(); Return -1, setting errno to EINTR.
Each of the USYS_RETxxx macros serves as a "return" statement, and
each takes care to process any pending signals. If a signal occurred
during the USYS routine, it is deferred until the USYS_RETxxx happens,
and is then handled just before returning to the user's program. The
reason for distinguishing RETVOLATILE from simple RET is because the
former case must save the return value in a temporary local-scope
location while any pending interrupts are processed. Otherwise, by the
time the actual return took place, the return value may have changed from
what it should have been!
Non-interference:
USYS routines are assumed not to interfere in any way with
non-USYS library functions. Thus, it is very, VERY bad for a USYS
routine to call a C library function which changes static data; the
user program will not be expecting this. Note that signal handlers
must be able to execute system calls, and any normal C library
function could be interrupted. malloc(), in particular, cannot be
used by a USYS routine for this reason!
JSYS calls:
When making a JSYS call, "fast" and "slow" calls need to be
distinguished. "fast" calls are those which never block or hang, and
for which no asynchronous PSI interrupts are expected to happen;
"slow" calls are those which have the potential to hang for indefinite
amounts of time, and should be considered interruptible. If using a
"slow" call, the JSYS_INTERRUPTABLE flag should be added to the
JSYS-number argument in the call to jsys(). The latter will return -1
if the call was interrupted, and in this case the USYS routine should
return with USYS_RETINT().
Things are actually a little more complicated than this, as
certain calls such as read() and write() must check to see whether they
should really be interrupted or if the signal handler permits them to
continue what they were doing. This is done by invoking USYS_END() and
examining its return value to see what happened. Look at the existing
code for read(), write(), and ioctl() for examples.

128
doc/kcc/humble.doc Executable file
View File

@@ -0,0 +1,128 @@
-*-Text-*-
HUMBLE - Functions for hacking inferiors.
#include <sys/humble.h>
The header file for using the humble package.
int j_create()
Creates an inferior, returns an FD or -1 if failure
This FD can be used just like any other file FD. It can even be used to do
I/O, although that is of limited utility. Conversely, a file FD obtained
from open() (by opening "USR:COMSAT IV" for example) will work with the
rest of the functions in the humble package, you don't have to use
j_create(). Although in that case it is kind of hard to control the
details of opening the USR: device.
Possible errors:
- Already have 8 inferiors.
- This job has no free channels.
- The system has no free job slots.
int j_kill(fd)
int fd;
Kills the specified inferior. Just like close() except it actually
destroys the job. Can only be applied to the last open FD. (Although I
don't see much advantage to dup'ing a job FD, it will work...)
Possible errors:
- Not a job FD.
- Not the last open FD.
int j_read(fd, addr, buf, count)
int fd, addr, *buf, count;
Copies COUNT words into BUF from the inferior starting at ADDR. Normally
returns 0. If error, it returns the number of words left to be written.
Possible errors:
- Not a job FD, negative count, negative or huge address.
- Tried to read nonexistent memory.
int j_write(fd, addr, buf, count)
int fd, addr, *buf, count;
Copies COUNT words from BUF into the inferior starting at ADDR. Creating
memory if it doesn't exist. Normally returns 0. If error it returns the
number of words left to be written.
Possible errors:
- Not a job FD, negative count, negative or huge address.
- System doesn't currently have enough virtual address space.
- Can't write into a foreign job.
int j_dump(job_fd, file_fd)
int job_fd, file_fd;
Writes a PDUMP file for the job on the freshly opened file.
Returns 0 if success and -1 if failure.
Possible errors:
- Not a job FD.
- File FD isn't open to DSK.
- DSK or directory full, etc.
int j_load(job_fd, file_fd)
int job_fd, file_fd;
Loads a PDUMP or SBLK file into the job from the freshly opened file.
Returns 0 if success and -1 if failure.
Possible errors:
- Not a job FD.
- File FD isn't open to DSK.
- File is in the wrong format.
int j_vread(fd, var, loc)
int fd, var, *loc;
Read a user variable. Returns 0 if it wins, -1 if failure.
VAR is a user variable specifier. LOC is where to store the result.
The header file humble.h defines the macro SIXBIT so that user variable
specifiers can be easily constructed. SIXBIT("USTP") returns the integer
that is the sixbit of "USTP". Other specifiers acceptable to .CALL USRVAR
will work as well.
Possible errors:
- Not a job FD.
- No such user variable.
int j_vwrite(fd, var, val)
int fd, var, val;
Write a user variable. Returns 0 if it wins, -1 if failure.
VAR is a user variable specifier. VAL is the new value.
Possible errors:
- Not a job FD.
- No such user variable.
- Can't write into this job.
int j_atty(fd)
int fd;
Allow an inferior to make use of the TTY. Returns 0 if it wins, -1
if failure.
Possible errors:
- Not a job FD.
- Job isn't an inferior.
int j_dtty()
Devour the TTY. Always returns 0. Can't possibly fail!

143
doc/kcc/instal.doc Executable file
View File

@@ -0,0 +1,143 @@
INSTALLING KCC ON A TOPS-20 SYSTEM
KCC is normally distributed over the Internet via FTP from
SRI-NIC.ARPA, but can also be obtained on tape. This file describes
the basics of installing KCC for each, but you should read everything
regardless of which medium you are using.
TAPE INSTALLATION:
The TOPS-20 tape consists of a single DUMPER saveset with
several directories. They are organized into a single tree with the
top-level directory named "KCCDIST" or "KCC-n" or whatever; for
purposes of discussion we'll assume the fictitious name "KCC-n". You
can either retrieve all files at once, or extract only those necessary
to install a working copy of KCC.
Retrieving all files:
Create a directory, such as KCCDIST, to hold the distribution.
This will contain the following:
<KCC-n> General information files, in particular:
CC.EXE The KCC compiler.
AGREE.TXT Ethical issues.
INSTAL.DOC Installation info; what you are reading now.
NEWS.TXT News about this version.
C: => <KCC-n.INCLUDE> Runtime library and include files.
CC.DOC KCC user documentation.
<KCC-n.INCLUDE.SYS> More include files, Un*x oriented.
<KCC-n.FAIL> FAIL assembler source, binary, and manual.
<KCC-n.KCC> KCC compiler sources and auxiliary files.
<KCC-n.LIB*> Runtime library sources:
<KCC-n.LIB> General-purpose library routines.
<KCC-n.LIB.STDIO> Standard I/O package routines.
<KCC-n.LIB.MATH> Math library routines.
<KCC-n.LIB.USYS> Unix simulation routines.
<KCC-n.LIB.NETWORK> A stab at a couple BSD net routines.
<KCC-n.LIB.PML> Unused "portable math library" routines.
<KCC-n.LIB.TEST> Unused testing routines.
Installing a working KCC:
To install a working copy of KCC, you should create a
directory to hold the runtime library and include files, and define
the logical name C: to point to it. This may be the same directory as
the one you restored the tape to (i.e. <KCC-n.INCLUDE>), or it may be
a different place. This directory should also have a subdirectory
called SYS to hold certain other include files.
Read the NEWS.TXT file for any special news about this version
of the distribution. Then define C:, copy CC.EXE to your site's SYS:
directory, and you're all set.
To summarize, these are the files you need:
<KCC-n>CC.EXE
C: => <KCC-n.INCLUDE>*.*.0 Runtime library and include files.
<KCC-n.INCLUDE.SYS>*.*.0 More include files, Un*x oriented.
Be sure to read the General Notes farther on in this file.
FTP transfer notes:
If you are fortunate enough to have Internet access, I
recommend that you use FTP (File Transfer Protocol) to get copies of
any KCC files that you need.
Connect to SRI-NIC.ARPA, and use the FTP anonymous login
convention (username "anonymous", password your real name) to log in.
The complete distribution is available in the directory tree defined
by the logical name KCCDIST:, which is organized exactly as described
in the previous (tape installation) section. You can retrieve any of
the files or directories mentioned as needed.
NOTE: the exact directory name which KCCDIST: points to will
vary! It may be <KCCDIST>, or <KCC-n>, or something else, so be
prepared to modify the given filenames appropriately.
BETA-TEST Versions:
For those interested in serving as "beta test" sites and
living dangerously, it is possible to acquire the very latest binaries
by transferring the following files:
SYS:CC.EXE Latest KCC.
C:*.*.0 Latest runtime library and include files.
C:<KCC.SYS>*.*.0 Latest Un*x-emulation include files.
Since KCC and the library are still evolving steadily, you will almost
certainly get something newer and better. Just be aware that you also
have the following risks:
(1) The binaries may contain new bugs.
(2) The new versions may be incompatible (this will cause linker
error messages to alert you, however).
(3) The new sources will not be available until things stabilize
enough for a new distribution to be made.
General Notes:
It is wise to retain the file version numbers during
installation, since that is how KCC versions are numbered; a higher
file version number means a more recent version of KCC.
C:CC.DOC contains user documentation. More internal details
may be available at various places in the directory tree, in files
named *.DOC.
KCC as distributed will invoke the FAIL assembler by
default, rather than MACRO, because FAIL is much faster. If you do
not have FAIL, you may wish to install it also. The .EXE binary,
.FAI source, and line-printer style manual (FAIL.MANUAL) are included.
If you don't want to try this, or for other reasons prefer to use
MACRO, then you will want to either recompile KCC with the CCSITE.H
file changed to reflect your preferences, or you can patch the "tgasm"
variable in CC.EXE to have the value 1.
MONITOR/EXEC Modifications:
There are certain modifications to the TOPS-20 Monitor and Exec
which KCC can make use of, if they are available. They are:
(1) Monitor: the PIP: device, to support pipes.
(2) Exec: PRARG% protocol to support "&" background processing.
(3) Exec: COMPIL-class command support.
Many sites already have these modifications, but if you don't, you
should be able to obtain them from their origin at Stanford; contact
Stu Grossman <Grossman@SIERRA.STANFORD.EDU>. Note that they are not
necessary, either to use KCC or run the C programs it compiles.
The COMPIL-class command change is simple enough to be described here:
The EXEC modifications to make its COMPILE/LOAD/etc commands
work with KCC can be found in the Stanford version of the EXEC
in the EXECCS module:
In the LANGUAGE macro definition, add:
L (DDT,C,CC,KCC) ;KCC
Immediately after the instruction at BSRC1, add:
CAIN P4,LT.C
RET
Immediately after the instruction at PUTDF, add:
CAIN P4,LT.C
SKIPA ; If KCC, always use native mode.

1230
doc/kcc/itskcc.mail Executable file

File diff suppressed because it is too large Load Diff

70
doc/kcc/jobdat.txt Executable file
View File

@@ -0,0 +1,70 @@
JOBDAT as of 9 Jan 78:
.JBUUO 40 User's UUO data location; opcode and EA stored here
.JB41 41 User's UUO trap address; contains instruction to go
to user's trap routine (usually JSR or PUSHJ)
.JBERR 42 LH: unused RH: accumulated error count
.JBREL 44 LH: 0 RH: highest lowseg address
.JBBLT 45 three locations used by the loader and monitor
.JBDDT 74 LH: Last addres of DDT RH: Starting address of DDT
if 0, DDT is not loaded
.JBHRL 115 LH: length of hiseg RH: highest legal address in
hiseg, 0 => no hiseg
.JBSYM 116 LH: Negative length of RH: Base address of symbol table
symbol table
.JBUSY 117 Same format as .JBSYM, pointer to undefined symbol table
.JBSA 120 LH: Initial .JBFF value RH: Start address
.JBFF 121 LH: 0 RH: Address of first free location
in lowseg; set to .JBSA<18,18>
by RESET UUO
.JBREN 124 LH: Unused RH: REENTER start address
.JBAPR 125 LH: 0 RH: Trap address for APR traps
.JBCNI 126 APR status from CONI when APR trap taken
.JBTPC 127 PC of next instruction when APR trap taken
.JBOPC 130 Previous .JOBPC saved by DDT, REENTER, START or CSTART
In some cases this value points to the erroneous UUO,
see the reference manual.
.JBCHN 131 LH: 0 or first free loc RH: Address of first location
after FORTRAN IV after first FORTRAN IV
program BLOCK DATA program
.JBCOR 133 LH: Highest location RH: User core argument on
in lowseg loaded last GET or SAVE command
with nonzero data
.JBINT 134 LH: reserved RH: 0 or address of error
intercept block
.JBVER 137 Version number: in octal, it is given as
gVVVmm,,eeeeee
where
g is the group who last modified the program:
0 - DEC development
1 - DEC
2,3,4 - Customers
5,6,7 - Customer's users
Mostly CMU ignores this field
VVV major version number, in octal
mm minor version number.
00 => no minor version
01 => A
02 => B etc.
eeeeee edit level
prints as (eeeeee)
e.g., the .JBVER version number 103402,,4556
would print to the VERSION command as 34B(4556)-1
NOTE: if the program has ONLY a high segment, .JBHVR must be set also!
For jobs with only a high segment, the vestigial job data area
is defined as the first '10 locations of the high segment, and
the fields are (relative to .JBHGH, usually 400000):
.JBHSA 0 Copy of .JBSA
.JBH41 1 Copy of .JB41
.JBHCR 2 Copy of .JBCOR
.JBHRN 3 LH: restores LH of .JBHRL
RH: restores RH of .JBREN
.JBHVR 4 Copy of .JBVER
.JBHNM 5 High-segment name set on a SAVE (sixbit)
.JBHSM 6 Pointer to highsegment symbols, if any
7 Reserved
.JBHDA 10 First free location after vestigial job data area

2749
doc/kcc/kcc.xmail Executable file

File diff suppressed because it is too large Load Diff

934
doc/kcc/libc.doc Executable file
View File

@@ -0,0 +1,934 @@
KCC Runtime Library documentation
This file summarizes the overall contents of the KCC C
library, and is used by implementors as a status file to determine the
portability or availability of particular library functions. This
file does NOT document what the functions do or how to use them, because
this information is already available in published form (see [CARM]
and [UPM] at the end of this page).
The organization of routines here follows that of the
descriptions in Part II of [CARM]. Note that as of this writing there
are two versions of CARM; the first (v1) appeared in 1984, and the
second (v2) in 1987. All references here are to the most recent (v2)
version, and the organization of this file follows sections 13-22 of
v2 rather than section 11 of v1.
KCC implements all CARM routines. In addition, there are
other routines which are part of KCC's C library, either for
compability with Un*x systems like V7 and BSD, or to provide access to
certain operating system functions. For the most part these have been
listed in whichever CARM section below is most appropriate, right
after the "official" CARM functions.
Additional information:
[CARM] Book: "C: A Reference Manual", Second edition, ISBN 0-13-109802-0
by Samuel P. Harbison & Guy L. Steele, Jr.
Also known as "H&S". This is a very good reference and
describes most of the library functions.
[UPM] Book: "Unix Programmer's Manual".
4.2/4.3BSD version (Reference Guide) printed by the USENIX Association.
[MAN] Files: "man foo" on most Un*x systems.
[TMX] File: LIBTMX.DOC - documents the extended time functions, time_*().
[USYS] File: USYS.DOC - contains a summary of those particular
KCC functions which simulate UN*X system calls. This is
considerably more implementor-oriented.
[SIGS] File: SIGNAL.DOC - contains an overview of the KCC signal
implementation.
[LIBC] File: LIB/CODING.DOC - describes guidelines for writing KCC library
functions and identifies certain crucial files. This is primarily
for implementors.
Contents summary:
Section 13: Standard Language Additions
Section 14: Character Processing (V1: Sec 11.1)
Section 15: String Processing (V1: Sec 11.2)
Section 16: Memory Functions
Section 17: Input/Output Facilities (V1: Sec 11.5)
Section 18: Storage Allocation (V1: Sec 11.4)
Section 19: Mathematical Functions (V1: Sec 11.3)
Section 20: Time and Date Functions
Section 21: Control Functions
Section 22: Miscellaneous Functions
Section BSD(3N): BSD network functions
Section TRM(3X): TERMCAP terminal independent functions
Section TMX(3X): Time and Date Functions (Extended)
Section KCC-1: KCC-specific general-purpose functions
Library function listing format:
Name Module Port Comments
(routine name) (source file) (see below)
Name: Name of the function, variable, or macro.
Module: Source file module. "XXX" means the pathname "lib/XXX.C"
unless the section identifies a different source directory,
such as "usys/" or "stdio/", etc.
Header files are shown as "<xxx.h>".
Port: A status code indicating portability, as follows:
E = file #includes "c-env.h" for environment configuration.
<sys> - runs on the given sys, one of: T20,10X,T10,WAITS,ITS.
*10 = portable to all of the above PDP-10 systems.
* = fully portable (either no OS-dependent stuff, or a
fully-portable conditional exists)
Section 13: Standard Language Additions
Name Module Port Comments
NULL <stddef.h>,<stdio.h> *
typedef ... ptrdiff_t; <stddef.h> *
typedef ... size_t; <stddef.h> *
int errno; usys/URT * (see USYS.DOC)
char *strerror(errnum); STRERR E T20,10X
void perror(s); stdio/PERROR E T20,10X
int sys_nerr; STRERR *
char *sys_errlist[]; STRERR *
constant EDOM; <errno.h> *
constant ERANGE; <errno.h> *
__DATE__ in KCC *
__FILE__ in KCC *
__LINE__ in KCC *
__TIME__ in KCC *
__STDC__ NOT YET (in KCC)
va_alist,va_dcl <varargs.h> * KCC Non-ANSI form
va_list,va_start,va_arg,va_end <varargs.h> * KCC Non-ANSI form
va_list,va_start,va_arg,va_end <stdarg.h> * KCC ANSI form
Notes:
All CARM facilities are supported, but __STDC__ is not defined
and will not be until KCC can provide full ANSI support. This of course
must wait until the ANSI draft standard becomes more concrete.
The standard set of UN*X error codes are provided, in particular
EDOM and ERANGE. All others apply only to failing UN*X system call
simulations.
Both <vararg.h> and <stdarg.h> are provided. Since they are
incompatible, they cannot be used together and only one of them
can be included by any particular program.
Section 14: Character Processing (V1: Sec 11.1) Src: <ctype.h>, lib/ctype.c
Name Module Port Comments
int isalnum(c); CTYPE *
int isalpha(c); CTYPE *
int isascii(i); CTYPE * CARM/BSD
int iscntrl(c); CTYPE *
int iscsym(c); CTYPE * CARM only
int iscsymf(c); CTYPE * CARM only
int isdigit(c); CTYPE *
int isodigit(c); CTYPE * CARM only
int isxdigit(c); CTYPE *
int isgraph(c); CTYPE *
int isprint(c); CTYPE *
int ispunct(c); CTYPE * DIFFERENT (no space!) CARM goofed.
int islower(c); CTYPE *
int isupper(c); CTYPE *
int isspace(c); CTYPE *
int iswhite(c); - - rare variant of isspace, not provided.
int toascii(i); CTYPE * CARM/BSD
int toint(c); CTYPE * CARM only
int tolower(c); CTYPE * allows any case
int toupper(c); CTYPE * allows any case
int _tolower(c); CTYPE * CARM only
int _toupper(c); CTYPE * CARM only
Tests: LIB/TEST/TCTYPE.C tests all these functions.
Notes:
All CARM facilities are supported; <ctype.h> must be included.
All work with any unsigned 9-bit character value and EOF; most are
macros and very fast. None evaluate their argument more than once.
The ispunct() function differs from the CARM description,
which claims that "space" is included in the set. Neither the BSD nor
the ANSI draft version of ispunct() does this however, so we have
assumed that H&S made a mistake here, and the KCC version excludes
"space".
BSD's implementation of tolower and toupper is incorrect
(corresponds to _tolower and _toupper). KCC's corresponds to CARM.
Implementation notes:
The flag table is large enough that any unsigned 9-bit char
value can be safely used as index. On the PDP-10 the table is an
integer array for speed, and is fully portable, but the macro
_CT_TABTYPE can be defined during installation if a char array is
preferable. <ctype.h> defines all of the macros. CTYPE.C defines the
_ctyp1 and _ctyp2 tables, plus some small auxiliary routines that the
macros may call.
Section 15: String Processing (V1: Sec 11.2) Src: <string.h>, lib/
Name Module Port Comments
char *strcat(s1,s2); STRING *
char *strncat(s1,s2,n); STRING *
int strcmp(s1,s2); STRING *
int strncmp(s1,s2,n); STRING *
char *strcpy(s1,s2); STRING *
char *strncpy(s1,s2,n); STRING *
int strlen(s); STRING *
char *strchr(s,c); STRING *
char *index(s,c); STRING * synonym for "strchr"
int strpos(s,c); STRING * CARM only
char *strrchr(s,c); STRING *
char *rindex(s,c); STRING * synonym for "strrchr"
int strrpos(s,c); STRING * CARM only
int strspn(s,set); STRING *
int strcspn(s,set); STRING *
char *strpbrk(s,set); STRING *
char *strrpbrk(s,set); STRING * CARM only
char *strstr(src, sub); STRING * CARM/ANSI only
char *strtok(str, set); STRING * ANSI/BSD/S5/CARM (not V7)
double strtod(str, ptr); ATOI *
long strtol(str,ptr,base); ATOI *
unsigned long strtoul(str,p,b); ATOI *
double atof(str); ATOI *
int atoi(str); ATOI *
long atol(str); ATOI *
Additional non-CARM functions:
Non-case-sensitive versions of the above functions are
provided by the STRUNG module, declared in <strung.h>:
int strCMP(s1, s2); STRUNG *
int strnCMP(s1, s2, n); STRUNG *
char *strCHR(s, c); STRUNG *
char *strSTR(src, sub); STRUNG *
Tests: LIB/TEST/TSTRIN.C partially tests these functions.
Notes:
All CARM facilities are supported. <string.h> must be
included. <strings.h> also exists for BSD compatibility; it merely
includes <string.h>.
Implementation notes:
This stuff can use more conditionalizing in order to optimize for
specific configurations. The routines are portable, but are coded to
encourage use of the PDP-10 ILDB/IDPB instructions (opposite of the optimal
PDP-11 order!)
Section 16: Memory Functions Src: lib/
Name Module Port Comments
char *memchr(ptr,val,len); MEMSTR E * ANSI/BSD/CARM/S5
int memcmp(ptr1,ptr2,len); MEMSTR E * ANSI/BSD/CARM/S5
int bcmp(ptr1,ptr2,len); MEMSTR E * BSD/CARM (calls memcmp)
char *memcpy(dest,src,len); MEMSTR E * ANSI/BSD/CARM/S5
char *memccpy(dest,src,c,len); MEMSTR E * BSD/CARM/S5
void *memmove(dest,src,len); MEMSTR E * ANSI/ CARM (needs optimiz)
char *bcopy(src,dest,len); MEMSTR E * BSD/CARM (calls memcpy)
char *memset(ptr,val,len); MEMSTR E * ANSI/BSD/CARM/S5
void bzero(ptr,len); MEMSTR E * BSD/CARM (calls memset)
Tests: LIB/TEST/TBCOPY.C tests bcopy() and bzero().
Notes:
All CARM facilities are supported. The header file for
declaring these routines is <string.h> as per ANSI, but <memory.h>
also exists for BSD compatibility.
These are guaranteed to work for all valid KCC byte sizes,
i.e. any of 6, 7, 8, 9, and 18-bit bytes. Remember that the
arguments must be of type (char *), rather than (int *). Both
memcpy() and memset() have special optimization built into them so
that they are very fast for large amounts of data. memmove() is much
slower.
Section 17: Input/Output Facilities (V1: Sec 11.5) Src: lib/stdio/
Name Module Port Comments
constant EOF; <stdio.h> *
struct FILE; <stdio.h> *
FILE *fopen(path,typ); FOPEN * See notes on next page.
int fclose(fp); FCLOSE *
int fflush(fp); FFLUSH * also works on input streams
FILE *freopen(path,typ,fp); FREOPE *
int setvbuf(fp,buf,type,size); SETBUF *
void setbuf(fp,buf); SETBUF *
FILE *stdin; <stdio.h> (m) *
FILE *stdout; <stdio.h> (m) *
FILE *stderr; <stdio.h> (m) *
int fseek(fp,off,typ); FSEEK *
long ftell(fp); FTELL *
void rewind(fp); REWIND *
int fgetc(fp); FGETC *
int getc(fp); <stdio.h> (m) *
int getchar(); <stdio.h> (m) *
int ungetc(c,fp); UNGETC *
char *fgets(s,n,fp); FGETS *
char *gets(s); GETS *
int fscanf(fp,fmt,ptrs); SCANF *
int scanf(fmt,ptrs); SCANF *
int sscanf(s,fmt,ptrs); SCANF *
int fputc(c,fp); FPUTC *
int putc(c,fp); <stdio.h> (m) *
int putchar(c); <stdio.h> (m) *
int fputs(s,fp); FPUTS *
int puts(s); PUTS *
int fprintf(fp,fmt,args); PRINTF *
int printf(fmt,args); PRINTF *
int sprintf(s,fmt,args); PRINTF *
int vfprintf(fp,fmt,arg); PRINTF *
int vprintf(fmt,arg); PRINTF *
int vsprintf(s,fmt,arg); PRINTF *
int fread(ptr,siz,cnt,fp); FREAD *
int fwrite(ptr,siz,cnt,fp); FWRITE *
int feof(fp); <stdio.h> (m) *
int ferror(fp); <stdio.h> (m) *
void clearerr(fp); <stdio.h> (m) *
int remove(filename); REMOVE * just calls unlink()
int rename(oldnam,newnam); RENAME * null file, uses USYS rename().
FILE *tmpfile(); TMPFIL *
char *tmpnam(buf); TMPNAM E T20,10X
char *mktemp(buf); MKTEMP E T20,10X uses HPTIM%, not getpid
These functions were recently added to the ANSI C draft (not yet implemented):
int fgetpos(FILE *stream, fpos_t *pos); ??
int fsetpos(FILE *stream, const fpos_t *pos); ??
Additional STDIO functions for V7/BSD compatibility:
constant BUFSIZ; <stdio.h> * V7/BSD
constant NULL; <stdio.h> * V7/BSD
FILE *fdopen(fd,type); FDOPEN * V7/BSD open w/existing FD
int fileno(fp); <stdio.h> (m) * V7/BSD
int getw(fp); GETW * V7/BSD Get word (int)
int putw(w,fp); PUTW * V7/BSD Put word (int)
void setbuffer(fp,buf,size); SETBUF * BSD
void setlinebuf(fp); SETBUF * BSD do linebuffering
Additional KCC functions:
FILE *sopen(s,type); SOPEN * (KCC only) open string for I/O
Internal globals, not for user consumption:
FILE _sios[]; <stdio.h> * internal array
void _cleanup(); CLEANU * called by exit() for cleanup
Tests: LIB/TEST/TFSEEK.C, TFTEL1.C, TFTEL2.C - tests fseek/ftell
LIB/TEST/TPRINT.C - tests printf.
Notes for Section 17 (STDIO):
See <.LIB.STDIO>-READ-.-THIS- for implementation-specific details.
Note that some facilities, in particular putc and getc, are
implemented as macros.
In general, the sequence CR-LF is converted to LF on 7-bit
input, and LF converted to CR-LF on 7-bit output. This conversion is
performed by the system call read/write functions and not by STDIO,
however. See the notes on fopen() below for details.
[17.2] (V1 11.5.7) fflush():
This should normally only be called on an output stream;
however, if called on an input stream, fflush() flushes any buffered
but unread data. This feature is probably not portable.
[17.2] (V1 11.5.10, 11.5.15) fopen(), freopen():
These implement all the H&S type specification characters,
with certain defaults and settings appropriate for the PDP-10 world:
String Mode Start Description
"r", "rb" R 0 Open existing file for reading. Error if not found.
"w", "wb" W 0 Create a new file for writing.
"a", "ab" W EOF Append to existing file (create new if necessary).
"r+","r+b" R/W 0 Open existing file for updating. Error if not found.
"w+","w+b" R/W 0 Create a new file for updating.
"a+","a+b" R/W EOF Append to existing file (create new if necessary).
Note that on TOPS-20 and TENEX, files have version numbers, and
writing a file never truncates an existing one; "w" and "w+" always create
new versions.
A stream can be either "text" or "binary", as per the ANSI
draft description; a "b" in the string specifies binary. The
characteristics of the two types of streams are:
Bytesize(old) Bytesize(new) LF-conversion
TEXT <file's> or 7 7 yes if size 7
BINARY <file's> or 9 9 no, never
When an OLD, existing file is opened (for reading, appending,
or updating), normally the bytesize of the file is used as the
bytesize of the stream. If the file bytesize is 7, 8, or 9 then that
size is used. If the file bytesize is 0 or 36 then the default (7 or
9) is used instead. If the file bytesize is anything other than
0, 7, 8, 9, or 36 then the behavior is undefined.
When a NEW file is created, its bytesize will be that of the
stream, which is normally 7 for text, 9 for binary. Note that older
versions of a file may have a different bytesize -- the notion of
checking these to set the bytesize was considered, but rejected in the
interest of simplicity.
Whether LF conversion is performed on the stream is a little
simpler. A text stream is only converted if the stream bytesize is 7;
otherwise conversion does NOT happen. A binary stream is never
converted, regardless of the bytesize.
The user can override either the bytesize or the conversion
by adding explicit specification characters, which should come after
any regular specification characters:
"C" Force LF-conversion.
"C-" Force NO LF-conversion.
"7" Force 7-bit bytesize.
"8" Force 8-bit bytesize.
"9" Force 9-bit bytesize.
"T" Open for thawed access (TOPS-10/TENEX only)
These are KCC-specific however, and are not portable to other
systems. Note that the actual LF conversion is done by the USYS (Unix
simulation) level calls (read() and write()) rather than STDIO.
[17.5] fseek(), ftell(), rewind():
For binary streams (no LF conversion), the I/O pointer value
returned by ftell() and used in fseek() is the same as the USYS (and
T20) pointer value; arithmetic can be done on this pointer to derive
new pointers as arguments to fseek(). However, for text streams when
LF conversion is being done, the I/O pointer value is a composite which
cannot be manipulated; the argument to fseek() can only be 0 or a
value previously returned by ftell() for that stream. This corresponds
to the restrictions described in H&S.
fseek() does not yet work for "+" text streams (i.e.
LF-converted streams open for both reading and writing).
[17.6] (V1 11.5.34) ungetc():
The number of characters that can be pushed back with ungetc is
a site-dependent option available at library compile-time. _SIO_NPBC
in STDIO.H defaults to 1.
[17.8] (V1 11.5.16, 11.5.28, 11.5.30) fscanf(), scanf(), sscanf():
Common sense was used in implementing the various conversion
routines when there was doubt about CARM's description:
For numeric conversions ('d', 'u', 'o', 'x', 'f'), there must
be at least one digit present for the parse to succeed, despite CARM's
claim that "some number" of digits, "possibly none" are allowed. For
string scanners ('s' and '['), at least one character must be read.
[17.11] (V1 11.5.11, 11.5.23, 11.5.29) printf(), fprintf(), sprintf():
An additional facility has been provided for the user to
assign his own conversion specification character to arbitrary
functions. This function is "prf_bind()" in module PRINTF, which should
be seen for details. Unfortunately this is not portable.
[17.13] (V1 11.5.14,11.5.19) fread(), fwrite():
These are implemented assuming that the input stream is open
in 9-bit binary mode, such that all 36 bits of an int can be read with
four successive bytes. No byte-size or mode checking is done, so it
is the user's responsibility to make sure the stream is open
correctly.
[17.16] tmpfile(), tmpnam(), mktemp():
On TOPS-20/TENEX these are implemented using a time value from
the system rather than getpid() due to the difficulty of ensuring that
getpid() is unique. This may change.
Additional STDIO routines from 4.2BSD:
See a BSD UPM section 3S for details on those routines. Some
of them existed in V7 as well, such as fdopen(), fileno(), getw(), putw(),
and setbuf().
Additional STDIO routines (KCC specific, not portable):
sopen(): opens a string as a source or destination for I/O.
The first arg is a string pointer, second is a standard fopen type
specification. The implementation of this is not yet complete: only
"r" and "w" are implemented. "a" (append) mode does NOT do the
obvious thing; place has been kept for "w+" to automatically expand
the given string if the end is reached (assuming it was allocated by
malloc). If a NULL string pointer is given, a string buffer is
allocated starting at max_size characters. The file pointer cannot be
repositioned (e.g. a string can be scanned only once). These things
may be finished some day.
Section 18: Storage Allocation (V1: Sec 11.4) Src: lib/
Name Module Port Comments
char *malloc(size); MALLOC *
char *calloc(cnt,siz); MALLOC * (calls malloc)
char *mlalloc(lsize); MALLOC * CARM only. (calls malloc)
char *clalloc(lcnt,lsize); MALLOC * CARM only. (calls malloc)
void free(ptr); MALLOC *
void cfree(ptr); MALLOC * Not in ANSI. (calls free)
char *realloc(ptr,size); MALLOC *
char *relalloc(ptr,size); MALLOC * CARM only. (calls realloc)
--------------------
Additional non-CARM functions:
These are temporary only and their use in new code is not
advisable; they will probably go away soon.
int _palloc(n); allocate n pages of memory
void _pfree(page); free allocated pages
Tests: LIB/TEST/TMALL1.C, TMALL2.C
Notes:
All CARM facilities supported. <stdlib.h> can be included.
Since "long" is the same size as "int" for KCC, the long and int forms
of calls are functionally identical. For portability the "long" forms
should not be used.
Note that in ANSI these facilities can be declared with
<stdlib.h>, but in non-ANSI implementations there is no associated
header file. You should either include <stdlib.h>, or you should be
VERY careful about pre-declaring these functions properly, and be SURE
that routines which expect a char pointer argument are given one.
A common mistake is failing to declare malloc(), so that the
compiler is unaware of the proper conversions that must be applied to
the return value (which is a PDP-10 byte pointer). This sort of type
mismatch error can go undetected on some machines but will cause you
all kinds of mysterious grief on the PDP-10.
Using brk() and sbrk() is not prohibited, but doing so is
guaranteed to confuse the storage allocator and cause problems if you
also use malloc() and friends.
The KCC functions conform to the ANSI/CARM descriptions of how
they should behave, particularly when given strange arguments like
NULL pointers. This is different from the behavior on BSD, where a
zero size will still return something from malloc and realloc (rather
than ignoring and freeing).
[18.1] (V1 11.4.1,11.4.3,11.4.5,11.4.6) calloc(),clalloc(),malloc(),mlalloc():
clalloc() == calloc() on the PDP-10. These will return NULL
if either argument is zero (as per ANSI).
mlalloc() == malloc() on the PDP-10. These also return NULL
if given a zero argument (as per ANSI).
[18.2] (V1 11.4.2, 11.4.4) free(), cfree():
cfree() == free() on the PDP-10. CARM claims that for
maximum portability it is best to use cfree() only to deallocate
memory allocated by calloc(), and free() only to deallocate memory
allocated by malloc(). However, the ANSI draft has flushed cfree()
altogether.
free() does nothing if given a NULL argument (as per ANSI).
If given a bad pointer, free() calls abort() after sending the following
message to stderr:
"free(): tried to free invalid block"
[18.3] (V1 11.4.7, 11.4.8) realloc(), relalloc():
relalloc() == realloc() on the PDP-10. These behave as per
ANSI for unusual arguments: if the pointer is NULL, it acts like
malloc(); if the size is zero, it acts like free() and returns NULL.
If given a bad pointer, realloc() calls abort() after sending the
following message to stderr:
"realloc(): tried to reallocate invalid block".
Section 19: Mathematical Functions (V1: Sec 11.3) Src: lib/math/
Name Module Port Comments
int abs(x); ABS * PRIMITIVE: C code
double fabs(x); FABS * PRIMITIVE: C code
long labs(x); LABS * PRIMITIVE: C code
div_t div(n,d); DIV E * PRIMITIVE: C or PDP10 code
ldiv_t ldiv(n,d); DIV E * PRIMITIVE: C or PDP10 code
double ceil(x); CEIL * based on modf()
double floor(x); FLOOR * based on modf()
double fmod(x,y); FMOD * based on modf()
double exp(x); EXP *10 PRIMITIVE: uses _sign,fabs,modf,ldexp
double log(x); LOG *10 based on _xexp, _xmant, _poly
double log10(x); LOG10 * based on log()
double frexp(x,nptr); FREXP *10 PRIMITIVE: MACH DEP C code!
double ldexp(x,n); LDEXP *10 PRIMITIVE: MACH DEP C code!
double modf(x,nptr); MODF E *10 PRIMITIVE: MACH DEP asm code!
double pow(x,y); POW * based on exp(), log(), modf()
double sqrt(x); SQRT * based on _xexp(), _xmant(), ldexp()
int rand(); RAND E *10 PRIMITIVE: mach dep C code
srand(seed); RAND E *10 PRIMITIVE: C code
double cos(x); COS *10 PRIMITIVE: uses fmod,sin,sqrt,_poly
double sin(x); SIN *10 PRIMITIVE: uses fmod,cos,sqrt,_poly
double tan(x); TAN * based on sin(), cos()
double acos(x); ACOS * based on atan()
double asin(x); ASIN * based on atan()
double atan(x); ATAN *10 PRIMITIVE: uses _sign, _poly
double atan2(y,x); ATAN2 * based on atan()
double cosh(x); COSH * based on exp()
double sinh(x); SINH * based on exp()
double tanh(x); TANH * based on exp()
--------------------
Additional support routines, NOT IN CARM:
These exist only to support the above routines and should not
be used by user code.
double _sign(x, y); SIGN * PRIMITIVE: C code
double _poly(x, y, z); POLY * PRIMITIVE: C code
int _xexp(x); XEXP *10 PRIMITIVE: MACH DEP C code!
double _xmant(x); XMANT *10 PRIMITIVE: MACH DEP C code!
Tests: LIB/TEST/TMATH.C
(Why don't we have good precision for atan()?? E-9 only)
Notes:
All CARM facilities are supported. <math.h> must be included.
These are mostly derived from the Portable Math Library written by
Fred Fish.
[19.8] (V1 11.3.25) tan():
According to CARM, "If the argument is so close to an odd
multiple of pi/2 that the correct result value is too large to be
represented, then the largest representable positive floating-point
number is returned and the error code ERANGE is stored into the
external variable errno". The actual error check done is to see if
for tan(x), cos(x) == 0. If so, the error behavior above is done.
[19.9] (V1 11.3.5) atan2():
For atan2(0, 0), the value 0 is returned and errno set to EDOM.
[19.10] (V1 11.3.22) sinh():
sinh() of a negative argument that is too large returns the
largest representable negative float-point number.
Other notes:
ANSI and CARM have the same functions. There are a few
differences about domain/range error specifications which are minor.
The BIG incompatibility is:
ANSI modf() is incompatible with CARM and BSD, because
the 2nd arg is (double *) instead of (int *)!!!
The functions abs, labs, rand, and srand are declared in <stdlib.h> by
ANSI, in <math.h> by CARM.
BSD appears to have all CARM functions except labs() and fmod().
BSD has these functions which are not in ANSI or CARM:
(all return double unless otherwise indicated)
Documented in UPM: gamma, hypot, cabs, j0, h1, jn, y0, y1, yn
Undocumented: asinh, acosh, atanh, erf, erfc, expm1, log1p
rint, lgamma, copysign, drem, logb, scalb, cbrt
finite (returns int), infnan (VAX only)
Section 20: Time and Date Functions Src: lib/, lib/usys/
Name Module Port Comments
clock_t clock(); CLOCK E *10
clock_t <time.h> *
CLK_TCK <time.h> *
struct tms <sys/times.h> *
void times(tmsbuf); USYS/TIMES * (see USYS.DOC)
time_t time(tptr); USYS/TIME E *10 (see USYS.DOC)
time_t <time.h> *
char *asctime(ts); CTIME E *10
char *ctime(timptr); CTIME E *10
struct tm *gmtime(t); CTIME E *10
struct tm *localtime(t); CTIME E *10
time_t mktime(tmptr); CTIME E *10
double difftime(t1,t0); CTIME E *10
--------------------
Additional non-CARM functions:
char *timezone(mwest, dstt); CTIME E *10 For BSD/V7 compatibility (!S5)
typedef ... tadl_t; <sys/time.h> E *10 Type for local TAD value
tadl_t tadl_get(); USYS/TIME E *10 Get current local TAD value
tadl_t tadl_to_utime(time); USYS/TIME E *10 Convert time_t to tadl_t
time_t tadl_from_utime(tadl); USYS/TIME E *10 Convert tadl_t to time_t
Internal globals, not for user consumption:
struct tm *_lbrktime(); CTIME E ITS,T10,WAITS For use by USYS/TIME
int _tmisdst(); CTIME E ITS,T10,WAITS For use by USYS/TIME
The latest ANSI C draft also includes this function (not implemented yet):
size_t strftime(char *s, size_t maxsize, const char *format); ??
Tests: LIB/TEST/TTIME.C
Notes:
All CARM facilities are supported.
For additional time functions, see the TMX(3X) section.
[20.1] clock(), times():
CLK_TCK is uniformly 1000 (i.e. runtime is in milliseconds). The
BSD times() call is supported, although only crudely; it does not return
its children's runtime. It could if this was needed.
[20.2] time_t, time():
The type of time_t is "int". The value is the same as that
for a standard UN*X implementation, i.e. the number of seconds since
1/1/1970 GMT. This is NOT a TOPS-20 or TENEX GTAD format time and date.
If you wish to manipulate time-and-date (TAD) values of the local operating
system, use the (non-standard) tadl_t facilities.
Section 21: Control Functions Src: lib/, lib/usys/
Name Module Port Comments
macro assert(); <assert.h> *
int system(cmd); SYSTEM E T20,10X (partial implem)
int exec*(); USYS/FORKEX E T20,10X (partial implem)
void exit(status); USYS/URT E T20,10X
void _exit(status); USYS/URT E T20,10X
void abort(); ABORT *10
typedef ... jmp_buf[]; <setjmp.h> E *10 KCC specific
int setjmp(env); SETJMP E *10 KCC specific
void longjmp(env,status); SETJMP E *10 KCC specific
typedef ... onexit_t; <stdlib.h> *
onexit_t onexit(func); ONEXIT *
constant SIG_IGN; <signal.h> *
constant SIG_DFL; <signal.h> *
constant SIG_ERR; <signal.h> *
constant SIGxxx; <signal.h> *
void (*signal(sig,func)); USYS/SIGNAL * See USYS.DOC
int raise(sig); USYS/SIGVEC E T20,10X See USYS.DOC
int kill(pid,sig); USYS/SIGVEC E T20,10X See USYS.DOC
int (*ssignal(softsig,func))(); SSIGNA *
int gsignal(softsig); SSIGNA *
void psignal(sig,prefix); PSIGNA *
void sleep(secs); USYS/SLEEP E *10 See USYS.DOC
unsigned alarm(secs); USYS/ALARM E T20 See USYS.DOC
--------------------
Additional functions:
int _setjmp(env); SETJMP E *10 For BSD compatibility
int _longjmp(env,val); SETJMP E *10 For BSD compatibility
void longjmperror(); SETJMP E *10 For BSD compatibility
int forkexec(); USYS/FORKEX E T20,10X Combines fork & exec!
The latest ANSI C draft has replaced onexit() with:
int atexit(void(*func)(void))
Notes:
All CARM facilities exist, although some may not be as
completely supported as for a real UN*X system.
[21.2] exec(), system():
The various forms of exec() all exist, but none of them do
anything with the "envp" environment pointer. For the very common
situation where a fork() is followed by an exec(), the forkexec() call
should be used instead; it is MUCH faster.
system() is not a full implementation. On TOPS-20 the command
string is parsed assuming that the first word is a system program
name, which is then invoked (using forkexec()) with the full
string as an RSCAN% argument. Unfortunately there is no convenient way
to feed input directly into an inferior EXEC. This call could be changed
to use a PTY, but this would be much slower.
[21.3] abort(), exit():
abort() does no cleanup actions whatsoever. It simply
attempts to execute a zero instruction, which generates an illegal
instruction fault on the PDP-10. This can be ignored by the signal
handler, but if so then the program will loop indefinitely; abort()
NEVER returns to its caller.
exit() cleans up by calling all functions registered with onexit().
The STDIO buffers are the last thing cleaned up.
[21.4] setjmp(), longjmp():
In addition to the above, KCC also implements the BSD
facilities of _setjmp(), _longjmp(), and longjmperror(). A checksum
is stored in jmp_buf, and longjmp() checks this as well as
other things; if anything looks bad, it calls longjmperror().
longjmperror() can be defined by the user (the default routine
simply prints "longjmp botch"). If it returns, abort() is called.
[21.5] onexit():
Up to 32 functions can be registered, as per CARM.
[21.6] signal(), raise(), kill(), gsignal(), ssignal(), psignal():
The implementation of signals is more complete than you might
expect.
The software signal functions gsignal() and ssignal() operate as
described in CARM, as does the signal description function psignal().
Note that psignal() outputs to the STDIO stream "stderr" rather than the
UN*X file descriptor 2.
raise(sig) is implemented simply as kill(getpid(),sig).
The signal() and kill() functions are "UN*X system calls" and
as such are treated specially. What KCC actually implements corresponds
to the 4.3BSD signal handling mechanism, using the sigvec() call and
a signal block mask. The main difference from standard UN*X is that
when a signal is caught, its handler is NOT reset to SIG_DFL; also,
most system calls are resumed rather than forced to fail with EINTR.
For a fuller description the file SIGNAL.DOC should be consulted.
[21.7] sleep(), alarm():
alarm() is implemented as described in CARM. On TOPS-20 this uses
the TIMER% jsys. A signal handler for SIGALRM must be defined before the
first call to alarm(), otherwise nothing will happen.
The TOPS-20 implementation of sleep() uses a timer separate from
that of alarm(). If any signal is handled, sleep() will return immediately
with errno set to EINTR; it does not return any value.
Section 22: Miscellaneous Functions Src: lib/
Name Module Port Comments
int main(argc,argv); * * User program!
char *ctermid(s); CTERMI E T20
char *cuserid(s); CTERMI E T20
char *getcwd(buf,size); GETCWD E T20
char *getwd(path); GETCWD E T20
char *getenv(name); GETENV E T20 Note 10X does not have LNMST%.
char *getlogin(); GETLOG E T20
int getopt(argc,argv,optstr); GETOPT * Note other externals defined!
int putenv(namval); GETENV E T20
char *bsearch(ky,bs,ct,sz,cmp); BSEARC *
void qsort(base,cnt,siz,cmp); QSORT * GNU version
--------------------
The latest ANSI C draft has added a new function and new header file:
<locale.h>
char *setlocale(int category, char *locale);
Notes:
All CARM functions are supported insofar as possible.
[22.1] main():
The runtime startup provides main() with argc and argv, as
parsed from the command line (on TOPS-20 this is the RSCAN% buffer).
However, it does NOT provide "env" or "environ".
[22.2] ctermid(), cuserid():
These are System V functions and are not present in BSD or ANSI.
KCC implements them as per the CARM description.
[22.3] getcwd(), getcd():
Implemented as per description.
[22.4] getenv(), getlogin(), getopt(), putenv():
CARM goofed by only describing getenv().
KCC implements all of these, but the environment variables need further
explanation.
[22.5] bsearch():
This is a new function in ANSI.
[22.6] qsort():
KCC uses the GNU (Free Software Foundation) implementation of
this function.
Section BSD(3N): UPM(3N) BSD network functions Src: lib/network/
Name Module Port Comments
struct hostent; <netdb.h> Defs for following
struct hostent *gethostent(); GETHST - not yet done
struct hostent *gethostbyaddr(adr,l,t); GETHST E T20,10X
struct hostent *gethostbyname(nam); GETHST E T20,10X
void sethostent(flg); GETHST - not yet
void endhostent(); GETHST - not yet
Section TRM(3X): TERMCAP functions Src: <trmcap.h>, lib/trmcap.c
Name Module Port Comments
int tgetent(bp,name); TRMCAP *
int tgetnum(id); TRMCAP *
int tgetflag(id); TRMCAP *
char *tgetstr(id, area); TRMCAP *
char *tgoto(cm, destcol, destline); TRMCAP *
int tputs(cp, affcnt, outc); TRMCAP *
Tests: Compile lib/trmcap.c with -DTEST to generate a test program.
Notes:
This should be a full TERMCAP emulation. The code is derived from
that of Gnuemacs (of the Free Software Foundation).
The functions are kept in a library separate from the normal C
library; to use them, the program must #include <trmcap.h> and the
"-ltrm" switch must be given on the KCC command line.
The terminal database file on TOPS-20 is kept in C:TRMCAP.DAT.
Programs using these functions must include declarations
of the following variables, which TERMCAP expects to use:
char PC;
char *BC;
char *UP;
short ospeed;
Section TMX(3X): Time and Date Functions (Extended) Src: <timex.h>, lib/
Name Module Port Comments
struct tmx <timex.h> * includes <time.h>
struct tmz <timex.h> *
int time_parse(str, tmx, endptr); TIMEPA *
time_t time_make(tmx); TIMEMK *
int time_lzone(tmz); TIMEZN E *
int time_tzset(); TIMEZN E *
Notes:
Documentation is in the file C:LIBTMX.DOC. These functions
were written by Ken Harrenstien and are distributed in a quasi-public
fashion, similar to GNU software. They are not supported by any
specific C implementation but because the code is available and is
portable to any reasonable system, it should be safe to write code
using these functions.
These functions are kept in a library separate from the normal C
library; to use them, the program must #include <timex.h> and the "-ltmx"
switch must be given on the KCC command line.
Section KCC-1: KCC-specific general-purpose functions Src: lib/
Name Module Port Comments
<lots> <jsys.h> T20,10X Defines JSYS nums and arg vals
jsys JSYS E T20,10X Support for T20/10X syscalls
regex* <regex.h> ? GNU version.
regex* REGEX * GNU version.
Not used, problems with overly
long variable names. Foo.
syscal <sysits.h> ITS Defines ITS system-call macro.
_scall SYSCAL E ITS C support for ITS syscalls
int muuo(ins,d,e); MUUO T10,WAITS Execute MUUO
int calli(n,ac,ret); MUUO T10,WAITS Execute CALLI
Notes on jsys():
The jsys() function has been provided for ease in performing
simple TOPS-20/TENEX monitor calls without being forced to resort to asm().
The calling convention is:
#include <jsys.h>
int jsys(num, acs);
int num, acs[5];
The jsys number is given in "num", and registers 1 through 4 are given
and returned in the "acs" array. Offsets in acs correspond to machine
registers; thus acs[1] goes into AC1 before the call and then takes
the value of AC1 after the call. acs[0] is not used unless the call fails.
The include file <jsys.h> defines all JSYS names, including
certain flags which tell the jsys() routine what behavior to expect from
that JSYS. This information allows jsys() to present completely regular
behavior to the C user, regardless of which JSYS is invoked.
jsys() returns:
== 0 if it failed. The JSYS error code is returned in acs[0].
If something was wrong with the arguments to jsys() itself,
so that no JSYS was done, the error code will be 0.
< 0 if it was interrupted.
This is only possible if the JSYS_OKINT flag was
OR'd into "num" for the call. The return value will be
-2 if the interrupt happened before the JSYS was invoked,
and -1 if it actually interrupted the JSYS.
> 0 if it succeeded. The return value will be one of 1, 2, or 3
depending on whether the JSYS returned to .+1, .+2, or .+3.
Note that interruption is ONLY allowed if the JSYS_OKINT flag
is set in the "num" argument. Thus, for example, the following call
can be interrupted:
jsys(WAIT|JSYS_OKINT, acs);
but this call will NOT be interrupted:
jsys(PMAP, acs);
If the user program does direct JSYS calls itself with asm()
then the signal handling code permits these to be interrupted, and
tries to restart the JSYS when the signal handler returns, but this is
not guaranteed to work for all possible cases. The jsys() call by
contrast is always guaranteed to behave in a predictable way.
Things are not yet completely normalized for TENEX, because
the need to handle .ICILI (illegal instruction) interrupts and emulate ERJMP
complicates matters.

269
doc/kcc/libtmx.doc Executable file
View File

@@ -0,0 +1,269 @@
NAME
time_parse - parse free-format date/time string
SYNOPSIS
#include <timex.h>
int time_parse(char *str, struct tmx *tmx, char **endptr);
struct tmx {
struct tm tm; /* See ctime(3) for definition */
struct tmz tmz; /* See time_lzone(3X) for definition */
char *tmx_err; /* NULL or pointer to error message */
int tmx_flags; /* Flags for possible future uses */
};
#define TMX_NULL (-1) /* Unspecified items are given this value */
DESCRIPTION
time_parse() accepts a null-terminated date/time string,
"str", and parses it to fill out the specified TMX structure, "tmx".
If "endptr" is not null, it is always set to point to the remainder
(if any) of the string not consumed by time_parse(). The "time_make()"
function can be used to derive a UNIX time word of type "time_t" from the
resulting TMX structure.
The integer return value is used to help indicate overall
success or failure. A negative value means that the parse stopped due
to conflicting specifications or ambiguous keywords, which usually
means an error; otherwise, the value is the number of non-break tokens
successfully scanned, which may be 0. Whenever the parse did not
reach the end of the string for whatever reason, the char pointer
"tmx_err" will be non-NULL and will point to a short constant message
string describing the reason.
INPUT
"time_parse()" is intended to parse all reasonable date and/or
time formats, specifically including everything that the TOPS-20/TENEX
IDTNC JSYS will accept. The function is actually much more flexible
than this since it will tolerate most cases of arbitrarily ordered,
delimited, and duplicated items; it makes use of contextual clues to
heuristically determine the meaning of numerical tokens.
The string is parsed into tokens which are either numbers or
keywords, separated by punctuation break characters. Keywords may be
in any case and need only have enough of the word to uniquely identify
it. Whitespace serves to delimit tokens but is otherwise ignored.
The parse will stop when it encounters a keyword which cannot be
identified (unknown or ambiguous), or encounters a character that is
not one of the valid date/time punctuation chars: "()-,/:." plus space
and tab. It will also stop if the only plausible interpretation of
a token leads to a clash with already parsed values.
For maximum flexibility, the parsing is deliberately as
forgiving as possible, and will accept ANY construct as long as it can
make some sense out of it, regardless of how bizarre the string looks
to a human. It is guaranteed to correctly parse all strings which are
"well formatted", but it cannot be used to enforce a specific syntax
and its interpretation of some inherently ambiguous strings may not be
what the user expects.
The following are examples of acceptable formats (most taken
from the TOPS-20/TENEX documentation). They are shown as dates and
times; a string may have only one of these, or it may have both in
either order, and sometimes their tokens can intermingle.
Dates Times
6-Feb-76 12:34:56 or 1234:56 or 123456
Feb-6-76 12:34 or 1234
Feb 6 76 16:30 or 1630 or 4:30pm
Feb 6, 1976 1:23 or 123 or 0123
6 Feb 76 1:56AM
6.2.1976 1:56-EST or 1:56 EST or 0156AM EST
2/6/76 NOON
1976-02-06 12:00AM or 12 AM or 12-am or MIDNIGHT
Wedn Febru 6 1976 5-STD or 0500-STANDARD
1976 We Fe 6 12:30-DAYLIGHT
Combined:
Fri Nov 13 13:08:02 PDT 1981 (output of ctime())
Monday, May 24, 1987 3:22:23am-PST (03:22:23) (output of T20 daytime)
Wed 2 Dec 87 09:18:44 PST (RFC822 format)
10-Nov-52 12:34-CDT
2:25 AM, December 25, 2025
Tues-PDT,(1988)8PM..AugUS 8 Tu (free-format example)
Note that any USA timezone abbreviation is allowed, plus GMT, UT,
and whatever else has been added to the keyword table.
DIAGNOSTICS
To summarize all possible return situations:
Value tmx_err **endptr Meaning
< 0 set start of bad token Parse stopped due to clashing specs
or ambiguous keyword.
>= 0 NULL '\0' String was completely parsed.
>= 0 set start of invalid token String was not completely parsed.
(if isalpha(**endptr) is
true, this is an unknown
keyword)
Return-value:
The exact quantity expressed by a positive return
value is not useful for most purposes; it represents the number of
valid numerical or alpha (keyword) tokens that the scan parsed. This
often but not always corresponds to the number of entries in "tmx"
that were set. A zero return value always indicates that the scan
halted before finding any such valid tokens, and nothing in the "tmx"
structure was set.
tmx_err:
The "tmx_err" member of "tmx" will be NULL if the parse scanned
the entire string, otherwise it will be set. Note that the setting of
this variable, as well as the sign of the return value, does not
necessarily reflect either success or failure; it is up to the
application program to interpret the results.
endptr:
The "endptr" return value provides another way to see what
terminated the scan, since it points to the first character of
whatever token stopped it. This will be '\0' at the end of the
string, and if **endptr is an alpha character then the token was an
unidentified or ambiguous keyword.
tmx:
NOTE!! Although a "tm" structure is included in the "tmx"
structure, the values it contains are not completely consistent with
the way "tm" structures are used by the C library functions. There
are two differences:
(1) If a structure member was not specified by the date/time string,
it is given the value TMX_NULL, defined in <timex.h>, which matches
no valid value for any member. In particular the "tm.tm_yday"
member will always be set to TMX_NULL since there is no standard
convention for specifying it in a text string.
(2) The "tm.tm_year" member is set to whatever year value the
string specifies. This may be 87, or 1987, or any other number.
This conflicts with the C library interpretation where 0 is the
year 1900.
In fact, time_parse() can be used to merely initialize a
"tmx" structure, by invoking it like this:
time_parse((char *)0, &tmx, (char *)0);
The time_make() function can be used to completely
canonicalize the structure so that the "tm" substructure is then
acceptable to the standard C library functions.
It is important to remember that time_parse() does not, in
general, attempt to verify the correctness of the resulting "tmx"
structure. Cross-checking is limited primarily to ensuring that duplicate
specifications are identical, e.g. if the weekday is seen twice, it
must have the same value or the parse fails. time_make() will perform
the necessary content checking to derive a valid "time_t" time.
SEE ALSO
time_make(3X), time_lzone(3X), ctime(3), time(2)
AUTHOR
Ken Harrenstien, SRI International
<KLH@SRI-NIC.ARPA> 415/859-6552
NAME
time_make - derive a "time_t" time value from a parsed time
SYNOPSIS
#include <timex.h>
time_t time_make(struct tmx *tmx);
DESCRIPTION
"time_make" can be considered the inverse of "localtime"; it
takes a broken-down time description and returns a UNIX-format time
value of type "time_t". Note that it works only on "tmx" structures,
not "tm" structures.
It is possible to have unspecified (TMX_NULL) values in the
structure, which time_make() will attempt to default reasonably:
Member Default value if unspecified
tm.tm_year Current year.
tm.tm_mon 0 (Jan) if year specified, else current month.
tm.tm_mday 1 if month specified, else current mday.
tm.tm_hour 0
tm.tm_min 0
tm.tm_sec 0
tmz.tm_secwest tmz.tm_minwest * 60
tmz.tm_minwest local timezone
tm.tm_isdst 0 if timezone not local. If local,
applies local DST algorithm.
For example, "July 10" will default the year to its current
value (e.g. 1987), and the time to 00:00:00. Just giving "1980" will
produce "Jan 1, 1980 00:00:00".
The timezone, which is specified by tmz.tm_secwest, defaults
to tmz.tm_minwest*60 which in turn defaults to the local timezone. A
value of 1 for either variable is interpreted as an explicit request to
use the local timezone.
If tm.tm_isdst is set to 0, daylight savings time (DST) is never
applied. If set to 1 (to represent USA DST) then DST is always applied
(by subtracting one hour). If not specified, no DST is applied unless
the timezone is that of the local timezone, in which case DST is applied
if appropriate (determined by consulting localtime()).
The "tm.tm_yday" (day of year) entry is not used to compute
the time unless neither the month nor day are specified. The
"tm.tm_wday" (day of week) entry is never used. However, specifying
either of these values will cause them to be checked, and time_make()
will fail if the values conflict with the other date specifications.
DIAGNOSTICS
-1 is returned on failure, which is usually due to a parameter
being out of range. A failure return will always set "tmx_err" in the
tmx structure to point to a short constant error message. This variable
is cleared to NULL for a successful return.
SEE ALSO
time_parse(3X), time_lzone(3X), ctime(3), time(2)
AUTHOR
Ken Harrenstien, SRI International
<KLH@SRI-NIC.ARPA> 415/859-6552
NAME
time_lzone - get local timezone information
time_tzset - set local timezone information from system
SYNOPSIS
#include <timex.h>
int time_lzone(struct tmz *tmz);
int time_tzset(void);
struct tmz {
long tmz_secwest; /* Secs west of GMT (-12/+12 hrs) */
int tmz_minwest; /* Same, in mins. (tmz_secwest/60) */
int tmz_dsttype; /* DST type if any (0 = none, 1 = USA) */
char *tmz_name; /* Standard timezone name */
char *tmz_dname; /* DST timezone name (if any) */
};
DESCRIPTION
"time_lzone()" fills out the structure pointed to. It
does this by copying the contents of the static area indicated by
time_tzset(), which it calls if necessary.
"time_tzset()" attempts to get the local timezone information
from the system or environment (this is system dependent) and uses
this to set (or re-initialize) its static TMZ structure. If
successful, a pointer to this structure is returned; if it could not
be initialized, NULL is returned. It is not necessary to invoke this
function explicitly unless the program has some reason to believe that
the timezone may have changed during execution.
SEE ALSO
time_make(3X), time_parse(3X), ctime(3), time(2)
BUGS
Time zones are a big mess, especially on Unix where there are
several incompatible (and unportable) methods of tracking them.
These functions attempt to standardize the information more sensibly.
AUTHOR
Ken Harrenstien, SRI International
<KLH@SRI-NIC.ARPA> 415/859-6552

24
doc/kcc/libtrm.doc Executable file
View File

@@ -0,0 +1,24 @@
libtrm is the library for fancy terminal stuff. currently, libtrm
only contains trmcap, the package for slurping in termcap entries,
returning requested portions, creating cursor movement strings, and so
forth. for full trmcap documentation see termcap(3X); for termcap
entry documentation see termcap(5);
trmcap contains these functions:
int tgetent(bp, name); get entry for terminal name into buf bp
int tgetnum(cap); get the numeric value of capability cap
int tgetflag(cap); returns 1 if the given cap is present, else 0
char *tgetstr(cap, area); return string value for capability cap
char *tgoto(cm, h, v); return cursor addressing string to get to h,v
void tputs(string, nlines, outfun);
output string with padding. see man page.
char *tparam(string, outstring, len, arg0, arg1, arg2, arg3);
expand termcap entry into outstring
hideous global constants which trmcap defines:
short ospeed; output speed of the terminal
char PC; character to use for padding to terminal?
char *BC; pointer to "bc" capability in termcap entry
char *UP; pointer to "up" capability in termcap entry

205
doc/kcc/news.txt Executable file
View File

@@ -0,0 +1,205 @@
03/17/87 KCC 560, LIBC 124: <2,,1> Binary KCC update
A copy of CC.EXE.560 is included which fixes a number of
annoying bugs that users encountered with KCC 557. The sources are
still those for 557, however. The library is unchanged.
03/06/87 KCC 557, LIBC 124: <2,,1> Third formal distribution snapshot
IMPORTANT: this version of KCC is incompatible with previous
versions! The way that structures are returned from functions has
changed, and the layout of "char" and "short" objects in structures has
also changed. In order to enforce this, the symbol $$CVER has been
updated, and any attempt to load .REL modules which have been produced
by incompatible versions of KCC will cause LINK to complain with an
error message similar to this:
%LNKMDS Multiply-defined global symbol $$CVER
Detected in module PRINTF from file C:LIBC.REL
Defined value = 1000001, this value = 2000001
This is easily remedied by re-compiling old modules. Fortunately, no
further incompatible changes are expected to be necessary.
Nothing has really changed from the user's viewpoint. However,
there are several new features available, and some inefficiencies
corrected. The noteworthy changes are listed below, very briefly;
as usual, CC.DOC should be consulted for more complete and informative
details.
KCC: ---------------------------------------------------------------
KCC - Bug fixes:
A multitude of minor bug fixes too trivial to mention, almost
all having to do with incorrectly optimized code. One that wasn't
trivial was that {char c, *cp = &c;} used to produce an (int *)!
KCC - Incompatible changes:
* "shorts" are now 18 bits long (halfwords), with sizeof(short) == 2.
* The mechanism for returning structure values from functions
is different. This is an internal change, invisible to the user, which
is much more efficient than the previous method.
* Structure members of type "char" and "short" are now packed
differently (more compactly). Any structure using these types will be
laid out differently in storage.
* Integer narrowing and widening is now done properly in all
situations. This may cause incorrectly written code to behave
differently.
* Implicit arithmetic conversions now follow the ANSI
value-preserving rules rather than the old K&R and H&S
unsigned-preserving rules. Ambiguous code may behave differently.
* "float" values are no longer automatically converted to "double",
except for function arguments. This conforms to the ANSI draft.
* The "signed" keyword (introduced by ANSI) has been implemented.
* "volatile" and "const" (also new from ANSI) are now reserved
words (but unimplemented).
KCC - Extension: New data types:
5 new data types have been introduced, which act like "char"
but with different byte sizes. You can now manipulate signed or
unsigned bytes of 6, 7, 8, 9, or 18 bits. This is non-portable and
intended strictly for PDP-10 machine-dependent code where efficiency
is desirable.
KCC - Efficiency improvements:
The change to the structure handling mechanism falls in this
category. Structure copies used to always take two subroutine calls
and two copies; they now use a single in-line BLT (or a series of
single-word moves, whichever is best), and are much faster than
element-by-element copying.
KCC's constant initialization code has been improved to the point
where almost all constants are now initialized at load time rather than
at run time; a similar mechanism eliminates the code that used to generate
string constant pointers. You will see a significant difference with code
that uses many string literals; both startup time and program size are
reduced.
KCC's pointer arithmetic for byte pointers is MUCH better.
Pointer comparison and subtraction formerly used subroutine calls and
many, many instructions; both now use a handful of in-line
instructions and some magic numbers.
There are no more calls to internal run-time subroutines.
All of the operations which used to require this are now compiled
in-line, including double-int and int-double conversion, pointer
operations, and structure copying.
KCC - unsigned and signed data:
KCC now fully supports "unsigned int" operations. Some code
that uses unsigned integers will now compile differently. Division in
particular needs many more instructions. Any integer type, "char" in
particular, may be declared as "signed" and will behave accordingly.
KCC - Switch changes:
-L=<str> Passes <str> in the command string to the linking loader.
-v=<fs> (Verbosity) has been expanded; see CC.DOC. -v alone prints out
everything, including the loader command string.
-l Libraries loaded with the -l switch are now loaded in /SEARCH
mode (they evidently weren't before).
KCC - Miscellaneous
-d=sym now produces a *.CYM file instead of *.SYM, to avoid
conflicts with LINK output files.
-P=ansi+kcc is now the default. The effects are minor and documented
in CC.DOC. The three new ANSI keywords of "signed", "const", and "volatile"
are recognized, although only the first has any real effect.
LIBC: ---------------------------------------------------------------
More minor bug fixes to the LIBC stdio routines.
open() now attempts to track down and expand logical device
names completely (thus performing what the monitor should be doing but
isn't). Thus, open("X:subdir/filename.ext",0) will work even if X is
a search path. Previously only the first device/directory could be tried.
This permits KCC #includes to work with C: defined as a search path.
malloc() no longer allocates pages 770-777 (non-extended) or
37770-37777 (extended), so that obsolete forms of DDT can be mapped therein.
12/07/86 KCC 537, LIBC 93: <1,,1> Informal distribution snapshot
Various additional bug fixes.
There may be some stray files and other cruft as this was made just
so that Systems Concepts could get the latest stuff; some things haven't
been checked out.
10/21/86 KCC 534
Fixed a register allocation bug which got tickled by very large
floating-point expressions.
LIBC: fixed a minor scanf bug. Fixed system/vfork/exit to work properly.
09/28/86 KCC 533, LIBC 14: <1,,1> Second formal distribution snapshot
This is called a "snapshot" to emphasize that while the sources
in this distribution should be consistent and working, the compiler and
library are still under active development to remove known quirks and
deficiencies, and have already changed.
As before, all .REL files must be recompiled; the STDIO
structures are different and there are new C runtime hooks. Most
importantly, the symbol $$CVER is now defined in every module
(currently it is <1,,1>) so as to detect any future conflicts when
loading modules that were incompatibly compiled.
Various change notes follow. For all of them, see the CC.DOC
file for more details.
KCC: ---------------------------------------------------------------
KCC - Command line
There are several new switches, and the way KCC interprets
filenames is slightly different. A file with a .REL extension is
always ignored, but is passed on to the loader. A file without any
extension is special if the -q switch is given; it is only compiled if
the .C source is more recent than the .REL binary.
New switches:
-A Specify nonstandard assembler header file (old meaning of -H)
-H Specify nonstandard path for #include <> files.
-i Loader: load program to run with extended addressing.
-L Loader: nonstandard path for library files.
-l Loader: search specified library
-o Loader: specify .EXE filename.
-P Set portability level.
-q Compile extension-less files conditionally.
KCC - General
There are no real changes in code generation. A couple of
over-optimization bugs were fixed, and a couple of other optimizations
added.
KCC now generates its own assembler header based on the target
CPU, assembler, and system; the file C-HDR.FAI no longer exists.
Two more KCC extensions were added: the `ident` quoting syntax,
and the asm() in-line code mechanism. #asm and #endasm must now appear
only within a function body.
KCC identifiers are now unique up to 31 characters, as per the
ANSI draft (external symbols are still only unique up to 6).
The runtime variable $EXADF no longer exists. The decision on
whether to run extended is now made at load time, either with the -i switch
or by loading C:LIBCKX as the first module.
LIBC: --------------------------------------------------------------
LIBC - CHAR
ispunct() was "fixed" to exclude space. CARM claims space is
included, but neither ANSI nor BSD does so. We assume this is a mistake
in CARM.
LIBC - STRING
The routines memchr, memcmp, memcpy, memset were added from ANSI.
LIBC - STORAGE
free(), malloc(), and realloc() now behave as per ANSI when given
NULL or zero as arguments.
LIBC - STDIO
The "update" mode is now supported for streams. In addition
to this, the library implements the ANSI concept of text vs binary
streams. The 'R' specification was flushed; 'b', '7', '8', '9', 'C',
and "C-" were added.
LIBC - other
system() was added.
07/26/86 KCC 512, CLIB 225: First formal distribution version.
If you already had a version of KCC on your system, you will need
to recompile any .REL modules generated by the old version, because the
new KCC uses a different STDIO package. .EXE files do not need to be
recompiled.

302
doc/kcc/port.doc Executable file
View File

@@ -0,0 +1,302 @@
INSTALLING AND PORTING KCC
This file tries to document various things about porting KCC to other
systems; including how to bring up new versions on systems which already have
KCC.
A "port" involves two major things: the KCC compiler itself, and
the C library (LIBC). They are interdependent, and since the compiler is used
to compile itself, things have to be done carefully.
KCC supports all CPUs: KA, KI, KS, KL, KX. System is irrelevant.
LIBC supports only TOPS-20. There is partial (but not complete)
support for TOPS-10, WAITS, and ITS.
The usual situations are these:
(1) Installing KCC and the library for the first time.
(2) Installing a new version of the C library or KCC.
(3) Using KCC as a cross-compiler for another CPU or system.
(4) Porting KCC and the library to a different CPU or system.
Other references:
For (1) see the distribution INSTAL.DOC file.
The KCC USER.DOC section about cross-compiling.
The C library file LIBC.DOC.
Building and installing a compatible new version of KCC/LIBC for your current
system:
If the new version has exactly the same site-dependent parameters
(C-ENV.H and CCSITE.H) then you can simply install the new binary, without
bothering to recompile from the sources.
If your site-dependent parameters are different from that of the
distributed KCC then you will need to recompile from the sources. To do
this,
1. Make sure that the C-ENV.H in the KCC source directory is correct
(or, if it doesn't exist, that the version in the include directory
is correct). Ditto your CCSITE.H or whatever is different.
2. On TOPS-20, simply invoke CC.MIC, as in "DO CC". Or do it by hand.
Then install the resulting NCC.EXE on your system as "CC".
NOTE: if the new version of KCC makes some changes in its runtime
assumptions, you may need to change some other things. The most that may be
required is to follow the cross-compilation procedure as if porting to a new
system. If you know what is going on, you may be able to get by with less
than a full new installation.
Using KCC as a cross-compiler:
This assumes you want to set things up on your source system so
that you can compile programs into binaries which can then be moved to
a target system and executed there. This can sometimes be useful if the
target system is not really able to run KCC itself for whatever reason.
Also, we assume that the source system is a TOPS-20, since KCC is fully
supported for that system and the existence of logical names makes things
easier.
[1] Set up a new directory to serve as the standard include (and library)
directory for the target system's files. For the sake of the following
discussion, call this directory NC:.
[2] Install in NC: an appropriately editted copy of C-ENV.H.
In particular, CPU_xxx and SYS_xxx must be set properly.
[3] Build a program called, for example, XCC which passes its arguments on
to an invoked CC with the addition of appropriate switches.
See the program TCC.C in the KCC source directory for a sample;
this program runs on TOPS-20 and compiles code for TENEX.
The following switches should be set:
-L to specify the library directory path (NC:)
-H to specify the standard include file directory path (NC:)
-x to specify the target CPU, system, and assembler
And others such as -A if necessary.
[4] Use XCC to recompile and rebuild the entire C library. Install the
new LIBC.REL in NC:.
[5] That's it. KCC does not need to be rebuilt, since XCC will simply
invoke KCC with the appropriate switches set. Whenever making
a program to run on the target machine, just use XCC.
KCC/LIBC Cross-compilation (using logical names):
These are the complete steps to follow when building a new KCC and
LIBC for another CPU or system. You may be able to get by with doing less,
if you know what is going on and what the changes are. You may have to
do more, if the new CPU or system is not fully supported.
This procedure for cross-compiling KCC/LIBC for a different CPU/system
relies on TOPS-20 logical names, and assumes that the logical name C: is used
by the source machine's KCC to refer to both the standard include directory
and the library directory. If some other logical name is used, substitute
that for C: in the following discussion.
[0] Redefine C: to be a search path pointing FIRST to a "new" standard
directory, and SECOND to KCC's standard directory (normally
this is the system-wide logical name C:).
This requires the user to:
@define C: <new-dir>, C:
[1] Edit C:C-ENV.H for new configuration; write out to C: (new dir).
In particular make sure that the SYS_xxx and CPU_xxx defaults are set.
Make sure that any local copies of C-ENV.H (in the KCC or LIBC
source directories) are identical.
The same applies to any other .H files that need to be changed; new
versions should be put in C: (new dir) and local copies made identical
or flushed.
[2] Connect to the LIBC source directory.
Delete all .REL files (@DEL *.REL,<.*>*.REL)
[3] Rebuild entire library with the LIBC.MIC file (@DO LIBC).
Edit LIBC.MIC beforehand to add any -x= switches that are necessary,
for example -x=ki, -x=klx. These switches should match with
the definitions in C-ENV.H!!!
[4] Install new LIBC.REL into C: (@COPY LIBC.REL.0 C:*.*.*)
[5] Also install the new LIBCKX.REL file into C:. This is necessary in
order to allow loading of extended-addressing programs. If your
machine does not support extended addressing, of course, you can
ignore this file.
--- At this point the new library is ready! ---
[6] Build a new KCC:
Connect to the KCC source directory.
Make sure that the site-dependent defaults in CCSITE.H are okay.
Other parameters can be changed in CCPARM.H if necessary.
Make sure that the local copy of C-ENV.H is either flushed or
is the same as the version in the new C:.
[7] Delete all the old .REL files (@DEL *.REL).
[8] Compile and load all the C modules with the CC.MIC file (@DO CC).
Edit CC.MIC beforehand to add any -x= switches that are necessary,
for example -x=ki, -x=klx.
This will automatically load up some library routines from the new
LIBC. You now have a binary KCC for the target system.
[9] To install on your own system:
you can replace the old C: by new C: in either of two ways:
A. (quick) Copy all new C: files over to old C:
Then undefine your job-wide C:.
B. (cautious) Copy all remaining files from old C: to new C:.
Test it out. If no problems, then revise the system-wide
logical name. If problems, swap the names back.
[10] To install on another system:
On target system, set up the include directory.
Copy all files from new C: to target (.H files plus LIBC.REL),
then all remaining files from old C: to target.
Copy the new CC binary to whereever the target's system progs live.
If desired, copy the LIBC and KCC sources too.
Cross-compilation without logical names:
This is a little harder because the source and target directories have
to be more explicitly specified. In the following discussion, the strings OLD
and NEW are assumed to represent the paths for the old (existing) standard
directory, and the new directory where the new .H files and library will be
written and stored.
[1] Edit C-ENV.H for new configuration; write out to NEW.
In particular make sure that the SYS_xxx and CPU_xxx defaults are set.
Make sure that any local copies of C-ENV.H (in the KCC or LIBC
source directories) are identical.
The same applies to any other .H files that need to be changed; new
versions should be put in NEW (new dir) and local copies made identical
or flushed.
[2] Connect to the LIBC source directory.
Delete all .REL files.
[3] Rebuild entire library. The LIBC.MIC file shows which files need
to be compiled and loaded into a library.
All compilations should be of this form:
CC -c -LNEWLIB -INEW -IOLD -x=ki module.C
Where:
"-x=ki" illustrates how a specific CPU must be selected.
"module" is the library module being compiled.
"NEWLIB" is the path for library modules in NEW, e.g. -LC:LIB=.REL
The need to specify this is an unfortunate artifact of
the way library load requests are inserted into the code.
[4] Build all the .REL files together into a library; the first two
files must be CPU.REL and CRT.REL. Move this file into the NEW
directory.
--- Now start building the new KCC ---
[5] Build a new KCC:
Connect to the KCC source directory.
Make sure that the site-dependent defaults in CCSITE.H are okay.
In particular make sure that LIBPREFIX and LIBPOSTFIX match
what was given in the -LNEWLIB switch while compiling LIBC.
Other parameters can be changed in CCPARM.H if necessary.
Make sure that the local copy of C-ENV.H is either flushed or
is the same as the version in NEW.
[6] Delete all the old .REL files.
[7] Compile and load all the C modules specified by the CC.MIC file.
Use the same form as for compiling the LIBC modules, including
the -L, -I, -x, and -A switches.
You will then have a binary KCC suitable for the target system.
[8] To install on your own system:
you can replace OLD by NEW in either of two ways:
A. (quick) Copy all NEW files over to OLD. Install the KCC binary.
B. (cautious) Copy all remaining files from OLD to NEW.
Test it out. If OK, install the KCC binary.
[9] To install on another system:
On target system, set up the include directory.
Copy all files from NEW to target (.H files plus LIBC.REL),
then all remaining files from OLD to target.
Copy the new CC binary to whereever the target's system progs live.
If desired, copy the LIBC and KCC sources too.
Thoughts on future port to ITS:
Main problem is that the only linking loader available on ITS is
STINK, which only understands STINK format .REL files. There may be
an old version of the DEC linker available, but this is non-supported
and painful to use. Finally, MIDAS can produce either STINK or DECREL format;
the ITS version of FAIL can do the same. This gives us only three
possibilities, in increasing order of generality:
(1) Use ITS FAIL, producing STINK format.
(2) Make KCC produce MIDAS output. Use MIDAS, with STINK format.
(3) Make STINK understand DECREL format. Use MIDAS or FAIL.
Note that if KCC is ever improved to bypass the assembler phase by
outputting .REL files directly, it will either have to also know about
STINK format, or STINK will have to know about DECREL format. The latter
is most general.
Actual porting:
Approach 1: build a KCC elsewhere, dump in old DECSAV format. FTP over
and convert to SBLK executable format.
Approach 2: generate complete set of .FAI files and then FTP them.
Run ITS FAIL to generate STINK format rels,
then STINK them together to produce KCC and CLIB.
Approach 3: generate complete set of .MID files and FTP them.
Run MIDAS and then STINK the results together.
Approach 4: generate complete set of .REL files and FTP them.
Modify STINK to understand DECREL format, load files with STINK.
Fixing KCC to produce valid MIDAS output will require:
(1) Modifying KCC to produce common assembler subset. Can do.
(2) Modifying the syntax of all assembler runtimes. This is
the real problem. Only hope for dealing with this reasonably
is to change everything to use new #ASM feature; then KCC
can conditionalize the syntax depending on system.
Library routines required by KCC:
(this list can be generated by loading all .REL modules and then
giving the /UNDEF switch to LINK)
$$$CPU 0
$$$CRT 0 ; * C Runtime stuff, in CRT.C
$BPCNT 413166
$BYTE 517604
$DFIX 437543
$NSPOP 472623
$NSPUS 472615
$START 403165
$SUBBP 413303
$ZERO 463273
Sys-dependent routines
.CPUTM 403072 ; * All systems supported
EXIT 441516 ; *
GETPID 517376 ; * CCASMB for temp files
JSYS 517315 ; T20 - CCASMB for PRARG%
PFORK 517675 ; T20,10X - CCASMB for asm/link invoke
****> UNLINK 517225 ; T20,10X,ITS - CC to flush asm files
; Needs LOOKUP+RENAME for T10/WAITS
STDIO ; * STDIO stuff. Should not be sys-dep
.SIOS 0
FCLOSE 517443
FFLUSH 517666
FGETC 517212
FOPEN 517417
FPRINT 516663
FPUTC 515464
FPUTS 517440
FWRITE 516627
SPRINT 517407
UNGETC 412045
Stg alloc ; * Depends on S/BRK, all sys supported.
FREE 442156
MALLOC 517154
REALLO 517235
STRING ; * (no sys-dep stuff)
STRCAT 414767
STRCMP 417712
STRCPY 517371
STRLEN 517335
Misc library
QSORT 457226 ; * (no sys-dep stuff)

240
doc/kcc/signal.doc Executable file
View File

@@ -0,0 +1,240 @@
KCC UN*X SIGNAL SIMULATION
This file provides some user-oriented information on how to
use the KCC simulation of the Un*x signal mechanism.
Unfortunately, there is no single consistent signal mechanism
used by all UN*X-type systems. The currently known schemes fall into
three basic categories:
(1) Traditional: V7, SYS V, ANSI. [signal()]
(2) Better: 4.2 BSD / SUN [signal(), sigvec(), sig*()]
KCC=> (3) Best: 4.3 BSD [signal(), sigvec(), sig*()]
Attributes:
Handler reset Signal mask Calls restarted
(1) yes no no
(2) no yes no
KCC=> (3) no yes yes
Handler Reset:
In traditional Un*x implementations, the call of a signal handler
automatically resets that signal's handler to SIG_DFL (default handling,
normally termination). The handler has to do invoke signal() again if
it wishes to catch additional signals. 4.3BSD and KCC do not do this
reset.
Signal mask:
BSD introduced a signal mask which allows signals to be kept
pending until the mask no longer blocks them from being handled.
Whenever a handler is called, the corresponding bit in its mask (at
least) is always set; thus there is no need to reset the handler to
SIG_DFL. This is much more robust as there is no gap during which
quickly repeated asynchronous signals can mistakenly kill a process.
BSD added a number of new calls to handle this mask. They are
sigvec (general-purpose replacement for signal), sigsetmask, sigblock, and
sigpause. KCC implements all of these.
Call restart:
In both (1) and (2) a signal during certain system calls would
cause those calls to return -1 with errno set to EINTR. In 4.3BSD this
was changed so that normally such calls are restarted automatically when
a signal handler returns. A flag bit with sigvec() allows the old action
of EINTR to still be taken. A new call, sigreturn(), was added to permit
true context restoration. KCC implements this too.
More on system call interruption:
On Un*x signals may only interrupt the following calls:
read(), write() - slow devices only (never DSK:)
wait()
ioctl() on a slow device (esp. TTY:)
any call that locks an inode - open(), creat()?
Calls which are not restarted by 4.3BSD if interrupted:
pause(), sigpause()
KCC permits only the above USYS calls to be interrupted. For all
but pause() and sigpause(), the calls will be restarted automatically
unless specifically requested by the SV_INTERRUPT bit in a sigvec call.
Changing the signal mechanism:
To accomodate cases where it is difficult to change the user
code (e.g. during initial stages of porting some software), the signal
mechanism can be changed from 4.3BSD to 4.2BSD or V7/SYSV by including
the following code in the module where "main" is defined:
#define _URTSUD_DEFAULT_SIGS _URTSUD_xxx_SIGS
#include <urtsud.h>
where "xxx" is one of SYSV, BSD42, or BSD43.
For additional information more detailed than that provided in this
file, consult the files CODSIG.DOC and SIGVEC.C in the source directory.
KCC-supported signals:
/--------------- (A)synchronous or (S)ynchronous.
| /------------ (P)anic channel or not.
| | /--- Only seen for (J)SYS or (U)ser; * = both.
Code: [AS][P-][O-][JU*]
\------- O means if interrupt PC is user-mode, the
PC is that of the offending instruction and
not the next one (as for all other cases).
Signal PSI Code
SIGINT x A--* TTY Interrupt (interactive)
SIGQUIT x A--* TTY Quit (interactive)
SIGALRM x A--* Alarm Clock (TIMER%)
SIGCHLD .ICIFT A--* Inferior fork termination
SIGFPE .ICFOV S--U Floating Point overflow
SIGFPE .ICAOV S--U Arithmetic overflow
SIGSEGV .ICPOV SP-U PDL overflow
SIGILL .ICILI SP-* Illegal Instruction
SIGBUS .ICIRD SPO* Illegal memory read
SIGBUS .ICIWR SPO* Illegal memory write
SIGPIPE .ICDAE SPO* Device or data error
SIGXFSZ .ICQTA SPO* Quota exceeded
SIGXFSZ .ICMSE SPO* Machine resources exhausted
SIGT20EOF .ICEOF S--J EOF condition on input
SIGT20NXP .ICNXP S-O* Ref to non-ex page
If a panic signal occurs during execution of a USYS call then
the program will be halted with an error message, even if a handler is
defined for that signal. It is possible to ignore panic signals with
SIG_IGN although this is unwise.
The default action (SIG_DFL) for a particular signal varies.
As long as a signal is not set to anything, its action remains
whatever the TOPS-20 system action is; panic signals will cause the
process to be halted, and all other signals are ignored. If a signal is
explicitly set to SIG_DFL then its default action will become whatever
the Un*x default action is. See the include file <signal.h> for a listing
of all signals with their default actions.
A "core" file is never made, since this is unnecessary and unhelpful
on TOPS-20/TENEX.
Use of SIGINT and SIGQUIT:
At startup there are no interrupt characters. That is,
t_intrc and t_quitc of the "tchars" ioctl structure are both -1.
Simply setting these characters does not cause either to generate
signals unless the signal handler has been explicitly set to something
by signal(). If explicitly set to SIG_DFL then the signal will
terminate the process, since this is the default Un*x action.
These interrupt characters can only be some form of control character,
including DEL.
Signal Handlers:
When a signal handler is invoked, it is called with the following
arguments:
void sighandler(sig, chn, scp)
int sig; /* Signal # */
int chn; /* PSI channel # (T20/10X) */
struct sigcontext *scp; /* Pointer to context */
Since more than one PSI channel is mapped into a single signal, the
"chn" variable allows the handler to distinguish between them if
necessary. The signal context structure is defined in <signal.h> and
contains the complete context of the signal, including the interrupt
PC and flags, saved ACs, and old signal mask. Code which references
this structure is not portable to machines other than the PDP-10, but
at this level things are non-portable anyway.
Returning from the handler will resume the process where it was
interrupted. longjmp() to some other location will work as long as the
signal handlers are not nested.
WARNING:
Any time you write a signal handler routine, you must be aware
of what you might be interrupting and how the handler actions may
affect the rest of the program. There are too many subtleties to go
into more than a few of the important aspects here. For example,
while it should be okay to use USYS calls within the handler (the
interrupt system ensures that these are treated as atomic), it is
almost NEVER okay to invoke any library routine which alters static
data, such as "ctime". In particular, none of the storage allocation
facilities such as "malloc" should be called, because the program might
have been interrupted out of a call to malloc, and the data structures
will be in an inconsistent state. It is also risky to use any of
the standard I/O library routines, for similar reasons.
WARNING:
The signal code goes to a great deal of trouble to ensure that
if a user program JSYS is interrupted, it can be continued on return
from the handler. But the TOPS-20/TENEX PSI scheme is so complex and
messed up that it is impossible to guarantee that this will always
work. To be COMPLETELY safe, you can use the jsys() facility, which will
never permit its JSYS to be interrupted unless the JSYS_OKINT flag is
set, and even then will provide you with a definite indication that
a signal was handled.
Additional notes:
What "a/synchronous" means:
A SYNCHRONOUS interrupt is one that happens at a specific PC
due to the instruction at that location. Typical examples: illegal
instruction interrupts (which can include JSYS calls), floating-point
exceptions, and illegal memory references. For these types of
interrupts the PC is significant and it or the contents it points to
may need to be checked to determine what to do, because simply
continuing the process at that PC will very likely just generate
another such interrupt.
An ASYNCHRONOUS interrupt is one that may happen at ANY time,
regardless of place; these are generated by events external to the
program. Typical examples: TTY input interrupts, timer interrupts.
For these, the PC is unimportant except that it should be preserved
and restored if the interrupt handler wishes to continue whatever was
interrupted.
No UN*X C signal handler has the capability of returning from
handling a synchronous interrupt. In fact there is no mechanism
provided for a signal handler to find out what its return PC is.
(it's possible, with trickery, but I've never seen an example).
4.3BSD (as opposed to 4.2 or any other Un*x) now makes this possible
by providing the handler with a pointer to a saved-context structure!
Note that some signal handlers return to normal code by
means of longjmp(); this is particularly true for alarm() handlers.
ANSI specifies that longjmp should restore the environment properly
even from within a signal handler, but is not required to do anything
meaningful if called from a nested signal handler. KCC supports this
use of longjmp().
Extensions to sigvec():
For additional flexibility, the "sigvec" structure has been
extended to include additional parameters. Some new flags in sv_flags
are used to indicate when the additional structure members are
significant.
The things that can be specified, independently of each other:
SV_XINTLEV: ON If handler should run at interrupt level.
SV_XASMHAN: ON If handler is special assembler routine (ACs not saved,
no args given). Otherwise, normal C handler.
SV_XOS: ON If the sigvec structure should be checked for:
(1) Exact PSI channel # to use for this signal (0 = existing).
(2) What PSI level to use (0 = existing).
(3) .TICxx code (plus 1) to ATI% to this channel (0 = none).
Not all of the flags work yet:
Currently only SV_XINTLEV is implemented. It works to use
longjmp() within handlers called with this flag!
SV_XASMHAN is not yet used. If added, it will be an error to
specify SV_XASMHAN without SV_XINTLEV; that is, if the handler is an
assembly routine, then it MUST run at interrupt level.
SV_XOS is not yet used. If added, specification of a positive
.TIC code will always replace any existing code by the new one, and
use of -1 will always clear any existing code. If the value is 0,
however, then the meaning depends on whether a channel # was
specified. If the channel # was given, 0 is the same as -1.
Otherwise, if no channel # was given, then 0 means leave any existing
code alone.

450
doc/kcc/usys.doc Executable file
View File

@@ -0,0 +1,450 @@
USYS.DOC - KCC Un*x System-call simulation
This file documents various things about the USYS library routines,
which are intended to provide simulation and support for Un*x system
call functions.
Specifications for the interfaces were taken from the March
1984 4.2BSD Unix Programmer's Manual (UPM), plus the 4.3BSD man pages,
and all code here works as described in those references unless
otherwise documented.
Implementors should also read the CODSYS.DOC file in the
source directory.
Contents:
Intro - listing format
Summary of USYS routines
Definitions
Individual Routine Descriptions (as needed)
Library function listing format:
Name Module Port-status Comments
(routine name) (source file) (see below)
Port-status code:
E = file #includes "c-env.h" for environment config.
<sys> - runs on the given sys, one of: T20,10X,T10,WAITS,ITS.
*10 = portable to all PDP-10 OS (T20,10X,T10,WAITS,ITS)
* = fully portable (either no OS-dependent stuff, or a
fully-portable conditional exists)
Comments:
"U" means the call is USYS_macro enclosed and cannot be
interrupted by signals.
"-" means it isn't enclosed
(this better be cuz interrupts don't affect the call!)
"I" means it is interruptible (i.e. can return EINTR error).
"IC" means interrupts may be continued within the call.
USYS function summary: Src: lib/usys/
Name Module Port-status Comments
access ACCESS T20,10X U 10X only partial.
alarm ALARM T20 U
brk SBRK *10 U
chdir CHDIR T20,10X U
chmod CHMOD T20,10X U
chown CHOWN T20,10X U
close CLOSE T20,10X,ITS U
creat OPEN T20,10X U
dup DUP *10 U
dup2 DUP *10 U
errno (data) URT *10 -
exec[lv][ep] FORK T20,10X U
exit EXIT *10 -
fchmod CHMOD T20,10X U
fchown CHOWN T20,10X U
fcntl FCNTL *10 U
fork FORKEX T20,10X U
forkexec FORKEX T20,10X U KCC-specific routine.
fstat STAT T20,10X U (also: xfstat)
ftime TIME *10 -
geteuid GETUID T20,10X U
getpid GETPID *10 U see format note.
gettimeofday TIME *10 -
getuid GETUID T20,10X U
gtty SGTTY T20 U
ioctl IOCTL T20 UIC Partial.
kill SIGVEC T20,10X U
lseek LSEEK T20,10X U
open OPEN T20,10X U (Uses BSD flags; mode not supported)
pause PAUSE *10 -I Always returns with EINTR
pipe PIPE T20 U (monitor must have PIP: device)
psignal PSIGNA *10 -
raise SIGVEC T20,10X U (ANSI function, not syscall)
read READ T20,10X U
rename RENAME T20,10X U
sbrk SBRK *10 U
sigblock SIGVEC T20,10X U
signal SIGNAL T20,10X U
sigpause SIGVEC T20,10X UI Always returns with EINTR
sigreturn SIGVEC T20,10X U
sigsetmask SIGVEC T20,10X U
sigstack SIGVEC T20,10X U
sigvec SIGVEC T20,10X U
sleep SLEEP *10 -I (returns no value)
stat STAT T20,10X U (also: xstat)
stty SGTTY T20 U
tell LSEEK T20,10X U
time TIME *10 - (also: tadl_xxx routines)
times TIMES *10 -
unlink UNLINK T20,10X,ITS U (10X doesn't expunge)
utime UTIME T20,10X U
vfork FORK T20,10X U
wait WAIT T20,10X UIC
write WRITE T20,10X,ITS UIC
_exit EXIT *10 U
_runtm URT *10 (internal) C programs start here.
_urtsud (data) URTSUD *10 (internal) Runtime startup defs.
DEFINITIONS:
The UPM introduction contains some definitions which provide
a convenient way to start describing how the KCC simulations differ from
Un*x; some concepts are supported and others are not.
Process ID (PID): Supported, see long description.
Parent Process ID: Supported, see long description.
Process Group ID: not implemented
TTY Group ID: not implemented
Real User ID: Supported.
The user ID on T20/10X is the "user number".
Real Group ID: not implemented
Effective UID, GID, and Access Groups: not implemented
Super-user: not implemented
Special Processes: not implemented
File Descriptor (FD): Supported.
Small non-negative integers in the range 0 to 63 inclusive.
FDs 0, 1, and 2 correspond to standard input, output, and error output.
On T20/10X these are initially set to the JFNs .PRIIN, .PRIOU, .CTTRM.
You can obtain the JFN for a FD by using the fcntl() call.
File Name: Supported.
On T20/10X, up to 39 chars per component. Must be 7-bit ASCII.
Can quote with ^V.
Path Name: Supported.
Un*x style / paths are permitted, where foo/ is taken to mean foo
is a subdirectory of the current directory.
If the monitor worked right, a filespec of the form "C:foo/bar.h" could
be turned into "C:<.foo>bar.h", assuming standard-type relative
directory fixes, and we would win. But no. Instead, we have to do
the work manually: the logical device is recursively expanded until
an end device-directory pair is found, at which point the file
lookup is tried. If it fails, the expansion/traversal continues.
Directory: Supported.
<.> and <..> work on some T20 systems (Stanford mods).
Root Directory and Current Working Directory:
A directory of the form "/foo" is taken to mean "<foo>".
The notion of a current working directory is supported.
File Access Permissions:
Each set of T20/10X owner, group, and world access bits
corresponds to a set of Un*x owner, group, and other bits.
Un*x T20/10X
04 040 Read access
02 020 Write access
01 010 Execute access
- 04 Append access
- 02 Directory listing access
- 01 -
Thus, a call such as "chmod(foo.bar, 0644)" will set the T20/10X
protection of "foo.bar" to 604040.
There is no way a user program can either read or set the last
three T20/10X protection bits, except by doing a CHFDB% itself.
Finally, there is no T20/10X counterpart to the set-UID or set-GID
bits.
Sockets and Address Families: not implemented (yet!)
ERRORS:
The global "errno" is set by all failing USYS calls.
The standard UN*X error numbers from <errno.h> are used where possible,
although a few T20-specific error codes have been defined. See <errno.h>
for details.
There is currently no easy way to find out what TOPS-20/TENEX
error (if any) caused errno to be set. The best one can do is find the
most recent error for the process with GETER%. Perhaps someday this will
be improved.
Exceptions:
ftime, time, gettimeofday, times
getpid
_exit (never returns)
PROCESS ID (PID): Long Description
PID values are generated by:
(1) getpid() - self process ID. This must not change over
the lifetime of the process!
(2) fork() - to identify the child process.
(3) wait() - to identify the child process that stopped.
This should match the value returned by fork().
PID values are used by:
(1) kill() - to send signals to self, child, or parent.
(It is rare to send them anywhere else.)
(2) Code that checks the return value of wait().
(3) Code that generates unique filenames, port numbers, or the like
which should not conflict with those of any other
active process.
For ITS, TOPS-10, and WAITS the PID is simply the job #, a
small positive integer; zero and negative PIDs will never be seen, as
job 0 is the monitor itself and no system can support 2**35 jobs.
However, TENEX (and hence TOPS-20) has never had a notion of a
unique process identifier, except internally inside the monitor; this
fork ID is simply not accessible to the user. Fork handles are all
relative, in an obscene attempt to prevent programs from referencing
any process they shouldn't. This makes it impossible to implement
getpid() in a straightforward way. The subterfuge I have resorted to
is as follows:
T20 PID = <IPCF PID>,,<frk #><job #>
<IPCF PID> - Left half of a PID generated by MUTIL% for process
This is guaranteed by system to be unique.
<frk #> - low 9 bits of relative fork handle, in 0777000.
<job #> - low 9 bits of job number, in 0777.
getpid() remembers the value generated on first call and
returns that thereafter. This satisfies the uniqueness and constancy
criterion, as well as being efficient.
fork() and wait() convert the relative fork handles from
CFORK% and GFRKS% to a child PID with a zero LH but with the other
fields set. Since relative fork handles are from 400000 to 400777, we
only need the low 9 bits.
fork() in the new child process copies the saved getpid()
value, if any; this is its parent's PID and may be used by kill(). The
saved value is then cleared so if the child calls getpid() it will generate
its own unique value.
kill() checks its PID argument first against the saved
getpid() value to see if a signal is being sent to itself. If not it then
sees whether it matches that of its parent (if any) and sends a signal
to .FHSUP if so. Otherwise, if the LH is 0 it assumes the signal is
being sent to a child, and generates the appropriate relative fork
handle from the 9 bits in the PID value. Note: There is no good way
to identify "miscellaneous" signals generated by another process (PSIs
on the "CHNmisc" channel); only those PSIs uniquely mapped to a single
signal can be successfully sent between processes.
This scheme fails only if PIDs are somehow passed from one
process to another either via pipe, file, or vfork() shared memory, since
the result of a child's getpid() won't match what its parent's fork()
returned. But this should practically never happen.
TENEX:
On TENEX, which doesn't have IPCF, we just use GFRKS% to
locate our fork within the job fork structure and hope the resulting
number, which we stick in the LH, doesn't change. At least TENEX
doesn't have extended addressing either so we can munch the GFRKS%
data on the stack.
OPEN() - Some I/O details:
The open() call has several additional flags which are intended to
help specify the proper actions on TOPS-20/TENEX systems, since the
defaults assumed by open() may not always be correct.
Standard BSD flags:
O_RDONLY open for reading only
O_WRONLY open for writing only
O_RDWR open for reading and writing
O_NDELAY do not block on open (not supported)
O_APPEND append on each write
O_CREAT create file if it does not exist
O_TRUNC truncate size to 0
O_EXCL error if create and file exists
KCC-specific flags (not portable)
O_BINARY Open in binary (9-bit byte) mode
O_CONVERTED Force LF-conversion
O_UNCONVERTED Force NO LF-conversion
O_BSIZE_7 Force 7-bit bytesize
O_BSIZE_8 Force 8-bit bytesize
O_BSIZE_9 Force 9-bit bytesize
TOPS-20 and TENEX specific flags
O_T20_WILD Allow wildcards on GTJFN%
O_T20_WROLD For writes, do NOT use GJ%FOU
O_T20_SYS_LOG logical device is system-wide!
O_T20_THAWED Open file for thawed access
The BSD flags behave as per the UPM documentation, and the T20
flags are fairly straightforward. The KCC flags however are more subtle;
they affect the characteristics of the I/O that will be done, rather than
how a file will be found or created. The two decisions that must be made
are: (1) Bytesize, and (2) LF-conversion. These are explained below.
BYTESIZE:
The decision of which bytesize to use for I/O is somewhat
complicated. The bytesize on UN*X is always 8 bits, but on PDP-10s it
can be anything from 0 to 36 bits. The algorithm we use is as follows:
If a byte size (one of 7, 8, or 9) is explicitly requested, use that.
Otherwise, for a new file, use 9 if O_BINARY, else 7.
for an old file, use the file's bytesize.
A size of 0 or 36 is treated as for a new file.
Any other size is simply used. If this is not
one of 7, 8, or 9 then the results are unpredictable.
LF-CONVERSION:
UN*X text files use the convention that a LF alone is a
"newline", whereas PDP-10 systems use CRLF together. Thus, the normal
mode of I/O uses LF-conversion, wherein read() converts a input CRLF
sequence to LF, and write() converts an output LF to CRLF. The algorithm
used to determine whether LF-conversion should be done is:
Conversion is normally only done if the bytesize is 7.
Any other size implies NO conversion.
However, this default can be overriden by certain flags:
If O_CONVERTED is set, conversion is ALWAYS done.
If O_UNCONVERTED or O_BINARY is set, conversion is NEVER done.
LSEEK() - Problems with LF-conversion
lseek() deals only with system-level file pointers. When no
LF-conversion is being done, this corresponds exactly to the UN*X notion
of a file position, namely the # of bytes offset from the start of the file,
and it is possible to create your own file positions arithmetically.
However, when LF-conversion is being done then this is not possible;
the position returned by lseek will correspond to the system's position,
rather than to the number of bytes fed through read() or write(). In this
case you can only lseek to a position previously returned by lseek() itself.
(Note that 0 is a special case that always works). Typically the pointer
returned will be larger than the number of bytes read or written thus far,
since the system is aware of the CR's in the file even though the C program
isn't.
STAT() - file status information
This section describes the correspondence between the components
of the stat() structure (as defined for Un*x) and the TOPS-20 file system
information.
struct stat
{
dev_t st_dev; /* The .DVxxx device type */
ino_t st_ino; /* .FBADR - Disk address of file index blk */
unsigned int st_mode; /* Un*x-style mode bits */
int st_nlink; /* 1 (always) */
int st_uid; /* T20: User #, 10X: directory # */
int st_gid; /* 0 (always, for now) */
dev_t st_rdev; /* 0 (always, for now) */
off_t st_size; /* .FBSIZ - size in bytes (any bytesize) */
time_t st_atime; /* .FBREF - last ref (Un*x format time) */
int st_spare1;
time_t st_mtime; /* .FBWRT - last write (Un*x format time) */
int st_spare2;
time_t st_ctime; /* .FBCRE - last mod (Un*x format time) */
int st_spare3;
long st_blksize; /* # bytes in a page (derived from FB%BSZ) */
long st_blocks; /* # pages in file (FB%PGC of .FBBYV) */
long st_spare4[2];
};
FORKEXEC() - New KCC-specific call
This call is intended to combine the functions of fork() and
exec() so that a user program that wants to perform the very common
procedure of first calling fork() and then having the child call exec()
can now simply use forkexec() and accomplish the same thing much faster.
The calling sequence is simply:
#include <frkxec.h>
int forkexec(fxp);
struct frkxec *fxp;
See the include file for details on the contents of the frkxec
structure and the flags that can be provided.
All of the exec*() functions call forkexec() with FX_NOFORK set.
TTY Handling:
The library supports many (though not all) of the Un*x TTY
functions. The primary means of getting information about the TTY and
setting TTY parameters is with the ioctl() call. All 4.3BSD TTY-related
ioctl functions are recognized, although not all are completely supported.
In particular, all requests to "get" data structures will always return
as much information as is available; attempting to "set" some elements of
these structures may or may not work, as described in the following comments.
IOCTL function comments:
FIONREAD - Get # bytes to read on FD. Supported.
TIOCGETP - Get sgttyb parameters, same as V6/V7 gtty(). Supported.
TIOCSETP - Set sgttyb parameters, same as V6/V7 stty(). Supported.
sg_ispeed, sg_ospeed Can read and set.
sg_erase Cannot set to anything but DEL (fails if you try).
sg_kill Cannot set to anything but ^U (fails if you try).
sg_flags The following flags are used:
RAW, CRMOD, ECHO, CBREAK
All other flags are ignored, esp. LCASE and TANDEM.
TIOCSETN - V7: same as TIOCSETP, but without flushing TTY input. Supported.
TIOCEXCL - V7: set exclusive use of tty (not implemented).
TIOCNXCL - V7: reset exclusive use of tty (not implemented).
TIOCHPCL - V7: Hang up on last close (not implemented).
TIOCFLUSH - V7: Flush TTY input and output buffers. Supported.
All other functions are for BSD4.3.
TIOCSTI - Simulate terminal input. Supported.
TIOCSBRK - Set break bit. (not implemented)
TIOCCBRK - Clear break bit. (not implemented)
TIOCSDTR - Set data terminal ready. (not implemented)
TIOCCDTR - Clear data terminal ready. (not implemented)
TIOCGPGRP - Get pgrp of tty. (not implemented)
TIOCSPGRP - Set pgrp of tty. (not implemented)
TIOCGETC - Get special characters (tchars). Supported.
TIOCSETC - Set special characters (tchars). Supported (sort of).
t_intrc and t_quitc (for SIGINT and SIGQUIT) are initially -1 but
can be set to any control character. Note that because
chars are unsigned, the initial value when converted to
an integer is 0777, not -1!
No other elements of tchars can be set to anything but what they
already are:
t_stopc = ^S, t_startc = ^Q, t_eofc = ^Z, t_brkc = -1
TIOCLBIS - Set bits in local mode word. (not implemented)
TIOCLBIC - Clear bits in local mode word. (not implemented)
TIOCLGET - Get local mode mask. (not implemented)
TIOCLSET - Set local mode mask. (not implemented)
TIOCSLTC - Set local special chars (ltchars). Supported.
TIOCGLTC - Get local special chars (ltchars). Supported (sort of).
None of these chars can be set to anything but what they already are:
t_suspc = ^C, t_dsuspc = ^C, t_rprntc = ^R, t_flushc = ^O,
t_werasc = ^W, t_lnextc = ^V
TIOCGETD - Get line discipline. Supported.
TIOCSETD - Set line discipline. Supported (sort of).
The line discipline is always NTTYDISC and cannot be set otherwise.
TIOCGWINSZ - Get window size info. Supported.
TIOCSWINSZ - Set window size info. Supported.
ws_col and ws_row correspond to the terminal's width and height.
Both can be read and set.
ws_xpixel and wx_ypixel are initially 0 but can be set and then read.
Signals:
Signals are complicated, both on Un*x and T20/10X. The KCC
implementation by default attempts to support the 4.3BSD signal
mechanism, which uses a variety of system calls. For those planning
to use signals, the file SIGNAL.DOC should be consulted.

59
src/c/c.defs Executable file
View File

@@ -0,0 +1,59 @@
/*
C Standard Definitions
*/
# define ITS ITS
/* data types */
struct _filespec {int dev, fn1, fn2, dir;};
# define filespec struct _filespec
# define channel int
struct _cal {int year, month, day, hour, minute, second;};
# define cal struct _cal
struct _tag {int *pc, *fp, *ap, *sp;};
# define tag struct _tag
/* common values */
# define TRUE 1
# define FALSE 0
# define OPENLOSS -1 /* returned by COPEN if lose */
# define EOF_VALUE 0 /* returned by CGETC if EOF */
/* C interrupts */
# define INT_DEFAULT 0
# define INT_IGNORE 1
# define realt_interrupt 0
# define mpv_interrupt 1
# define ioc_interrupt 2
# define ilopr_interrupt 3
# define mar_interrupt 4
# define utrap_interrupt 5
# define pure_interrupt 6
# define wiro_interrupt 7
# define sys_down_interrupt 8
# define clock_interrupt 9
# define timer_interrupt 10
# define pdlov_interrupt 11
# define ttyi_interrupt 12
# define cli_interrupt 13
# define overflow 14
# define float_overflow 15
# define channel0_interrupt 16
# define inferior0_interrupt 32
# define ctrls_interrupt 41
# define ctrlg_interrupt 42

7
src/c/clib.stinkr Executable file
View File

@@ -0,0 +1,7 @@
; xfile for loading basic C library
; this file must be loaded first
; segment 0 must start at 100
s 100,n,p,n
i sinit
l c;[crel] >

15
src/c/ctype.h Executable file
View File

@@ -0,0 +1,15 @@
#define _U 01
#define _L 02
#define _A 03
#define _N 04
#define _S 010
extern char _ctype[];
#define isalpha(c) (_ctype[c]&_A)
#define isupper(c) (_ctype[c]&_U)
#define islower(c) (_ctype[c]&_L)
#define isdigit(c) (_ctype[c]&_N)
#define isspace(c) (_ctype[c]&_S)
#define toupper(c) ((c)-'a'+'A')
#define tolower(c) ((c)-'A'+'a')

61
src/c/nc.insert Executable file
View File

@@ -0,0 +1,61 @@
; C;NC INSERT
; THIS FILE IS NEEDED TO ASSEMBLE MIDAS PROGRAMS PRODUCED BY
; THE C COMPILER AS WELL AS HAND-CODED MIDAS PROGRAMS DESIGNED
; TO BE LOADED WITH C PROGRAMS
RELOCATABLE
.INSRT SYSENG;MULSEG INSERT
.MSEG 200000',600000',700000'
IF1,[
.MLLIT==1
A=1
B=2
C=3
D=4
P=15.
.CCALL=1_27.
GO=JRST
EQUALS ENTRY .GLOBAL
EQUALS EXTERN .GLOBAL
DEFINE .IDATA
.SEG 0
TERMIN
DEFINE .UDATA
.SEG 1
TERMIN
DEFINE .CODE
.SEG 2
TERMIN
DEFINE .PDATA
.SEG 3
TERMIN
; STACK HACKING FOR VARIABLE REFERENCES
%P==0
DEFINE PPUSH [A]
PUSH P,A
%P==%P+1
TERMIN
DEFINE PPOP [A]
POP P,A
%P==%P-1
TERMIN
DEFINE CCALL N,F
.CCALL N,F
%P==%P-N
TERMIN
];END IF1
IF2,[IFDEF FS1,[
.KILL %A,%P,A,B,C,D,P,GO,.CCALL
]]

21
src/c/stdio.h Executable file
View File

@@ -0,0 +1,21 @@
/* STDIO.H for DEC20 implementation */
/* actual code is in <C.LIB>C20STD.C */
# define BUFSIZ 512 /* this number is irrelevant */
# define FILE int /* the actual structure is irrelevant */
# define NULL 0 /* null file pointer for error return */
# define EOF (-1) /* returned on end of file */
# define peekchar pkchar /* rename to avoid name conflict */
# define fopen flopen /* " */
# define getc fgetc /* " */
# define getchar fgeth /* " */
# define fprintf ffprintf /* " */
# define calloc fcalloc /* " */
# define feof ceof /* direct translation */
# define putc cputc /* " */
# define fputc cputc /* " */
extern FILE *stdin, *stdout, *stderr;

104
src/kcc_sy/fsdefs.h Executable file
View File

@@ -0,0 +1,104 @@
/* -*-C-*-
* ITS filesystem definitions
*
* Defines the format of binary MFDs and UFDs for use by C programs.
*/
/*
** MFD INFO
*/
/* RANDOM INFO IN MFD */
#define MDNUM 0 /* ASCENDING DIR NUM */
#define MDNAMP 1 /* PNTR TO ORG OF USER NAME BLOCK AREA */
#define MDYEAR 2 /* CURRENT YEAR */
#define MPDOFF 3 /* DE-CORIOLIS CLOCK OFFSET */
#define MPDWDK 4 /* PREFERRED WRITING DISK (PHYSICAL DRIVE #) */
#define MDCHK 5 /* THIS WORD MUST BE M.F.D. (FOR CHECKING) */
#define MDNUDS 6 /* NUMBER USER DIRECTORIES (FOR CHECKING ONLY) */
#define LMIBLK 7 /* TOTAL STG USED BY HACKS LIKE THIS */
/* USER NAME BLKS FROM C(MDNAMP) TO END */
#define LMNBLK 2 /* # WDS/BLK */
#define MNUNAM 0 /* 6BIT USER NAME */
/*
** UFD INFO
*/
#define UFDBYT 6 /* SIZE OF BYTES */
#define UFDBPW (36 / UFDBYT) /* NUMBER OF BYTES PER WORD */
/* RANDOM INFO IN UFD */
#define UDESCP 0 /* FS PNTR TO DESC AREA */
#define UDNAMP 1 /* PNTR TO ORG OF NAME AREA */
#define UDNAME 2 /* USER NAME (FOR CHECKING) */
#define UDBLKS 3 /* LEFT HALF HAS AMOUNT OF SPACE ALLOCATED (NOT */
/* USED CURRENTLY BY SYSTEM), RIGHT HALF HAS */
/* NUMBER OF BLOCKS USED. */
#define UDALLO 4 /* IF NONZERO, LEFT HALF HAS DISK NUMBER, RIGHT */
/* HALF HAS AMOUNT OF SPACE ALLOCATED */
#define UDDESC 11 /* FIRST LOC AVAIL FOR DESC */
/* UFD DESCRIPTORS
** 0 => FREE 1-UDTKMX => TAKE NEXT N
** UDTKMX+1 THRU UDWPH-1 => SKIP N-UDTKMX AND TAKE ONE
** UDWPH => WRITE-PLACE-HOLDER
** 040 BIT SET => LOAD ADDRESS. LOWER 5 BITS PLUS NEXT NXLBYT (2)
** CHARS (17 BITS IN ALL)
** 040 BIT & 020 BIT => "FUNNY" BLOCK IF DMDSK. WHAT IS THIS, ANYWAY?
** END BY 0
**
** IF LINK DESCR
** 6 CHAR OR UNTIL ; = SYS NAME. MUST HAVE NO CHAR = 0 IN THIS OR
** NEXT 2 NAMES
** NEXT CHAR QUOTED BY : (FOR NAMES WITH : OR ;)
** NEXT CHAR N1
** NEXT CHAR N2
** END BY 0
*/
#define UDTKMX 12 /* HIGHEST "TAKE N" CODE */
#define UDWPH 31 /* PLACE HOLDER ON WRITE (OR NULL FILE) */
#define UDSKMX (UDWPH - UDTKMX - 1) /* # BLOCKS THAT CAN BE SKIPPED */
#define NXLBYT 2 /* # ADDITIONAL BYTES FOR LOAD ADDR */
/* NAME AREA DATA */
#define LUNBLK 5 /* WDS/NAME BLK */
#define UNFN1 0 /* FIRST FN */
#define UNFN2 1 /* SECOND FN */
#define UNRNDM 2 /* ALL KINDS OF RANDOM INFO */
#define UNDSCP 0001500000000 /* PNTR TO DESC */
#define UNPKN 0150500000000 /* PACK # */
#define UNLINK 01000000 /* LINK BIT */
#define UNREAP 02000000 /* IF 1, DONT REAP FILE */
#define UNWRIT 04000000 /* OPEN FOR WRITING */
#define UNMARK 010000000 /* GC MARK BIT */
#define UNCDEL 020000000 /* DEL WHEN CLOSED */
#define DELBTS 020000000 /* DELETED -- IGNORE */
#define UNIGFL 024000000 /* BITS TO IGNORE FILE */
#define UNWRDC 0301200000000 /* WORD COUNT OF LAST BLOCK MOD 2000 */
#define UNDUMP 0400000000000 /* HAS BEEN DUMPED */
#define UNDATE 3 /* DATE ETC. */
#define UNTIM 0002200000000 /* COMPACTED TIME OF CREATION */
#define UNYMD 0222000000000 /* Y,M,D OF CREATION */
#define UNMON 0270400000000 /* MONTH */
#define UNDAY 0220500000000 /* DAY */
#define UNYRB 0330700000000 /* YEAR */
#define UNREF 4 /* REFERENCE DATE SAME AS LEFT HALF OF UNDATE */
#define UNREFD 0222000000000 /* REFERENCE DATE */
#define UNAUTH 0111100000000 /* MFD INDEX OF AUTHOR, ALL 1=> NO */
/* DIRECTORY */
#define UNBYTE 0001100000000 /* FILE BYTE SIZE AND LENGTH INFO. */
/* LET S=BITS PER BYTE, C=COUNT OF UNUSED BYTES
** IN LAST WD
** 400+100xS+C S=1 TO 3 C=0 TO 35.
** 200+20xS+C S=4 TO 7 C=0 TO 8
** 44+4xS+C S=8 TO 18. C=0 TO 3
** 44-S S=19. TO 36. C=0
** NOTE THAT OLD FILES HAVE UNBYTE=0 => S=36.
*/

11
src/kcc_sy/humble.h Executable file
View File

@@ -0,0 +1,11 @@
/* -*-C-*-
* HUMBLE header file
*/
extern int j_create(), j_kill();
extern int j_read(), j_write();
extern int j_dump(), j_load();
extern int j_vread(), j_vwrite();
extern int j_atty(), j_dtty();
#define SIXBIT(name) (* ((int *) ((_KCCtype_char6 *) name)))