13. Stack Groups

A stack (usually abbreviated "SG") is a type of Lisp object useful for implementation of certain advanced control structures such as coroutines and generators. A stack represents a computation and its internal state, including the Lisp stack. At any time, the computation being performed by the Lisp Machine is associated with one stack, called the current or running stack. The operation of making some stack be the current stack is called a resumption or a stack switch ; the running stack is said to have resumed the new stack. The resume operation has two parts: first, the state of the running computation is saved away inside the current stack, and secondly the state saved in the new stack is restored, and the new stack is made current. Then the computation of the new stack resumes its course. The stack remembers all functions which were active at the time of the resumption (that is, the running function, its caller, its caller's caller, etc.), and where in each function the computation was up to. In other words, the entire control stack (or regular pdl) is saved. In addition, the bindings that were present are saved also; that is, the environment stack (or special pdl) is saved. When the state of the current stack is saved away, all of its bindings are undone, and when the state is restored, the bindings are put back. Note that although bindings are temporarily undone, unwind-protect handlers are not run (see let-globally ). There are several ways that a resumption can happen. First of all, there are several Lisp functions, described below, which resume some other stack. When some stack (call it c ) calls such a function, it is suspended in the state of being in the middle of a call to that function. When someone eventually resumes c , the function will return. The arguments to these functions and the returned values can therefore be used to pass information back and forth between stack groups. Secondly, if an error is signalled, the current stack resumes an error handler stack, which handles the error in some way. Thirdly, a sequence break can happen, which transfers control to a special stack called the scheduler (see LINK:(scheduler)). Note: the following discussion of resumers is incomplete, and the way they work is being changed anyway.

Each stack has a resumer . c 's resumer is some other stack, which essentially is the last stack to resume c . This is not completely right, however, because some resume-forms set the resumed stack's resumer, and some don't. So c 's resumer is actually the last stack to resume c by means of one of the types of resume-form which does set the resumer.

si:%current-stack-previous-stack Variable
The binding of this variable is the resumer of the current stack.
There are currently four kinds of resume-forms:
1)If c calls s as a function with an argument x , then s is resumed, and the object transmitted is x . s 's resumer is now c .
2)If c evaluates (stack-return x) , then its resumer is resumed, and the object transmitted is x . The resumer's resumer is not affected.
3)If c evaluates (stack-resume s x) , then c is resumed, and the object transmitted is x . c 's resumer is not affected. (This is not currently implemented.)
4)If the initial function of c attempts to return a value x , the regular kind of Lisp function return cannot take place, since the function did not have any caller (it got there when the stack was initialized). So instead of returning, its resumer is resumed, and the value transmitted is x . The resumer's resumer is not affected. c is left in a state from which it cannot be resumed again; any attempt to resume it would signal an error.
There is one other way a stack can be resumed. If the running stack c gets a microcode trap, then the error handler stack is resumed. The object transmitted is nil , and the error handler's resumer is set to c . This kind of resuming will only happen to the error handler, so regular programs should not see it.
13.1 What is Going On Inside
The stack itself holds a great deal of state information. First of all, it contains the control stack, or "regular PDL". The control stack is what you are shown by the backtracing commands of the error handler (currently the Control-B and Meta-B commands); it remembers the function which is running, its caller, its caller's caller, and so on, and remembers the point of execution of each function (i.e. the "return addresses" of each function). Secondly, it contains the environment stack, or "special PDL". This contains all of the values saved by lambda -binding. Finally, it contains various internal state information (contents of machine registers and so on). When one stack resumes a second, the first thing that happens is that (some of) the state of the processor is saved in the first stack. Next, all of the bindings in effect are undone; each stack has its own environment, and the bindings done in one stack do not affect another stack at all. Then the second stack's bindings are restored, its machine state is restored, and the second stack proceeds from where it left off. While these things are happening, the transmitted object is passed into the second stack, and optionally the second stack's resumer is made to be the first stack.
si:%current-stack Variable
The value of si:%current-stack is the stack which is currently running. A program can use this variable to get its hands on its own stack.
make-stack-group name &optional options
This creates and returns a new stack. name may be any symbol; it is used to identify and print the stack. Each option is a keyword followed by a value for that option; any number of options may be given, including zero. The options are not too useful; most calls to make-stack don't have any options at all. The options are:
:sg-areaThe area in which to create the stack structure itself. Defaults to default-array-area .
:regular-pdl-area
The area in which to create the regular PDL. Note that this may not be any area; only certain areas may hold regular PDL, because accessing a regular PDL as memory must go through special microcode which checks an internal cache called the pdl buffer . Defaults to error-linear-pdl-area .
:special-pdl-area
The area in which to create the special PDL. Defaults to default-array-area .
:regular-pdl-size
Length of the regular PDL to be created. Defaults to 3000.
:special-pdl-size
Length of the special PDL to be created. Defaults to 400.
:car-sym-modeThe "error mode" which determines the action taken when there is an attempt to apply car to a symbol. This, and the other "error mode" options, are documented with the fucntions car and cdr . Defaults to 1 .
:car-num-modeAs above, for applying car to a number. Defaults to 0.
:cdr-sym-modeAs above, for applying cdr to a symbol. Defaults to 1.
:cdr-num-modeAs above, for applying cdr to a number. Defaults to 0.
:swap-sv-on-call-out
:swap-sv-of-sg-that-calls-me
:trap-enableThis determines what to do if a microcode error occurs. If it is 1 the system tries to handle the error; if it is 0 the machine halts. Defaults to 1.
:safeIf 1 (the default), a strict call-return discipline among stacks is enforced. If 0 , no restriction on stack switching is imposed.
stack-group-preset stack-group function &rest arguments
This sets up stack so that when it is resumed, function will be applied to arguments within the stack. Both stacks are made empty. stack-preset is used to initialize a stack just after it is made, but it may be done to any stack at any time.
stack-group-return x
Let s be the current stack's resumer; stack-return will resume s , transmitting the value x . s 's resumer is not affected.
stack-group-resume s x
stack-resume will resume s , transmitting the object x . s 's resumer is not affected. This function is not currently implemented.