|The Revised Maclisp Manual||Page A-24|
|TTY Interrupts||Concept||Control Characters|
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.
|TTYINT||SStatus 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 ...).
;; 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).
|TTYINT||Status 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)||Value||NIL|
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
[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.
|CLI||Status Option||(STATUS CLI)|
|CLI||SStatus Option||(SSTATUS CLI flag)|
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: ;;;  Place the name of the handler function (function of one arg) ;;; in the variable CLI-MESSAGE. ;;;  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)))
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.
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.
|ITS||Status Option||(STATUS ITS)|
(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.
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.
[ITS Only] This is a handler to be run upon return from the superior job.
|ALARMCLOCK||Function||(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).
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.
causes a real-time delay of k seconds, then returns T. k may be a fixnum or a flonum.
[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.
|NOINTERRUPTS||Status Option||(STATUS NOINTERRUPTS)|
|NOINTERRUPTS||SStatus Option||(SSTATUS NOINTERRUPTS flag)|
|WITHOUT-INTERRUPTS||Special 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.
|STATUS||Special 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.
|STATUS||Status Option||(STATUS STATUS [key])|
|SSTATUS||Special 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.
|SSTATUS||Status Option||(STATUS SSTATUS [key])|
The ``Features List''
|FEATURES||Status 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.
|FEATURE||Status Option||(STATUS FEATURE sym)|
|FEATURE||SStatus Option||(SSTATUS FEATURE sym)|
|NOFEATURE||Status Option||(STATUS NOFEATURE sym)|
|NOFEATURE||SStatus Option||(SSTATUS NOFEATURE sym)|
Job and System Flags
|LISPVERSION||Status Option||(STATUS LISPVERSION)|
|SITE||Status Option||(STATUS SITE)|
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-TYPE||Status Option||(STATUS FILESYSTEM-TYPE)|
|OPSYSTEM-TYPE||Status Option||(STATUS OPSYSTEM-TYPE)|
[PDP-10 Only] Returns one of ITS, TOPS-20, TENEX, TOPS-10, CMU, or SAIL.
|ARG||Status 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.
|JCL||Status 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.
|XJNAME||Status Option||(STATUS XJNAME)|
|SUBSYSTEM||Status 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.”
|JNAME||Status 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.
|JNUMBER||Status Option||(STATUS JNUMBER)|
|HACTRN||Status Option||(STATUS HACTRN)|
[ITS Only] Returns information about the superior job. The following return values are defined:
This information is determined from information in the ITS job's .OPTION user variable.
|UNAME||Status 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.
|USERID||Status Option||(STATUS USERID)|
|XUNAME||Status Option||(STATUS XUNAME)|
|UDIR||Status Option||(STATUS UDIR)|
|HOMEDIR||Status Option||(STATUS HOMEDIR)|
|HSNAME||Status 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.
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.
|DOW||Status Option||(STATUS DOW)|
|DATE||Status 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.).
|DAYTIME||Status 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.).
|TIME||Status Option||(STATUS TIME)|
Archaic. The same as (TIME), the number of seconds the system has been up.
|RUNTIME||Status Option||(STATUS RUNTIME)|
Archaic. The same as (RUNTIME), the number of microseconds of cpu time that has been used.
|SUSPEND||Function||(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...
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
|SYSCALL||Function||(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.
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
[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.
|PUTDDTSYM||Function||(PUTDDTSYM sym 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.
[PDP-10 Only] Returns a fixnum representing the raw contents of address which is given as its argument. (See also LH/| and DEPOSIT.)
|DEPOSIT||Function||(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.
[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.
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. ***
;; 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!
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.
|SXHASH||Status 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:
|SXHASH||SStatus Option||(SSTATUS SXHASH flag)|
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:
or, in the Multics implementation:
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.
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
Causes a garbage collection and returns NIL.
|GCPROTECT||Function||(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.
|GCTWA||Special 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.
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):
|SYSTEM||Status 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.
|RECLAIM||Function||(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.
(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.
|^D (Uparrow D)||Value||NIL|
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).
|GCTIME||Status Option||(STATUS GCTIME)|
|GCTIME||SStatus Option||(SSTATUS GCTIME n)|
|GCMAX||Status Option||(STATUS GCMAX space)|
|GCMAX||SStatus Option||(SSTATUS GCMAX space i)|
[PDP-10 Only] Sets the GCMAX parameter of a given space to a given fixnum value, i. Both space and i are evaluated.
|GCMIN||Status Option||(STATUS GCMIN space)|
|GCMIN||SStatus Option||(SSTATUS GCMIN space k)|
[PDP-10 Only] Sets the GCMIN parameter of a given space to a given value, k, which must be a fixnum or flonum. Both space and i are evaluated.
|GCSIZE||Status Option||(STATUS GCSIZE space)|
|GCSIZE||SStatus Option||(SSTATUS GCSIZE space i)|
[PDP-10 Only] Sets the GCSIZE parameter for a given space to a given fixnum value, i. Both space and i are evaluated.
|ARRAY||Status Option||(STATUS ARRAY)|
[PDP-10 Only] Returns a list of four fixnums: the minimum number of dimensions an array may have, the maximum number of dimensions an array may have, the minimum axis length for an array, and the maximum axis length for an array. The list returned is freshly consed and may be destructively modified.
|BPSH||Status Option||(STATUS BPSH)|
|BPSL||Status Option||(STATUS BPSL)|
|MEMFREE||Status Option||(STATUS MEMFREE)|
|PAGING||Status Option||(STATUS PAGING)|
[Multics Only] Returns a list of the paging-device page faults and total page faults that have been incurred. The first element of this list may always be zero if there is no paging-device.
|FLUSH||Status Option||(STATUS FLUSH)|
[PDP-10 Only] If T, Lisp will try to flush certain system pages from the current environment during a suspend expecting that it can find them in the SYS;TS LISP (ITS) or LISP.EXE (Tops-20) it was loaded from. This flag seems to work only on ITS, but is harmless to set on Tops-20 and may someday work.
|FLUSH||SStatus Option||(SSTATUS FLUSH flag)|
|LOSEF||Status Option||(STATUS LOSEF)|
[PDP-10 Only] LOSEF supposedly stands for “LAP Object Storage Efficiency Factor.” According to the implementors, this is the “wrong thing” and doesn't want to be documented at all. It has something to do with the size of the hash table used by LAP and/or FASLOAD in interning quoted constants at load time.
|LOSEF||SStatus Option||(SSTATUS LOSEF val)|
Stack-Related Status Options
|PDLMAX||Status Option||(STATUS PDLMAX pdl)|
The maximum size to which a given pdl may grow before intervention is required. Used to detect infinite recursion.
|PDLMAX||SStatus Option||(SSTATUS PDLMAX pdl value)|
Sets PDLMAX for a given pdl to a given value.
|PDLNAMES||Status Option||(STATUS PDLNAMES)|
|PDLROOM||Status Option||(STATUS PDLROOM pdl)|
|PDLSIZE||Status Option||(STATUS PDLSIZE pdl)|
|FXPDL||Status Option||(STATUS FXPDL)|
[PDP-10 Only] Returns the contents of the base of the Lisp fixnum stack pointer, FXP, as a fixnum. Note, this is not the current value of that stack pointer. It is what that pointer would be at Lisp toplevel.
Note: “FXPDL” is pronounced like “fix-piddle.”
|FLPDL||Status Option||(STATUS FLPDL)|
[PDP-10 Only] Returns the contents of the base of the Lisp flonum stack pointer, FLP, as a fixnum. Note, this is not the current value of that stack pointer. It is what that pointer would be at Lisp toplevel.
Note: “FLPDL” is pronounced like “flow-piddle.”
|PDL||Status Option||(STATUS PDL)|
[PDP-10 Only] Returns the contents of the base of the Lisp control stack pointer, P, as a fixnum. (This is the same pdl as the one ALLOC calls REGPDL). Note, this is not the current value of that stack pointer. It is what that pointer would be at Lisp toplevel.
Note: “PDL” is pronounced like “piddle.”
|SPDL||Status Option||(STATUS SPDL)|
[PDP-10 Only] Returns the contents of the base of the Lisp special stack pointer, SP, as a fixnum. Note, this is not the current value of that stack pointer. It is what that pointer would be at Lisp toplevel.
Note: “SPDL” is pronounced like “spec-piddle.”
|SEGLOG||Status Option||(STATUS SEGLOG)|
[PDP-10 Only] Returns the log base 2 of segment, i.e. one unit of space allocation. On TOPS-10 systems this is one page (512 words), so the status call returns 9.
|PURSIZE||Status Option||(STATUS PURSIZE spacename)|
|PURSPCNAMES||Status Option||(STATUS PURSPCNAMES)|
|SPCNAMES||Status Option||(STATUS SPCNAMES)|
|SPCSIZE||Status Option||(STATUS SPCSIZE spacename)|
Returns the size (in words) physically allocated to a given space, spacename. This is frequently less than the amount which has been specified as allocatable with ALLOC.
Binary Program Space
There are a number of features which control how binary code and constants are purified when a compiled program is loaded into LISP.
[PDP-10 Only] The value of this variable should always be a fixnum, whose value is the address of the first unused word of “binary program space,” where SUBR code is stored. This value generally should only be examined by the user, not altered. BPORG is updated whenever binary code is loaded by LAP or FASLOAD.
[PDP-10 Only] This variable should also always have a fixnum as its value; this indicates the last available word of binary program space. Below this address, arrays are allocated. This is updated by many internal LISP routines, such as the garbage collector, the array allocator, and LAP and FASLOAD.
[PDP-10 Only] Calling this function causes “binary program space” (as marked by the BPORG variable) to be rounded up to a page boundary. It is necessary for this to be done if binary program space is to be purified; if it is not done, then future FASLOADing will attempt to write on a read-only page.
|GETSP||Function||(GETSP n [flag])|
The flag defaults to the value of the variable PURE. If flag is not NIL, then the memory added is marked as being potentially purifiable by PURIFY. This is generally used by clever subsystem loaders to expand binary program space quickly so that FASLOAD will not require several garbage collections to do the same thing. It can also be used by programs which create and destroy many arrays (see NORET).
Sets the NORET flag.
On Multics, this flag is not used for anything useful.
[PDP-10 Only] Holds the current value of the NORET flag. After a GC has been run, one of the last things done is to check how big the difference between BPEND and BPORG is; if it is more than several ITS pages, then an array-relocation phase is done in order to move downwards. Originally, in the pre-paging ITS days, this relocation actually returned core and swapping pages to the system, but nowadays, it merely prevents your LISP address space from being eaten up by dead space between the last loaded SUBR and beginning of array storage. One might set NORET to T, thereby preventing this action, if he wants to grab a big chunk of binary program space for his own use. This may be useful in conjunction with GETSP.
Pure cells, pure pages, ...
Purification is the term used to describe making something read-only. With respect to Lisp, this has two advantages:
A data structure which is pure does not get swept by the garbage collector. If (as is typically the case) pure structure does not reference impure structure, then the garbage collector does not even have to mark through it, thus saving mark time.
Pure structure can be shared (i.e., utilize the same virtual memory) between restored dumped Lisps. This results in less paging overhead for the operating system, and generally better performance.
On Multics, only code areas are pure; data areas are not, so this section isn't particularly relevant to Multics.
[PDP-10 Only] When you load FASL files, if *PURE is not NIL, then fasload will PURCOPY the quoted constants. Also PUTPROP will PURCOPY any property it sets up which has one of the indicators in the list held by the variable PUTPROP.
If this variable is not NIL, then Lisp will set things up so that constant datastructure referenced from loaded compiled code, the print-names of symbols which get interned, and things PUTPROPed under any of the properties on the list which is the value of PUTPROP (described more below), can be purified. Normally, this variable is NIL; if one is making a sharable dumped system, however, it should be set to T before things get loaded, and then reset to NIL before the Lisp is suspended.
In the SAIL implementation, the value of *PURE, if not NIL, should be (rather than just T) an estimate of the total number of words of pure free storage needed, including all that loaded by previous files and all that included in the initial lisp system. This causes FASLOAD to preallocate enough additional room in the high segment to accomodate the estimated total amount of pure storage. (The preallocation is necessary because it isn't possible to allocate list storage in the high segment once the loading of code has begun.) Making the estimate in *PURE too big merely wastes space in the high segment; making it too small causes PURCOPY to make its copies in the low segment when it runs out of room in the high segment. This whole feature only works if PURE is a negative fixnum.
It used to be the case that any call to COPYSYMBOL while *PURE was not NIL would return a purified symbol. As of May, 1978, this is no longer true. Now only symbols that are interned are automatically pure. This change in semantics seemed to result in a reduction in the size of COMPLR and Macsyma dumps.
|PUTPROP||Value||(+INTERNAL-STRING-MARKER SUBR FSUBR LSUBR)|
[PDP-10 Only] The value of PUTPROP is a list of properties which should be purified. In fact, not only the objects on those properties, but the portion of the plist referencing the property name and the object will be purified. To do this, PUTPROP (etc.) violates its normal semantics somewhat; it does not necessarily put the new property at the front of the property list. Conceptually, it divides the plist into two “zones”; the impure zone, and the pure zone. The impure zone comes at the front, with the pure zone as some sublist of it, since pure data structures should not point to impure data structures (unless special gc protection measures are taken).
Note that because of the presence of two zones, PUTPROP (etc.) of something that is not already there may not add the property to the front of the property list. In particular, consider the following sequence:
This function makes and returns a copy of obj in pure storage. This is primarily of use in the creation of large sharable systems like Macsyma. In implementations other than PDP-10 implementations with pure spaces, PURCOPY simply returns its argument.
|PURIFY||Function||(PURIFY start end flag)|
If flag is BPORG, then the pages are made pure, but in addition some work is done to make sure that no UUO on those pages may ever be “clobbered” (see PURE and PURCLOBRL). This option should always be used if the pages involved contain binary code loaded by LAP or FASLOAD.
If the first two arguments are zero, as in (PURIFY 0 0 'BPORG), Lisp will purify those portions of its address space which have been “marked for purification” (see PURCOPY), including all of binary program space. (A call to (PAGEBPORG) needs to be done first).
PURIFY does nothing in the TOPS-10 implementation.
[PDP-10 Only] This variable should be made not NIL by the user before loading binary code which is to be made pure. It tells LAP and FASLOAD to be circumspect about any UUO's in the code, because pure UUO's cannot be clobbered to be PUSHJ's or JRST's. LAP solves this problem by clobbering the UUO immediately if the referenced function is already defined and is itself a subr rather than an expr; otherwise the UUO is made permanently unclobberable (i.e. CALL is converted to CALLF, etc.).
FASLOAD is somewhat more clever: it, too, tries to clobber each UUO immediately, but if it can't it puts the address of the UUO on a list called PURCLOBRL, which is checked at the end of each call to FASLOAD, and each UUO on the list is clobbered at that time, if the appropriate function had been loaded by that call to FASLOAD. If the function never does get defined, then PURIFY will also check PURCLOBRL and convert each UUO to its permanently unclobberable form.
If pure has a fixnum as its value, then FASLOAD (but not LAP) behaves somewhat differently. PURE should be the desired size in words of the “uuolinks area”; this is rounded up to a whole number of pages. (If PURE is between 1 and 8, it is the number of pages rather than the number of words.) Let the number of pages be n. First FASLOAD calls PAGEBPORG, and then reserves 2n pages of binary program space, unless a previous call to fasload has already reserved them (i.e. they are reserved only once). Thus FASLOAD has two sets of n pages to work with; we shall call the first set “area 1” and the second set “area 2.” Now whenever FASLOAD has to load a clobberable UUO, it does not place it in the code being loaded, but rather hashes it and places it in area 1 if it was not there already; a copy is placed in the same relative position in area 2. Then an XCT instruction pointing to the UUO in area 1 is placed in the binary code. When all loading has been done, area 2 may be purified, but area 1 may not.
Now when running the code, the UUO's pointed to by the XCT's may be clobbered (the PDP-10 LISP UUO handler is clever about XCT), provided, of course, that the value of NOUUO is NIL, and the code will run faster the second time around because the XCT's will point to PUSHJ's. However, if (SSTATUS UUOLINKS) is called, then area 2 is copied back into area 1, effectively unclobbering all the UUO's. This allows the called functions to be traced again, for example, or redefined as expr code. Naturally, an area large enough to contain all the UUO's should be reserved; (STATUS UUOLINKS) yields information relevant to this. As a rule of thumb, the area should be 20% larger than the number of functions called by the loaded code (including LISP functions such as EQUAL). For the DEC-10 version, PURE may be set to a negative value. The magnitude is used as above, while the sign controls which segment to load into (positive means low segments, negative means high segment). A negative value also causes uuolinks area 1 to go in the low segment, and area 2 in the high segment. For compatibility, a negative value means the same as a positive value to the ITS implementation.
|GCWHO||Status Option||(STATUS GCWHO)|
|GCWHO||SStatus Option||(SSTATUS GCWHO i)|
1-bit When GC in progress, show “GC:reason” in wholine. 2-bit After a GC, clobber WHO2 word with GC runtime info.
Specifically, bit 2 turned on means that the left half of the WHO2 word gets the percentage of the run time which has been spent in GC, and the right half gets the GC run time in 40ths of a second. If the first two arguments to (SSTATUS WHO1 ...) are #o52 and '%, then these statistics will be printed in the form “NNN% HH:MM:DD.T”, just like the standard system runtime percentage and value. In this way one can continuously monitor GC run time statistics. The 1 and 2 bits may be used together (i.e., 3) or independently. Note that while using the 2 bit the WHO3 variable is still left over for use by the user. Thus one might say:
A note for those who use suspend: If the suspended job is dumped out and later reloaded, the runtime (maintained by the time-sharing system) will have been reset, but not the GCTIME, which is maintained by Lisp. Therefore a routine which does a suspend should perform (SSTATUS GCTIME 0) on return from the SUSPEND in order to make the who-line and other gc statistics accurate.
The “.WHOn” user variables cause information to be displayed in the terminal's who-line. The meaning of i1, i2, i3, AND i4 is as follows:
VAR BITS MEANING i1 200 If 1, suppress entire who-line. 100 Suppress space between halves of .WHO2 70 Mode for printing left half of .WHO2 0 Do not print 1 Date in packed form --- bits 774000 year mod 100 --- bits 3600 month (1=January) --- bits 174 day of month 2 Time in 40ths of a second, as HH:MM:SS.T 3 Time in half-seconds, as HH:MM:SS 4 octal halfword 5 Decimal halfword (no "." supplied) 6 Three sixbit characters 7 unused 7 mode for right half of .WHO2 i2 177 If non-zero, print between halves of .WHO2 as an ASCII character. 200 If 1, print char twice i3 200 If 1, suppress space between .WHO2 printout and .WHO3 printout Otherwise like i1, but for .WHO3. i4 Like i2, but for .WHO3.
That is, if the who-line is printed at all, what appears at the end is the characters:
IIII is .WHO2's left half, in i1's 70 bits' format. JJJJ right half of .WHO2, in i1's 7 bits' format. KKKK left half of .WHO3, in i3's 70 bits' format. LLLL right half of .WHO3, in i3's 7bits' format. XX 0-2 chars, specified by i2. YY 0-2 chars, specified by i4. - Space, unless i1's 100 bit is 1. = Space, unless i3's 200 bit is 1. + Space, unless i3's 100 bit is 1.
|WHO1||Status Option||(STATUS WHO1)|
|WHO1||SStatus Option||(SSTATUS WHO1 i1 i2 i3 i4)|
<.BYTE 8 ? i1 ? i2 ? i3 ? i4>
|WHO2||Status Option||(STATUS WHO2)|
|WHO2||SStatus Option||(SSTATUS WHO2 q)|
|WHO3||Status Option||(STATUS WHO3)|
|WHO3||SStatus Option||(SSTATUS WHO3 q)|
|The Revised Maclisp Manual (Sunday Morning Edition)|
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.