The Revised Maclisp ManualThe PitmanualPage A-24
Published by HyperMeta Inc.
 
Prev | Index | Next
[Blue Marble]
Climate Change
Is cap and trade really sufficient?


System Programming

TTY-Related Interrupts


TTY InterruptsConceptControl Characters

It is possible to define control characters in Lisp to execute functions at interrupt level. Handlers can be be set with the TTYINT option to STATUS and SSTATUS.

Interrupt handlers are normally functions of two arguments, char and stream (upon which char was typed).

Certain primitive character interrupt handlers are defined which are safe to run even if garbage collection is in progress. Rather than use a function name, these primitive handlers are identified by the numeric code for the character which initially had the desired functionality. For example, the initial handler for Control-G is called 7 (or #^G).

The following control characters are defined as interrupt characters in Maclisp:

Char Handler Effect 
Control-A #^A (SETQ ^A T) 
Control-B +INTERNAL-^B-BREAK (BREAK ^B) 
Control-C #^C (SETQ ^D NIL) 
Control-D #^D (SETQ ^D T) 
Control-G #^G (^G) 
Control-R #^R (SETQ ^R T) 
Control-S #^W (SETQ ^W T) 
Control-T #^T (SETQ ^R NIL) 
Control-V #^V (SETQ ^W NIL) 
Control-W #^W (SETQ ^W T) 
Control-X #^X (ERROR 'QUIT) 
Control-Z #^Z (VALRET "") 

Interrupt handlers run with interrupts disabled unless the handler function explicitly re-enables interrupts.

Also, the interrupting character will still be on the input stream. In fact, there may be other characters ahead of it on the input stream since an interrupt runs immediately even before finishing pre-scanning other non-interrupting input.

Note that Control-S has the same definition as Control-W but a different effect. This is because Control-S only disables typeout at the interrupt level. Later, when seen by READ (usually in the Read-Eval-Print loop), it is also a splicing readmacro character which turns type-out back on. Control-W lacks this readmacro definition, so leaves typeout turned off until a Control-V is typed or until the variable ^W is somehow turned back on.

Control-H (backspace), which many Lisp versions ago caused a Lisp breakpoint is now a normal alphabetic character. Control-B has superseded it as the proper way to invoke a breakpoint at interrupt level.

Control-K (which re-types input to the READ and READLINE functions) and Control-L (which clears the screen and then re-types input) are not interrupt characters. They are handled at the tty prescan level.

Control-Q is not an interrupt character, it is a tty force-feed character.

The tty interrupt status of a character may be a function of two arguments or a fixnum.

If it is a function, then when the interrupt occurs it receives as arguments the file on which the interrupt occurred, and the character typed, as a fixnum.

If the function is a fixnum, it represents the internal system interrupt initially associated with the character whose ASCII code is the value of the fixnum. Not all codes are valid; it must be one of #^A, #^C, #^D, #^G, #^R, #^S, #^T, #^V, #^W, #^X, or #^Z.


TTYINTSStatus Option(SSTATUS TTYINT char val [fileobj])

[PDP-10 Only] Sets the tty interrupt information for char on a given tty input file array, fileobj (default T, the terminal), to a given val, which must be a handler such as would be later returned by (STATUS TTYINT ...).

Multics users may want (STATUS INTERRUPT).

;; Set up control-E to type a stupid message.
(sstatus ttyint #^e #'(lambda (stream char) (print 'hi)))
=> T

;; Now type Control-E to test it. Note that the interrupt
;; runs before the character echos!
HI ^E

;; Set up Control-F to do what Control-G does.
(SSTATUS TTYINT #^F #^G)

;; Now type Control-F to see how it works
QUIT

*

Note that an interrupt can be associated with any ASCII character, not just control characters. On ITS, one must use (SSTATUS TTY) to tell ITS that things like "?" or "#" are to be considered interrupt characters (this is similar to the activation character problem).

Note also that initially Control-S is set to be like Control-W as an interrupt character (see below).


TTYINTStatus Option(STATUS TTYINT char [fileobj])

[PDP-10 Only] Returns the tty interrupt information for char on a given tty input file array, which defaults to T, the terminal. All argument positions are evaluated.

The char may be a character in fixnum or symbol representation.


^A (Uparrow A)ValueNIL

In the initial Lisp system, Control-A is an interrupt which sets ^A to T. This was from the early days of Lisp when general tty interrupts were not available -- programs could query the value of ^A to see if it had changed from NIL (and reset the value to NIL so they could detect such interrupts again later).

Externally Signalled Interrupts


CLI-MESSAGEValueNIL

[ITS Only] The symbol CLI-MESSAGE, if not NIL, should be a function of one argument which handles a interrupt on the Lisp job's CLI device. The argument may be ignored since it is always NIL. To handle the interrupt, the function should open the “CLA:” device in order to read the message. One of the options in OPEN's second argument should be CLA (as opposed to DSK or TTY) because of the format of the input stream read from the CLA device (see ITS system documentation for more about this problem). This causes open to read the first two words of the file and use them as the file names for the truename function. The CLA: file should be opened in block mode for this purpose.

If CLI-MESSAGE is set to NIL, such interrupts are ignored. This is the default case.


CLIStatus Option(STATUS CLI)

[ITS only] Says whether CLI handling is enabled. See documentation on the CLI-MESSAGE variable.


CLISStatus Option(SSTATUS CLI flag)

[ITS Only] If flag is T, enables CLI handling using the handler given by the CLI-MESSAGE variable. If flag is NIL, disables CLI interrupt handling.

Web-Only Note:

The following is some sample code (complete with documentation) that I found in my notes and thought might be helpful:

;;; Notes about CLI interrupts:
;;;
;;; A CLI interrupt is what happens when another job sends to yours. It is
;;; normally the case that other jobs will send directly to a user's HACTRN.
;;; If, however, Lisp is interrupted by a CLI message, it can elect to handle
;;; handle the interrupt in an arbitrary way.
;;;
;;; To define a handler, two things must be done:
;;;  [1] Place the name of the handler function (function of one arg)
;;;	 in the variable CLI-MESSAGE.
;;;  [2] Enable CLI handling with (SSTATUS CLI T)
;;;
;;; The handler should take a single argument which it probably should ignore
;;; since I have no idea what it is likely to be.
;;;
;;; The handler should open the file "CLA:" in (CLA BLOCK) mode and immediately
;;; discard the first 8 characters which will be garbage.
;;;
;;; The remainder of the stream, until a control-C or an eof, will be the text
;;; of the message sent. It may be read with TYI, READ, etc. and handled 
;;; however.

(eval-when (eval compile)
  (cond ((not (get 'iota 'version))
         (load "liblsp;iota"))))

(defun handle-cli-msg (ignore)
  (iota ((stream '((cla)) '(cla block)))
    (do ((i 0 (1+ i))) ((= i 8)) (tyi stream))
    (do ((c (tyi stream -1) (tyi stream -1)))
        ((or (= c -1) (= c 3)))
      (format t "~&~3,'0O ~@:C~%" c c)))) ;print out chars seen

(setq cli-message 'handle-cli-msg)

(sstatus cli t)

; --------

(defun eval-cli-msg (ignore) ;alternate handler
  (iota ((stream '((cla)) '(block cla)))
    (do ((i 0 (1+ i))) ((= i 8)) (tyi stream))
    (do ((f (read stream nil) (read stream nil)))
        ((null f))
      (errset (eval f) nil)))) ;Quietly evaluate forms...

;; Assumes the other lisp will have EVAL-CLI-MSG as value of CLI-MESSAGE

(defun eval-in-other-lisp (uname jname s-expression)
  (iota ((stream `((cli) ,uname ,jname) '(out ascii block)))
    (print s-expression stream)))

SYS-DEATHValueNIL

The value of this variable is a handler to be called if an interrupt is received from the operating system saying that the system is going down.

Web-Only Note:

Here's a sample use of this that I had laying around. Note that +EXTERNAL-YES\NO-PREDICATE was one of my personal utility functions, not something pre-defined by MACLISP, so think of it as like YES-OR-NO-P in Common Lisp. Likewise, SAVE was a FEXPR that I had defined elsewhere, and (LSDMP DEATH) is not an evaluable form, but a filename in which SAVE will put data.

(SETQ SYS-DEATH 'SYS-DEATH-HANDLER)
(DEFUN SYS-DEATH-HANDLER N
  (COND ((AND (ZEROP (CADR (STATUS ITS)))
              (OR (NOT (STATUS TTY))
                  (+EXTERNAL-YES\NO-PREDICATE ;user-defined
                     '|Sys going down. Save environment?|)))
         (SAVE (LSPDMP DEATH)))))

ITSStatus Option(STATUS ITS)

[ITS Only] Useful in conjunction with the SYS-DEATH interrupt is (STATUS ITS). This returns a list of five numbers:

(1) A flonum number of seconds until system is to go down. 
 -1.0 means the system does not plan to go down. 
 -2.0 means the system is already down. 
(2) A fixnum, non-zero if the system is being debugged. 
(3) The number of users on the system, as a fixnum. 
(4) The number of memory errors the system has survived. 
(5) A flonum number of seconds that the system has been up. 

This information is obtained from the ITS SSTATU system call.

Web-Only Note:

No, amazingly enough, that's not a joke about -2.0 above. I thought it was but when I questioned it one day, someone with more skill about these things than I ever had just laughed and took me to the ITS system console, brought down timesharing on the mainframe (which leaves one in single-user mode typing to the console). In this mode, the relevant system call returns -2.0, indicating that timesharing is down.


TTY-RETURNValueNIL

[ITS Only] This is a handler to be run upon return from the superior job.

Alarm Clocks


ALARMCLOCKFunction(ALARMCLOCK timername q)

[ITS and Multics only] ALARMCLOCK is a function for controlling timers. It can start and stop two seperate timers; one is a real-time timer and the other is a cpu-time timer. The first argument to ALARMCLOCK indicates which timer is being referred to: it may be the symbol TIME to indicate the real-time timer or the symbol RUNTIME to indicate the cpu-time timer. The second argument to alarmclock controls what is done to the selected timer. If it is a positive (non-bignum) number the timer is started. Thus if q is a positive fixnum or flonum, then (ALARMCLOCK 'TIME q) sets the real-time timer to go off in q seconds, and (ALARMCLOCK 'RUNTIME q) sets the cpu-time timer to go off in q microseconds. If the timer was already running the old setting is lost. Thus at any given time each timer can only be running for one alarm, but the two timers can run simultaneously. If the second argument to ALARMCLOCK is not a positive number, the timer is shut off, so (ALARMCLOCK timername NIL) or (alarmclock timername -1) shuts off the timer. ALARMCLOCK returns T if it starts a timer, NIL if it shuts it off. When a timer goes off, the handler for that interrupt (controlled by the variable ALARMCLOCK), if any, is run in (NOINTERRUPT T) mode so that it can not be interrupted until it has done its thing. If it wants to allow interrupts, other timers, etc. it can do (NOINTERRUPT NIL). In any case the status of the nointerrupt flag will be restored when the handler function returns (see NOINTERRUPT).


ALARMCLOCKValueNIL

[ITS and Multics only] The value of alarmclock is the handler for the timer interrupt, which is signalled when a timer set up by the ALARMCLOCK function goes off.

The handler function should be a function of one argument, which will be a list of one element, the symbol TIME or the symbol RUNTIME, depending on the first argument in the call to the ALARMCLOCK function which set up the timer.


SLEEPFunction(SLEEP k)

causes a real-time delay of k seconds, then returns T. k may be a fixnum or a flonum.

Enabling/Disabling Interrupts


NOINTERRUPTFunction(NOINTERRUPT val)

[PDP-10 Only] (NOINTERRUPT T) shuts off Lisp interrupts. This prevents alarmclock timers from going off and prevents the use of control characters such as Control-G and Control-B. Any of these interrupts that occur are simply deferred until interrupts are re-enabled. (NOINTERRUPT T) mode is used to protect critical code in large subsystems written in Lisp. It is also used by the Lisp subsystem itself to protect against interrupts in the garbage collector.

(NOINTERRUPT NIL) turns interrupts back on. Any interrupts which were saved will now get processed. NOINTERRUPT returns the previous state of the interruptdisable switch, T or NIL. The normal, initial state is NIL.

In most cases, it is best to bind interrupts using the WITHOUT-INTERRUPTS special form.


NOINTERRUPTSStatus Option(STATUS NOINTERRUPTS)

Reads the value of the pseudo-variable +INTERNAL-WITHOUT-INTERRUPTS. This variable should never be set, only bound. To set it, use (SSTATUS NOINTERRUPTS ...). Even when bound, it will always appear to be bound to NIL. This is the only right way to read the value it has been bound to.


NOINTERRUPTSSStatus Option(SSTATUS NOINTERRUPTS flag)

Sets the value of (STATUS NOINTERRUPTS) to T or NIL according to flag.


WITHOUT-INTERRUPTSSpecial Form(WITHOUT-INTERRUPTS form1 form2 ...)

Executes form1, form2, etc. from left to right returning the value of the last. During execution, interrupts are disabled. After execution, interrupts are restored to the state they had prior to the WITHOUT-INTERRUPTS form. If interrupts had been off, they remain off; if interrupts had been enabled, they are re-enabled.


STATUSSpecial Form(STATUS key [data1 [data2 ...]])

Returns useful information about lots of things. What things the information is about, which kinds of data are required, and even whether various argument positions are evaluated or not depends on the choice of key.

The key argument position itself is not evaluated. It turns out that STATUS, unlike nearly all other functions in Lisp, does not do dispatching using EQ, but rather looks at the first five characters of the symbol to determine if it matches. This behavior causes many programmers to write (STATUS OPSYS) when they mean (STATUS OPSYSTEM-TYPE), (STATUS FILES) or (STATUS FILESYS) when they mean (STATUS FILESYSTEM-TYPE), etc. Doing this is not encouraged, as it is intended that the implementation of STATUS may some day be corrected and programs which cheat may break.

In this documentation, all argument positions to STATUS may be assumed to evaluate (except, of course, the key) unless otherwise noted.

To see a list of possible STATUS keys, see the Status Option Index.


STATUSStatus Option(STATUS STATUS [key])

If key is supplied, returns true iff the given key is a valid first argument to STATUS. If key is not supplied, returns a list of all valid first arguments to STATUS. The key is not evaluated.

To see a list of possible STATUS keys, see the Status Option Index.


SSTATUSSpecial Form(SSTATUS key [data1 [data2 ...]])

Sets the state of various switches in the Lisp system. The state of many, but not all, of the things which SSTATUS can set can be read with (STATUS key ...). SSTATUS and STATUS share the same peculiar argument conventions; see documentation on STATUS for details.

To see a list of possible SSTATUS keys, see the SStatus Option Index.


SSTATUSStatus Option(STATUS SSTATUS [key])

If key is supplied, returns true iff the given key is a valid first argument to SSTATUS. If key is not supplied, returns a list of all valid first arguments to SSTATUS. The key is not evaluated.

To see a list of possible SSTATUS keys, see the SStatus Option Index.

The ``Features List''


FEATURESStatus Option(STATUS FEATURES)

Returns a list of symbols representing the features implemented in the LISP being used. The main idea behind this STATUS call is that an application package can be loaded into any MACLISP implementation and can decide what to do on the basis of the features it finds available. e.g., possible features include:

BIBOP Using PDP-10 “big bag of pages” memory management. 
LAP “Lisp Assembly Program” facility available. 
SORT Sorting functions (SORT, SORTCAR) are present. 
EDIT EDIT function is present. 
FASLOAD FASLOAD facility is present. 
^F “Moby I/O” facility is present. 
BIGNUM Arbitrary-precision arithmetic is available. 
STRINGS Character strings and related functions are present. 
NEWIO All of the new-I/O functions are present. 
MC This Lisp is on the MIT-MC machine. 
ML This Lisp is on the MIT-ML machine. 
AI This Lisp is on the MIT-AI machine. 
H6180 This Lisp is on an H6180 (e.g., MIT-MULTICS). 
PDP10 This Lisp is on a DEC PDP-10 machine. 
ITS This Lisp is on some ITS system. 
MULTICS This Lisp is on some Multics system. 
DEC10 This Lisp is on some DEC TOPS-10 (or TENEX). 
 Note: TENEX runs under a TOPS-10 emulator. 
NOLDMSG Disable “;Loading ...” typeout by HERALD forms. 

The old idiom (CAR (LAST (STATUS FEATURES))), which was generally considered to be an implementation name, such as ITS or DEC10 or Multics is now discouraged. Use (STATUS SITE), (STATUS FILESYSTEM-TYPE), or (STATUS OPSYSTEM-TYPE) as appropriate instead.

The most frequent use of the features list is through the reader macro sequences #+sym and #-sym. This functionality is more fully described elsewhere, but simply put, the form after a #+sym is invisible to READ unless (STATUS FEATURE sym) is true in the readtime environment. Similarly, #-sym is visible only in environments where (STATUS NOFEATURE sym) is true. For example, the expression

(ABC #+ITS DEF #-ITS GHI #+LISPM JKL)

is read by a Lisp reader running on ITS as (ABC DEF). In a Maclisp under some other operating system, (ABC GHI) would be the result of READ on the above text. And on a Lisp Machine, (ABC GHI JKL) would be seen by READ. Use of the #+ and #- readtime conditionalization is, however, not recommended for novices.


FEATUREStatus Option(STATUS FEATURE sym)

Returns T if sym is on the features list, else NIL. The sym is not evaluated.

Synonym:

(AND (MEMQ 'sym (STATUS FEATURES)) T)

FEATURESStatus Option(SSTATUS FEATURE sym)

Adds sym to the features list. The sym is not evaluated.


NOFEATUREStatus Option(STATUS NOFEATURE sym)

Returns T if sym is not on the features list, else NIL. The sym is not evaluated.

Synonym:

(NOT (STATUS FEATURE sym))

NOFEATURESStatus Option(SSTATUS NOFEATURE sym)

Removes sym from the features list. The sym is not evaluated.

Job and System Flags


LISPVERSIONStatus Option(STATUS LISPVERSION)

Returns the version number of this Maclisp as an atomic symbol.


SITEStatus Option(STATUS SITE)

[PDP-10 Only] Returns a site name such as AI, ML, MC, CMU, SAIL, etc., or the kind of operating system if Lisp does not know the site name (i.e., TOPS-20, TENEX, or TOPS-10).

System maintainers: To get it to return the name of a site rather than just the site type, try creating a file LISP:SITE.TXT whose only contents is the string which is the printname of the symbol (STATUS SITE) should return.


FILESYSTEM-TYPEStatus Option(STATUS FILESYSTEM-TYPE)

[PDP-10 Only] Returns one of ITS, DEC20, OR DEC10.


OPSYSTEM-TYPEStatus Option(STATUS OPSYSTEM-TYPE)

[PDP-10 Only] Returns one of ITS, TOPS-20, TENEX, TOPS-10, CMU, or SAIL.


ARGStatus Option(STATUS ARG n)

[Multics Only] Returns the n+1th argument of the lisp command, as an interned atomic symbol. NIL is returned if n is more than the number of arguments on the lisp command.


JCLStatus Option(STATUS JCL)

In the PDP-10 implementation, returns the “job command line” as a list of characters (see EXPLODEC).

In Multics, jcl is more structured. The first “argument” to the Multics lisp command, if given, is used to designate a saved environment to start Lisp with. The second “argument,” if present, is returned (in EXPLODEC'd format) by (STATUS JCL). If no second argument was given, (STATUS JCL) returns NIL.


XJNAMEStatus Option(STATUS XJNAME)

[PDP-10 Only] Obsolete. Replaced by (STATUS SUBSYSTEM).


SUBSYSTEMStatus Option(STATUS SUBSYSTEM)

[PDP-10 Only] Returns the true name this job (ITS) or fork (Tops-20) wanted to run under. For example, on ITS, if multiple LISP jobs are started, they are called LISP0, LISP1, etc. (STATUS JNAME) will get the names with the digits, but (STATUS SUBSYSTEM) should always return just LISP for this case.

Eventually this will be made meaningful on TOPS-10 and multics implementations. The intended interpretation is “the generic name of this program.”


JNAMEStatus Option(STATUS JNAME)

[PDP-10 Only] This returns “the unique identifier of this job within the time-sharing system.” For example, on systems where the first of many Lisp forks for a user is LISP, the second is LISP0, etc., (STATUS JNAME) will return values like LISP0. See also (STATUS SUBSYSTEM).

On Tops-10, returns a job identifier of form nnnLSP, where nnn is a TOPS-10 job number.


JNUMBERStatus Option(STATUS JNUMBER)

[PDP-10 Only] Returns the job's job number.


HACTRNStatus Option(STATUS HACTRN)

[ITS Only] Returns information about the superior job. The following return values are defined:

LISP A Lisp superior. 
DDT A DDT superior. 
T Superior job unknown. 
NIL No superior job. 

This information is determined from information in the ITS job's .OPTION user variable.


UNAMEStatus Option(STATUS UNAME)

Returns an atomic symbol whose pname is the current user's name or ppn. In the Multics implementation this is in the format User.Project; the dot will be slashified if print is used to display this.


USERIDStatus Option(STATUS USERID)

[PDP-10 Only] Returns the user's real user name. On ITS, multiple logins of a user JDOE will get names like JDOE0 and JDOE1 assigned for that login session. (STATUS USERID) will always return the real name, JDOE in this case. To get names like JDOE0, you want (STATUS UNAME).


XUNAMEStatus Option(STATUS XUNAME)

[PDP-10 Only] Archaic. Use (STATUS USERID).


UDIRStatus Option(STATUS UDIR)

Returns the name of the file directory the user was connected to at the time the Lisp was started.


HOMEDIRStatus Option(STATUS HOMEDIR)

[PDP-10 Only] Returns the user's home directory as an interned symbol.


HSNAMEStatus Option(STATUS HSNAME [uname] [sitename])

[PDP-10 Only] For non-ITS sites, this is like (STATUS HOMEDIR). The arguments uname and sitename are only meaningful on ITS sites. Elsewhere they are likely to be ignored or an error. On ITS, however, they may find the home directory of user on a given ITS site. The value of uname defaults to the Lisp user's name, and sitename defaults to the current site.

Time


RUNTIMEFunction(RUNTIME)

Returns the number of microseconds of cpu time used so far by the process in which LISP is running. The difference between two values of (RUNTIME) indicates the amount of computation that was done between the two calls to runtime.


TIMEFunction(TIME)

Returns the time that the system has been up as a flonum in seconds.


DOWStatus Option(STATUS DOW)

Returns the day of the week as an interned symbol in uppercase. For example, on Monday, (STATUS DOW) returns the symbol MONDAY.


DATEStatus Option(STATUS DATE)

Returns the current date as a 3-list of fixnums, representing the date as (year month date), where year is based on 1900 and where month and date are based on 1. So July 4, 1976 would be (76. 7. 4.).


DAYTIMEStatus Option(STATUS DAYTIME)

Returns a 3-list of fixnums representing the current time of day as 24-hour clock time in the form of a list, (hour minute second), where all elements are based on 0. So the time 4:15:37pm would be given by (16. 15. 37.).


TIMEStatus Option(STATUS TIME)

Archaic. The same as (TIME), the number of seconds the system has been up.


RUNTIMEStatus Option(STATUS RUNTIME)

Archaic. The same as (RUNTIME), the number of microseconds of cpu time that has been used.

Dumping Environments


SUSPENDFunction(SUSPEND [data] [file])

SUSPEND is used to save an entire loaded environment as an executable image for later invocation. This is how subsystems built on top of Lisp are created. To use SUSPEND, you must first load your system, then close any files you have opened except TYI and TYO. Then call SUSPEND. On the next page is a sample of an init file to dump a system.

The optional arguments to SUSPEND have meaning only on ITS. The data argument may be a string to VALRET after doing the argument, or bits to use in a .BREAK 16,, or NIL meaning to not suspend at all (only useful when file is also specified). If file is given, the current environment is dumped as an executable file (a TS file). If file is not specified, the user is expected to use DDT to dump the file. Also, if the filename is specified and the value of (STATUS FLUSH) is not NIL, then the shared parts of the Lisp will not be saved.

On non-ITS sites, just call (SUSPEND) with no arguments and save according to the site-specific saving protocol. For example, on Tops-20...

@LISP.EXE

LISP 2129
Alloc? N

*
(load "MYSYS")
T

(suspend):$Job Suspended$
@SAVE (on file) MYSYS.EXE
 MYSYS.EXE.1 Saved	
@RESET MYSYS
@

A suspended Lisp can be continued on ITS (with $P or :CONTINUE). On non-ITS sites, a suspended Lisp must be restarted (e.g., by START from the Tops-20 Exec).

Alternatively, after having saved the Lisp to a file (either by the file argument to SUSPEND or by some Exec or DDT save command), it is appropriate to kill the Lisp. This can be done all at once on ITS by something like:

(SUSPEND ":KILL " '((DSK MYDIR) TS MYSYS))
    
;;; -*- LISP -*-
;;; Sample init file for dumping out an imaginary program 
;;; called MYSYS.

(COMMENT LIST 100000 SYMBOL 20000 FIXNUM 10000) ;octal

(PROGN ;; Magic to close this init file
       (CLOSE (PROG1 INFILE (INPUSH -1)))
       ;; Load compiled system
       (LOAD '((MYDIR) MYSYS FASL))
       ;; Personalized options to aid debugging
       (SETQ BASE 10. IBASE 10. *NOPOINT ())
       (DEFPROP DEBUG ((LIBLSP) DEBUG FASL) AUTOLOAD)
       ;; Tell user he's dumping our system
       (FORMAT T "~&Dumping: MYSYS~@[.~A~], A System of Mine~%"
               (GET 'MYSYS 'VERSION))
       ;; Set up runtime environment features
       (SSTATUS TOPLEVEL '(MY-TOPLEVEL)) ;Toplevel loop
       (SSTATUS FEATURE NOLDMSG) ;Suppress ";Loading ..." messages
       (SETQ GC-OVERFLOW '(LAMBDA (X) T)) ;Suppress GC-OVERFLOW breaks
       ;; Clean garbage made while dumping
       (GC)
       ;; On ITS, let this dump share pages with dump it's built from
       (SSTATUS FLUSH T)
       ;; Do the dumping
       (COND ((STATUS FEATURE ITS)
              (SUSPEND ":KILL " '((DSK MYDIR) TS MYSYS)))
             (T
              (SUSPEND)))
       ;; *** Anything after here runs each time the MYSYS program starts. ***
       ;; My handling of fix files, init files, etc.
       (MY-STARTUP)
       'READY)

Operating System Interface


SYSCALLFunction(SYSCALL n callname arg1 arg2 ...)

[ITS Only] This does system calls. n should be the number of values that will be returned. they will be returned as a list, unless an error occurs, in which case a numeric code describing the error will be returned.


VALRETFunction(VALRET [sym])

(VALRET) is supposed to be like the now-obsolete (IOC Z); that is, it does a .LOGOUT if LISP is a top level procedure, and otherwise valrets ":VK " to DDT.

*** Warning: There is a bad bug wherein (VALRET) will kill your Lisp rather than returning harmlessly, making it work more like (QUIT). Hence, this form should probably be avoided.

If an argument is provided but is not a symbol, it will be converted to a symbol.

If the string of characters making up sym is one of "$^X.", ":KILL ", or ":KILL^M" (the letters of KILL must be capitalized) then valret performs a "silent kill" by executing a .BREAK 16,20000. This may also allow programs that VALRET these forms to be transported to non-ITS sites and still work, though in practice it's not wise to depend on such a feature.

If the sym isn't one of those special configurations, it is passed to the superior (usually DDT) on ITS or placed in the rescan buffer on Tops-20. The superior job (ITS) or fork (Tops-20) will then usually execute the commands it has been passed.

Here are some examples from the ITS implementation:

(valret ':PROCED/ :DISOWN/ ) ; procedes and disowns the LISP. 
(valret '/ :KILL/ :TECO/^M) ; kills the LISP and starts up a TECO. 

Low-Level Machine Addressing


GETDDTSYMFunction(GETDDTSYM sym)

[PDP-10 Only] Returns the machine location represented by the symbolic name which is the argument. This works only if symbols have been loaded for the job. If symbols are not loaded, NIL is returned.


PUTDDTSYMFunction(PUTDDTSYM sym i)

[PDP-10 Only] Assigns sym as the DDT symbolic name of location i.


LH/|Function(LH/| n space)

[PDP-10 Only] Supposedly an ITS-only feature. Allocates a piece of memory of datatype space, n words big (actually rounds up to enough words to fill a page). The returned value is a fixnum which is the address of the first word of the chunk of memory or 0 if the memory could not be gotten. GC will mark through the space if it is of type LIST, BIGNUM, or HUNK. The data in the memory itself is not marked or swept. No guarantees are made if space is SYMBOL or ARRAY --- all other types should work.

In spite of its return value convention, do not do (DECLARE (FIXNUM (LH/|))); this is not a fixnum function.


EXAMINEFunction(EXAMINE address)

[PDP-10 Only] Returns a fixnum representing the raw contents of address which is given as its argument. (See also LH/| and DEPOSIT.)


DEPOSITFunction(DEPOSIT address value)

[PDP-10 Only] Both arguments must be fixnums. Deposits in a given machine address a fixnum value. A good way to get around using Lisp-pointers for certain specialized applications but highly machine-dependent and not recommended for general use. (See also LH/| and EXAMINE.)

High-Level Machine Addressing

The functions described on this page are intended for very special-puprose applications only, and are not useful in day-to-day programming. They are mostly useful to writers of system utilities who must do system calls, interface to LAP code, etc.


VALUE-CELL-LOCATIONFunction(VALUE-CELL-LOCATION sym)

[PDP-10 Only] Returns the address of symbol's value cell. The value cell itself is a cons whose cdr points at the value. Ages ago, when the value cell lived on the property list of a symbol, (GET sym 'VALUE) used to obtain the value cell. In modern Maclisp, (MAKNUM (VALUE-CELL-LOCATION sym)) does that.


MAKNUMFunction(MAKNUM q)

A dereferencing operator. Returns the machine address of q. Reasonably machine-dependent. In worlds with relocating garbage-collectors, it may be prone to timing-errors and hence useless.

*** Actually, this does something reasonably useful on Multics, but it doesn't return a machine address. ***


MUNKAMFunction(MUNKAM fixnum)

This will return a pointer to the object at machine location specified by its argument. It is not recommended as a way of creating objects, but can be used effectively in undoing a dereference of an object (as done by MAKNUM).

Note: MUNKAM is MAKNUM spelled backwards.

;; Example of (MUNKAM (MAKNUM x)) => x
(munkam (maknum '(foo bar)))
=> (FOO BAR)

;; Here's an example of accessing a symbol's value cell.
(setq foo 3)
=> 3

;; Get our hands on FOO's value cell.
(munkam (value-cell-location 'foo))
=> (NIL . 3)

;; Modify that cell
(rplacd * 4)
=> (NIL . 4)

;; Inspect that FOO was really changed.
foo
=> 4

;; Playing with the MAKNUMs of things if you have dropped the
;; original pointer may cause you grief because they can be
;; garbage-collected... consider the following:
(munkam (prog1 (maknum '(a . b)) (gc)))
=> (A B) ; the variable - (minus sign) had a pointer to the cons in GC

(munkam (prog1 (maknum (cons 'a 'b)) (gc)))
=> (NIL NIL NIL NIL ... ; the free list! nothing pointed to (A . B) in GC

(munkam (prog1 (maknum 12346.) (gc)))
=> 12346. ; the variable - (minus sign) had a pointer to the number in GC

(munkam (prog1 (maknum (1+ 12345.)) (gc)))
=> 241077.	; the fixnum free list! nothing pointed to 12346. during GC!

Hashing


SXHASHFunction(SXHASH q)

SXHASH computes a hash code of an S-expression, and returns it as a (possibly negative) fixnum. A property of SXHASH is that

(EQUAL x y) implies (= (SXHASH x) (SXHASH y)).

The number returned by SXHASH is some possibly large number in the range allowed by fixnums. It is guaranteed that:

1) SXHASH for an atomic symbol will always be positive. 
2) SXHASH of any particular expression will be constant in 
 a particular implementation for all time. 
3) Two different implementations may hash the same  
 expression into different values. 
4) SXHASH of any object of type RANDOM will be zero. 
5) (= (SXHASH i) i), for any fixnum i

SXHASHStatus Option(STATUS SXHASH)

[PDP-10 Only] Returns info about which of two SXHASH algorithms is in use. If T, the default, then the old SXHASH algorithm is in effect. If NIL, the new SXHASH algorithm is in effect. This algorithm is incompatible with the old one, so might break some programs and hence is not the default. It tries to fix the bug of SXHASH working too symmetrically on lists. The new SXHASH algorithm defines (SXHASH x) to mean:

(+ (ROT (SXHASH (CAR x)) 11.) (ROT (SXHASH (CDR x)) 7.))

SXHASHSStatus Option(SSTATUS SXHASH flag)

[PDP-10 Only] Sets the state of the SXHASH switch to flag. See documentation on (STATUS SXHASH).

Allocation


ALLOCFunction(ALLOC l)

The ALLOC function is used to examine and set parameters of various spaces having to do with storage management. To set parameters, the argument to alloc should be a list containing an even number of elements. The first element of a pair is the name of a space, and the second is either a fixnum or a 3-list. A fixnum specifies the PDLSIZE (for a pdl space) or the GCSIZE (for other spaces). A 3-list cannot be used with pdl space. It specifies, from left to right, the GCSIZE, GCMAX, and GCMIN. NIL means "don't change this parameter." Otherwise a fixnum must be supplied, except in the third element (the GCMIN), where a flonum is acceptable.

An example of this use of ALLOC, in the PDP-10 (BiBOP) implementation:

(ALLOC '(LIST (30000. 5000. 0.25)
         FIXNUM (4000. 7000. NIL)
         REGPDL 2000.))

or, in the Multics implementation:

(alloc '(list (30000. nil 0.3)
         markedpdl 5000.
         unmarkedpdl 5000.))

ALLOC may also be called with an argument of T, which causes it to return a list of all the spaces and their parameters. This list is in a form such that it could be given back to ALLOC at some later time to set the parameters back to what they are now.

Valid space names for the PDP-10 are LIST, FIXNUM, FLONUM, BIGNUM, SYMBOL, ARRAY, HUNK2, HUNK4, HUNK8, HUNK16, HUNK32, HUNK64, HUNK128, HUNK256, HUNK512, REGPDL, FLPDL, FXPDL, and SPECPDL.

The REGPDL is the “regular pdl.” It holds control information, compiled local variables, and arguments. The garbage collector marks through the relevant parts of this pdl. Naming conventions are not uniform in Maclisp for this pdl; elsewhere (e.g., in STATUS) this is called just PDL, not REGPDL.

The SPECPDL is the “special pdl.” It holds information about special variables which have been dynamically bound. Bindings are shallow, so the values on this pdl are the inactive values, not the active ones. Relevant parts of this pdl are marked through by the garbage collector.

The FLPDL, or “flonum pdl,” and the FXPDL, or “fixnum pdl,” contain 36-bit fixnum and flonum data which are temporaries being used by compiled code, number-declared compiled local variable storage, etc. These pdls are not marked through by the garbage collector.

The Garbage Collector


GCFunction(GC)

Causes a garbage collection and returns NIL.


GCPROTECTFunction(GCPROTECT obj switch)

[PDP-10 Only] If first arg is a symbol, merely sets the flag in the symbol-header which says “compiled code needs me”; such symbols will never be GC'd. Otherwise, it does a hash-table look-up of the s-expresssion on an internal array (stored in the cell labelled “GCPSAR:”) just like INTERN; so you get EQification for random list structure, which is what FASLOAD does in order to minimize duplication in "constant" structures. If second arg is "?", then it merely does a lookup, with no interning - sort of like INTERNDP. One other crinkle added to this function was for the benefit of the OWL system: if the value of the symbol GCPROTECT is not NIL, then this “interning” action is not done, but instead each structure (except symbols, of course) is freshly consed up.


GCTWASpecial Form(GCTWA [flag])

GCTWA is used to control the garbage collection of “truly worthless atoms,” which are atomic symbols which have no value and no special properties, and which are not referenced by any list structure, other than the obarray (the current obarray if there is more than one).

(GCTWA) causes truly worthless atoms to be removed on the next garbage collection.

The flag, if supplied, is not evaluated and must be one of T or NIL.

(GCTWA T) causes truly worthless atoms to be removed on each garbage collection from now on.

(GCTWA NIL) causes this continual removal of truly worthless atoms to be shut off, but it does not affect whether the next garbage collection removes such atoms.

Note: The “A” for “atom” in “GCTWA”is really misleading, since GCTWA affects the behavior of the garbage collector with respect to only symbols and not with respect to other kinds of atoms (such as numbers, arrays, etc.). However, this should cause no problem since the garbage collector can tell what truly worthless numbers, etc. are without needing hints from a switch.

The meaning of the value returned by GCTWA is given by the following table (numbers shown are in octal):

no GC of truly worthless atoms will be done. 
truly worthless atoms will be GC'd on next GC only. 
10 truly worthless atoms are GC'd on all GC's. 
11 both 

It is possible to test whether subsequent GC's are going to collect truly worthless atoms by checking the value of of the variable GCTWA.


GCTWAValueNIL

[PDP-10 Only] Holds a value saying whether the default during GC's is for “truly worthless atoms” are to be GC'd (T means Yes, NIL means No). See documentation on the GCTWA function for more information.


SYSTEMStatus Option(STATUS SYSTEM sym)

Returns a list of the system properties of the atomic symbol sym, which is evaluated. This list may contain SUBR, FSUBR, LSUBR, MACRO, or AUTOLOAD if sym denotes a function; VALUE if it is a variable in the initial system; and will always contain SYMBOL for initial symbols. Note that symbols defined only by out-of-core packages do not answer T to (STATUS SYSTEM sym) so this feature is of limited value. If it answers with something other than NIL, you can be sure the argument was an initial Lisp symbol, but if it returns NIL, you cannot be sure that it is not. Further, this STATUS option must cons the list of properties, so it's somewhat storage inefficient since generally all it gets used for is for boolean value in the first place.

On Multics, the list returned never contains any of the symbols SYMBOL, MACRO, or AUTOLOAD.

Examples:

(STATUS SYSTEM 'CAR)	=>	(SUBR VALUE SYMBOL)
(STATUS SYSTEM 'LAMBDA)	=>	(SYMBOL)
(STATUS SYSTEM 'FRED)	=>	NIL

SYSPFunction(SYSP sym)

If sym, which must be a symbol, is the name of a system function (and has not been redefined), SYSP returns the type of function (SUBR, LSUBR, or FSUBR). Otherwise, it returns NIL.

Examples:

(SYSP 'FOO)	=> NIL
(SYSP 'CAR)	=> SUBR
(SYSP 'COND)	=> FSUBR
(SYSP 'LAMBDA)	=> NIL

RECLAIMFunction(RECLAIM obj flag)

[PDP-10 Only] Usually, just calling the garbage collector directly (see GC) or waiting for it to run is the right way to deal with the recycling of storage. For those rare cases where this is not enough, RECLAIM is provided to allow an individual piece of storage to be returned without running the entire garbage collector mechanism.

This function reclaims list structure or numbers; i.e., returns them to the “free list.” The user is responsible for dropping all pointers to RECLAIMed object; failure to do so will leave him with pointers into the free list. Pure cells, value cells, hunks, arrays, objects of type random, and pointers to stack-allocated objects are ignored by RECLAIM. Only heap-consed lists and numbers will be reclaimed.

If flag is NIL, only the top level of obj is reclaimed. If obj is a number, that number is reclaimed. If obj is a list, the top level of conses in that list are reclaimed.

If flag is T, all levels are reclaimed. If obj is a number, that number is reclaimed. If obj is a list, all levels of that list are reclaimed.

Given:

(setq x1 '(a b c) x2 '(d e f) x3 '(g h i) x4 '(j k l) x5 '(m n o))
(setq n1 5000. n2 5000. n3 5000.)
(setq foo (list x1 x2 n1 (hunk x3 n2) (list x4 n3)))

(RECLAIM X5 NIL) would reclaim the three cells of X5.

(RECLAIM FOO NIL) would reclaim the five toplevel cells of FOO, leaving X1, X2, N1, etc. intact.

(RECLAIM FOO T) would reclaim all list cells in FOO except those in X3 because RECLAIM will not recurse into the hunk. The hunk itself will also not be reclaimed. The numbers held by N1 and N3 would also be reclaimed.

(RECLAIM N2 NIL) and (RECLAIM N2 T) would do the same thing; i.e., reclaim the number held by N3.

The behavior of RECLAIM with respect to hunks is not affected by the value of HUNKP.


GC-DAEMONValueNIL

The value of the variable GC-DAEMON, if not NIL, should be a function of one argument to be called after each garbage collection.

*** What is the nature of the argument? ***


GC-OVERFLOWValue+INTERNAL-GCO-BREAK

[PDP-10 Only] The value of the variable GC-OVERFLOW is a function of 1 argument to be run when a GC-OVERFLOW condition is signalled.

*** When are they signalled? What does it mean to handle this condition? What happens with return values? ***


GCPROTECTValueNIL

[PDP-10 Only] If the value of the symbol "GCPROTECT" is not NIL, then the "interning" action described in documentation for the GCPROTECT function is not done, but instead each structure (except symbols, of course) is freshly consed up.


^D (Uparrow D)ValueNIL

If the value of the symbol ^D (Uparrow D, not Control-D) is not NIL, the garbage collector prints an informative message after each garbage collection.

Typing Control-D sets the variable ^D to T. By default, typing Control-C interactively to a Lisp sets this variable back to NIL, except on Tops-20 where the system definition of Control-C has precedence over the Lisp definition of Control-C, so there is no easy way to set this variable back to NIL other than (SETQ ^D NIL).


GCTIMEStatus Option(STATUS GCTIME)

Returns the number of microseconds spent garbage collecting.


GCTIMESStatus Option(SSTATUS GCTIME n)

Resets the gctime counter to n and returns the previous value of the GCTIME counter. See also (STATUS GCTIME).


GCMAXStatus Option(STATUS GCMAX space)

[PDP-10 Only] Returns the GCMAX parameter for a given space, which is evaluated. See ALLOC for more information about GCMAX.


</