\input imbasic.tex \def\chapnum{0} \setcount0 0 \def\draftflg{F} \rm{} \vfill\eject\def\noheaderonce{T} \bf{}\noindent\save0\hbox{1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}THE INTERLISP-D PROCESS MECHANISM \rm{}\penalty 2000 \penalty 2000 \mark{THE INTERLISP-D PROCESS MECHANISM} \penalty 2000 \vskip10pt \penalty 2000 The Interlisp-D Process mechanism provides an environment in which multiple Lisp processes can run in parallel. Each executes in its own stack space, but all share a global adress space. The current process implementation is cooperative; i.e., process switches happen voluntarily, either when the process in control has nothing to do or when it is in a convenient place to pause. There is no preemption or guaranteed service, so you cannot run something demanding (e.g., Chat) at the same time as something that runs for long periods without yielding control. Keyboard input and network operations block with great frequency, so processes currently work best for highly interactive tasks (editing, making remote files). In Interlisp-D, the process mechanism is already turned on, and is expected to stay on during normal operations, as some system facilities (in particular, most network operations) require it. However, under exceptional conditions, the following function can be used to turn the world off and on: \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESSWORLD \arg{}FLG\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Starts up the process world, or if \arg{}FLG\rm{} = \lisp{}OFF\rm{}, kills all processes and turns it off. Normally does not return. The environment starts out with two processes: a top-level \lisp{}EVALQT\rm{} (the initial {\lquotes}tty{\rquotes} process) and the {\lquotes}background{\rquotes} process, which runs the window mouse handler and other system background tasks. Note: \lisp{}PROCESSWORLD\rm{} is intended to be called at the top level of Interlisp, not from within a program. It does not toggle some sort of switch; rather, it constructs some new processes in a new part of the stack, leaving any callers of \lisp{}PROCESSWORLD\rm{} in a now inaccessible part of the stack. Calling \lisp{}(PROCESSWORLD 'OFF)\rm{} is the only way the call to \lisp{}PROCESSWORLD\rm{} ever returns. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(HARDRESET)\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Resets the whole world, and rebuilds the stack from scratch. This is {\lquotes}harder{\rquotes} than doing \lisp{}RESET\rm{} to every process, because it also resets system internal processes (such as the keyboard handler). \lisp{}HARDRESET\rm{} automatically turns the process world on (or resets it if it was on), unless the variable \lisp{}AUTOPROCESSFLG\rm{} is \lisp{}NIL\rm{}. \parshape 1 0 pt 462pt {} \vskip10pt \bf{}\noindent\save0\hbox{1.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Creating and Destroying Processes \rm{}\penalty 2000 \penalty 2000 \mark{Creating and Destroying Processes} \penalty 2000 \vskip10pt \penalty 2000 \vskip 10pt \formatdef{462pt}{\lisp{}(ADD.PROCESS \arg{}FORM PROP\sub{1} VALUE\sub{1} {$\cdots$} PROP\sub{N} VALUE\sub{N}\lisp{})\arg{}\lisp{}\rm{}}{NoSpread Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Creates a new process evaluating \arg{}FORM\rm{}, and returns its process handle. The process's stack environment is the top level, i.e., the new process does not have access to the environment in which \lisp{}ADD.PROCESS\rm{} was called; all such information must be passed as arguments in \arg{}FORM\rm{}. The process runs until \arg{}FORM\rm{} returns or the process is explicitly deleted. An untrapped error within the process also deletes the process (unless its \lisp{}RESTARTABLE\rm{} property is \lisp{}T\rm{}), in which case a message is printed to that effect. The remaining arguments are alternately property names and values. Any property{\char'57}value pairs acceptable to \lisp{}PROCESSPROP\rm{} may be given, but the following two are directly relevant to \lisp{}ADD.PROCESS\rm{}: \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}NAME\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value should be a litatom; if not given, the process name is taken from \lisp{}(CAR \arg{}FORM\lisp{})\rm{}. \lisp{}ADD.PROCESS\rm{} may pack the name with a number to make it unique. This name is solely for the convenience of manipulating processes at Lisp typein; e.g., the name can be given as the \arg{}PROC\rm{} argument to most process functions, and the name appears in menus of processes. However, programs should normally only deal in process handles, both for efficiency and to avoid the confusion that can result if two processes have the same defining form. \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}SUSPEND\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}If the value is non-\lisp{}NIL\rm{}, the new process is created but then immediately suspended; i.e., the process does not actually run until woken by a \lisp{}WAKE.PROCESS\rm{} (below). \parshape 1 92pt 370pt {} \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESSPROP \arg{}PROC PROP NEWVALUE\lisp{})\arg{}\lisp{}\rm{}}{NoSpread Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92 pt 370pt {} \noindent Used to get or set the values of certain properties of process \arg{}PROC\rm{}, in a manner analogous to \lisp{}WINDOWPROP\rm{}. If \arg{}NEWVALUE\rm{} is supplied (including if it is \lisp{}NIL\rm{}), property \arg{}PROP\rm{} is given that value. In all cases, returns the old value of the property. The following properties have special meaning for processes; all others are uninterpreted: \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}NAME\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value is a litatom used for identifying the process to the user. \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}RESTARTABLE\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value is a flag indicating the disposition of the process following errors or hard resets: \vskip 10pt \vskip-10pt \parshape 1 161pt 301pt {}\save0\hbox{\lisp{}NIL\rm{} or \lisp{}NO\rm{}}\noindent\ifdimen 1wd0>29pt{\hskip-33pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-33pt\box0\hskip0pt plus 1000pt minus 1000pt}}(the default) If an untrapped error (or control-E or control-D) causes its form to be exited, the process is deleted. The process is also deleted if a \lisp{}HARDRESET\rm{} (or control-D from \lisp{}RAID\rm{}) occurs, causing the entire Process world to be reinitialized. \parshape 1 128pt 334pt {} \vskip 10pt \vskip-10pt \parshape 1 161pt 301pt {}\save0\hbox{\lisp{}T\rm{} or \lisp{}YES\rm{}}\noindent\ifdimen 1wd0>29pt{\hskip-33pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-33pt\box0\hskip0pt plus 1000pt minus 1000pt}}The process is automatically restarted on errors or \lisp{}HARDRESET\rm{}. This is the normal setting for persistent {\lquotes}background{\rquotes} processes, such as the mouse process, that can safely restart themselves on errors. \parshape 1 128 pt 334pt {} \vskip 10pt \vskip-10pt \parshape 1 161pt 301pt {}\save0\hbox{\lisp{}HARDRESET\rm{}}\noindent\ifdimen 1wd0>29pt{\hskip-33pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-33pt\box0\hskip0pt plus 1000pt minus 1000pt}}The process is deleted as usual if an error causes its form to be exited, but it \sl{}is\rm{} restarted on a \lisp{}HARDRESET\rm{}. This setting is preferred for persistent processes for which an error is an unusual condition, one that might repeat itself if the process were simply blindly restarted. \parshape 1 128pt 334pt {} \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}FORM\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value is the Lisp form used to start the process (readonly). \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}AFTEREXIT\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value indicates the disposition of the process following a resumption of Lisp after some exit (\lisp{}LOGOUT\rm{}, \lisp{}SYSOUT\rm{}, \lisp{}MAKESYS\rm{}). Possible values are: \vskip 10pt \vskip-10pt \parshape 1 161 pt 301pt {}\save0\hbox{\lisp{}DELETE\rm{}}\noindent\ifdimen 1wd0>29pt{\hskip-33pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-33pt\box0\hskip0pt plus 1000pt minus 1000pt}}Delete the process. \parshape 1 128pt 334pt {} \vskip 10pt \vskip-10pt \parshape 1 161pt 301pt {}\save0\hbox{\lisp{}SUSPEND\rm{}}\noindent\ifdimen 1wd0>29pt{\hskip-33pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-33pt\box0\hskip0pt plus 1000pt minus 1000pt}}Suspend the process; i.e., do not let it run until it is explicitly woken. \parshape 1 128pt 334pt {} \vskip 10pt \vskip-10pt \parshape 1 161pt 301pt {}\save0\hbox{<an event>}\noindent\ifdimen 1wd0>29pt{\hskip-33pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-33pt\box0\hskip0pt plus 1000pt minus 1000pt}}Cause the process to be suspended waiting for the event (page X.XX). \parshape 1 128pt 334pt {} \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128 pt 334pt {}\save0\hbox{\lisp{}INFOHOOK\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value is a function or form used to provide information about the process, in conjunction with the process status window (page X.XX). \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}WINDOW\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value is a window associated with the process, the process's {\lquotes}main{\rquotes} window. Used in conjunction with switching the tty process (page X.XX). \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}TTYENTRYFN\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value is a function that is applied to the process when the process is made the tty process (page X.XX). \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}TTYEXITFN\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Value is a function that is applied to the process when the process ceases to be the tty process (page X.XX). \parshape 1 92 pt 370pt {} \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(THIS.PROCESS)\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Returns the handle of the currently running process, or \lisp{}NIL\rm{} if the Process world is turned off. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(DEL.PROCESS \arg{}PROC {---}\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Deletes process \arg{}PROC\rm{}. \arg{}PROC\rm{} may be a process handle (returned by \lisp{}ADD.PROCESS\rm{}), or its name. Note that if \arg{}PROC\rm{} is the currently running process, \lisp{}DEL.PROCESS\rm{} does not return! \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESS.RETURN \arg{}VALUE\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Terminates the currently running process, causing it to {\lquotes}return{\rquotes} \arg{}VALUE\rm{}. There is an implicit \lisp{}PROCESS.RETURN\rm{} around the \arg{}FORM\rm{} argument given to \lisp{}ADD.PROCESS\rm{}, so that normally a process can finish by simply returning; \lisp{}PROCESS.RETURN\rm{} is supplied for earlier termination. \parshape 1 0 pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESS.RESULT \arg{}PROCESS WAITFORRESULT\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent If \arg{}PROCESS\rm{} has terminated, returns the value, if any, that it returned. This is either the value of a \lisp{}PROCESS.RETURN\rm{} or the value returned from the form given to \lisp{}ADD.PROCESS\rm{}. If the process was aborted, the value is \lisp{}NIL\rm{}. If \arg{}WAITFORRESULT\rm{} is true, \lisp{}PROCESS.RESULT\rm{} blocks until \arg{}PROCESS\rm{} finishes, if necessary; otherwise, it returns \lisp{}NIL\rm{} immediately if \arg{}PROCESS\rm{} is still running. Note that \arg{}PROCESS\rm{} must be the actual process handle returned from \lisp{}ADD.PROCESS\rm{}, not a process name, as the association between handle and name disappears when the process finishes (and the process handle itself is then garbage collected if no one else has a pointer to it). \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESS.FINISHEDP \arg{}PROCESS\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent True if \arg{}PROCESS\rm{} has terminated. The value returned is an indication of how it finished: \lisp{}NORMAL\rm{} or \lisp{}ERROR\rm{}. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESSP \arg{}PROC\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent True if \arg{}PROC\rm{} is the handle of an active process, i.e., one that has not yet finished. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(RELPROCESSP \arg{}PROCHANDLE\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92 pt 370pt {} \noindent True if \arg{}PROCHANDLE\rm{} is the handle of a deleted process. This is analogous to \lisp{}RELSTKP\rm{}. It differs from \lisp{}PROCESS.FINISHEDP\rm{} in that it never causes an error, while \lisp{}PROCESS.FINISHEDP\rm{} can cause an error if its \arg{}PROC\rm{} argument is not a process at all. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(RESTART.PROCESS \arg{}PROC\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Unwinds \arg{}PROC\rm{} to its top level and reevaluates its form. This is effectively a \lisp{}DEL.PROCESS\rm{} followed by the original \lisp{}ADD.PROCESS\rm{}. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(MAP.PROCESSES \arg{}MAPFN\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Maps over all processes, calling \arg{}MAPFN\rm{} with three arguments: the process handle, its name, and its form. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(FIND.PROCESS \arg{}PROC ERRORFLG\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent If \arg{}PROC\rm{} is a process handle or the name of a process, returns the process handle for it, else \lisp{}NIL\rm{}. If \arg{}ERRORFLG\rm{} is \lisp{}T\rm{}, generates an error if \arg{}PROC\rm{} is not, and does not name, a live process. \parshape 1 0 pt 462pt {} \vskip10pt \bf{}\noindent\save0\hbox{1.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Process Control Constructs \rm{}\penalty 2000 \penalty 2000 \mark{Process Control Constructs} \penalty 2000 \vskip10pt \penalty 2000 \vskip 10pt \formatdef{462pt}{\lisp{}(BLOCK \arg{}MSECSWAIT TIMER\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Yields control to the next waiting process, assuming any is ready to run. If \arg{}MSECSWAIT\rm{} is specified, it is a number of milliseconds to wait before returning (in which case \lisp{}BLOCK\rm{} is very much like \lisp{}DISMISS\rm{}), or \lisp{}T\rm{}, meaning wait forever (until explicitly woken). Alternatively, \arg{}TIMER\rm{} can be given as a millisecond timer (as returned by \lisp{}SETUPTIMER\rm{}) of an absolute time at which to wake up. In any of those cases, the process enters the \sl{}waiting\rm{} state until the time limit is up. \lisp{}BLOCK\rm{} with no arguments leaves the process in the \sl{}runnable\rm{} state, i.e., it returns as soon as every other runnable process of the same priority has had a chance. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(WAKE.PROCESS \arg{}PROC STATUS\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Explicitly wakes process \arg{}PROC\rm{}, i.e., makes it \sl{}runnable\rm{}, and causes its call to \lisp{}BLOCK\rm{} (or other waiting function) to return \arg{}STATUS\rm{}. This is one simple way to notify a process of some happening; however, note that if \lisp{}WAKE.PROCESS\rm{} is applied to a process more than once before the process actually gets its turn to run, it sees only the latest \arg{}STATUS\rm{}. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(SUSPEND.PROCESS \arg{}PROC\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Blocks process \arg{}PROC\rm{} indefinitely, i.e., \arg{}PROC\rm{} will not run until it is woken by a \lisp{}WAKE.PROCESS\rm{}. \parshape 1 0pt 462pt {} The following three functions allow access to the stack context of some other process. They require a little bit of care, and are computationally non-trivial, but they do provide a more powerful way of manipulating another process than \lisp{}WAKE.PROCESS\rm{} allows. \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESS.EVALV \arg{}PROC VAR\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92 pt 370pt {} \noindent Performs \lisp{}(EVALV \arg{}VAR\lisp{})\rm{} in the stack context of \arg{}PROC\rm{}. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESS.EVAL \arg{}PROC FORM WAITFORRESULT\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Evaluates \arg{}FORM\rm{} in the stack context of \arg{}PROC\rm{}. If \arg{}WAITFORRESULT\rm{} is true, blocks until the evaluation returns a result, else allows the current process to run in parallel with the evaluation. Any errors that occur will be in the context of \arg{}PROC\rm{}, so be careful. In particular, note that \lisp{}(PROCESS.EVAL \arg{}PROC\lisp{} '(NLSETQ (FOO)))\rm{} and \lisp{}(NLSETQ (PROCESS.EVAL \arg{}PROC\lisp{} '(FOO)))\rm{} behave quite differently if \lisp{}FOO\rm{} causes an error. And it is quite permissible to intentionally cause an error in proc by performing \lisp{}(PROCESS.EVAL \arg{}PROC\lisp{} '(ERROR!))\rm{} If errors are possible and \arg{}WAITFORRESULT\rm{} is true, the caller should almost certainly make sure that \arg{}FORM\rm{} traps the errors; otherwise the caller could end up waiting forever if \arg{}FORM\rm{} unwinds back into the pre-existing stack context of \arg{}PROC\rm{}. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESS.APPLY \arg{}PROC FN ARGS WAITFORRESULT\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Performs \lisp{}(APPLY \arg{}FN\lisp{} \arg{}ARGS\lisp{})\rm{} in the stack context of \arg{}PROC\rm{}. Note same warnings as with \lisp{}PROCESS.EVAL\rm{}. \parshape 1 0pt 462pt {} \vskip10pt \bf{}\noindent\save0\hbox{1.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Events \rm{}\penalty 2000 \penalty 2000 \mark{Events} \penalty 2000 \vskip10pt \penalty 2000 An {\lquotes}event{\rquotes} is a synchronizing primitive used to coordinate related processes, typically producers and consumers. Consumer processes can {\lquotes}wait{\rquotes} on events, and producers {\lquotes}notify{\rquotes} events. \vskip 10pt \formatdef{462pt}{\lisp{}(CREATE.EVENT \arg{}NAME\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Returns an instance of the \lisp{}EVENT\rm{} datatype, to be used as the event argument to functions listed below. \arg{}NAME\rm{} is arbitrary, and is used for debugging or status information. \parshape 1 0 pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(AWAIT.EVENT \arg{}EVENT TIMEOUT TIMERP\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Suspends the current process until \arg{}EVENT\rm{} is notified, or until a timeout occurs. If \arg{}TIMEOUT\rm{} is \lisp{}NIL\rm{}, there is no timeout. Otherwise, timeout is either a number of milliseconds to wait, or, if \arg{}TIMERP\rm{} is \lisp{}T\rm{}, a millisecond timer set to expire at the desired time using \lisp{}SETUPTIMER\rm{} (see page X.XX). \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(NOTIFY.EVENT \arg{}EVENT ONCEONLY\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent If there are processes waiting for \arg{}EVENT\rm{} to occur, causes those processes to be placed in the running state, with \arg{}EVENT\rm{} returned as the value from \lisp{}AWAIT.EVENT\rm{}. If \arg{}ONCEONLY\rm{} is true, only runs the first process waiting for the event (this should only be done if the programmer knows that there can only be one process capable of responding to the event at once). \parshape 1 0pt 462pt {} The meaning of an event is up to the programmer. In general, however, the notification of an event is merely a hint that something of interest to the waiting process has happened; the process should still verify that the conceptual event actually occurred. That is, \sl{}the process should be written so that it operates correctly even if woken up before the timeout and in the absence of the notified event.\rm{} In particular, the completion of \lisp{}PROCESS.EVAL\rm{} and related operations in effect wakes up the process in which they were performed, since there is no secure way of knowing whether the event of interest occurred while the process was busy performing the \lisp{}PROCESS.EVAL\rm{}. There is currently one class of system-defined events, used with the network code. Each Pup and NS socket has associated with it an event that is notified when a packet arrives on the socket; the event can be obtained by calling \lisp{}(PUPSOCKETEVENT \arg{}PUPSOCKET\lisp{})\rm{} or \lisp{}(NSOCKETEVENT \arg{}NSOCKET\lisp{})\rm{}, respectively. \vskip10pt \bf{}\noindent\save0\hbox{1.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Monitors \rm{}\penalty 2000 \penalty 2000 \mark{Monitors} \penalty 2000 \vskip10pt \penalty 2000 It is often the case that cooperating processes perform operations on shared structures, and some mechanism is needed to prevent more than one process from altering the structure at the same time. Some languages have a construct called a monitor, a collection of functions that access a common structure with mutual exclusion provided and enforced by the compiler via the use of monitor locks. Interlisp-D has taken this implementation notion as the basis for a mutual exclusion capability suitable for a dynamically-scoped environment. A monitorlock is an object created by the user and associated with (e.g., stored in) some shared structure that is to be protected from simultaneous access. To access the structure, a program waits for the lock to be free, then takes ownership of the lock, accesses the structure, then releases the lock. The functions and macros below are used: \vskip 10pt \formatdef{462pt}{\lisp{}(CREATE.MONITORLOCK \arg{}NAME {---}\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Returns an instance of the \lisp{}MONITORLOCK\rm{} datatype, to be used as the lock argument to functions listed below. \arg{}NAME\rm{} is arbitrary, and is used for debugging or status information. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(WITH.MONITOR \arg{}LOCK \lisp{}.\arg{} FORMS\lisp{})\arg{}\lisp{}\rm{}}{Macro} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92 pt 370pt {} \noindent Evaluates \lisp{}(PROGN . \arg{}FORMS\lisp{})\rm{} while owning \arg{}LOCK\rm{}. Value is the last of \arg{}FORMS\rm{}. This construct is implemented so that the lock is released even if the form is exited via error (currently implemented with \lisp{}RESETLST\rm{}). Ownership of a lock is dynamically scoped: if the current process already owns the lock (e.g., if the caller was itself inside a \lisp{}WITH.MONITOR\rm{} for this lock), \lisp{}WITH.MONITOR\rm{} is a noop. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(WITH.FAST.MONITOR \arg{}LOCK \lisp{}.\arg{} FORMS\lisp{})\arg{}\lisp{}\rm{}}{Macro} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Like \lisp{}WITH.MONITOR\rm{}, but implemented without the \lisp{}RESETLST\rm{}. User interrupts (e.g., control-E) are inhibited during the evaluation of \arg{}FORMS\rm{}. Programming restriction: the evaluation of \arg{}FORMS\rm{} must not error (the lock would not be released). This construct is mainly useful when \arg{}FORMS\rm{} is a small, safe computation that never errors and need never be interrupted. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(MONITOR.AWAIT.EVENT \arg{}RELEASELOCK EVENT TIMEOUT TIMERP\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent For use in blocking inside a monitor. Performs \lisp{}(AWAIT.EVENT \arg{}EVENT\lisp{} \arg{}TIMEOUT\lisp{} \arg{}TIMERP\lisp{})\rm{}, but releases \arg{}RELEASELOCK\rm{} first, and reobtains the lock (possibly waiting) on wakeup. \parshape 1 0pt 462pt {} Typical use for \lisp{}MONITOR.AWAIT.EVENT\rm{}: A function wants to perform some operation on \arg{}Foo\rm{}, but only if it is in a certain state. It has to obtain the lock on the structure to make sure that the state of the structure does not change between the time it tests the state and performs the operation. If the state turns out to be bad, it then waits for some other process to make the state good, meanwhile releasing the lock so that the other process can alter the structure. \lisp{}{\nofill{}(WITH.MONITOR \arg{}FooLock\lisp{} (until \arg{}condition-of-Foo\lisp{} do (MONITOR.AWAIT.EVENT \arg{}FooLock\lisp{} \arg{}EventFooChanged\lisp{} \arg{}timeout\lisp{})) \arg{}operate-on-Foo\lisp{})\par}\rm{} It is sometimes convenient for a process to have \lisp{}WITH.MONITOR\rm{} at its top level and then do all its interesting waiting using \lisp{}MONITOR.AWAIT.EVENT\rm{}. Not only is this often cleaner, but in the present implementation in cases where the lock is frequently accessed, it saves the \lisp{}RESETLST\rm{} overhead of \lisp{}WITH.MONITOR\rm{}. Programming restriction: there must not be an \lisp{}ERRORSET\rm{} between the enclosing \lisp{}WITH.MONITOR\rm{} and the call to \lisp{}MONITOR.AWAIT.EVENT\rm{} such that the \lisp{}ERRORSET\rm{} would catch an \lisp{}ERROR!\rm{} and continue inside the monitor, for the lock would not have been reobtained. (The reason for this restriction is that, although \lisp{}MONITOR.AWAIT.EVENT\rm{} won't itself error, the user could have caused an error with an interrupt, or a \lisp{}PROCESS.EVAL\rm{} in the context of the waiting process that produced an error.) On rare occasions it may be useful to manipulate monitor locks directly. The following two functions are used in the implementation of \lisp{}WITH.MONITOR\rm{}: \vskip 10pt \formatdef{462pt}{\lisp{}(OBTAIN.MONITORLOCK \arg{}LOCK DONTWAIT UNWINDSAVE\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Takes possession of \arg{}LOCK\rm{}, waiting if necessary until it is free, unless \arg{}DONTWAIT\rm{} is true, in which case it returns \lisp{}NIL\rm{} immediately. If \arg{}UNWINDSAVE\rm{} is true, performs a \lisp{}RESETSAVE\rm{} to be unwound when the enclosing \lisp{}RESETLST\rm{} exits. Returns \arg{}LOCK\rm{} if \arg{}LOCK\rm{} was successfully obtained, \lisp{}T\rm{} if the current process already owned \arg{}LOCK\rm{}. \parshape 1 0 pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(RELEASE.MONITORLOCK \arg{}LOCK\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Releases \arg{}LOCK\rm{} if it is owned by the current process, and wakes up the next process, if any, waiting to obtain the lock. \parshape 1 0pt 462pt {} When a process is deleted, any locks it owns are released. \vskip10pt \bf{}\noindent\save0\hbox{1.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Global Resources \rm{}\penalty 2000 \penalty 2000 \mark{Global Resources} \penalty 2000 \vskip10pt \penalty 2000 The biggest source of problems in the multi-processing environment is the matter of global resources. Two processes cannot both use the same global resource if there can be a process switch in the middle of their use (currently this means calls to \lisp{}BLOCK\rm{}, but ultimately with a preemptive scheduler means anytime). Thus, user code should be wary of its own use of global variables, if it ever makes sense for the code to be run in more than one process at a time. {\lquotes}State{\rquotes} variables private to a process should generally be bound in that process; structures that are shared among processes (or resources used privately but expensive to duplicate per process) should be protected with monitor locks or some other form of synchronization. Aside from user code, however, there are many \sl{}system\rm{} global variables and resources. Most of these arise historically from the single-process Interlisp-10 environment, and will eventually be changed in Interlisp-D to behave appropriately in a multi-processing environment. Some have already been changed, and are described below. Two other resources not generally thought of as global variables{---}the keyboard and the mouse{---}are particularly idosyncratic, and are discussed in the next section. The following resources, which are global in Interlisp-10, are allocated per process in Interlisp-D: primary input and output (the streams affected by \lisp{}INPUT\rm{} and \lisp{}OUTPUT\rm{}), terminal input and output (the streams designated by the name \lisp{}T\rm{}), the primary read table and primary terminal table, and dribble files. Thus, each process can print to its own primary output, print to the terminal, read from a different primary input, all without interfering with another process's reading and printing. Each process begins life with its primary and terminal input{\char'57}output streams set to a dummy stream. If the process attempts input or output using any of those dummy streams, e.g., by calling \lisp{}(READ T)\rm{}, or \lisp{}(PRINT & T)\rm{}, a tty window is automatically created for the process, and that window becomes the primary input{\char'57}output and terminal input{\char'57}output for the process. The default tty window is created at or near the region specified in the variable \lisp{}DEFAULTTTYREGION\rm{}. A process can, of course, call \lisp{}TTYDISPLAYSTREAM\rm{} explicitly to give itself a tty window of its own choosing, in which case the automatic mechanism never comes into play. Calling \lisp{}TTYDISPLAYSTREAM\rm{} when a process has no tty window not only sets the terminal streams, but also sets the primary input and output streams to be that window, assuming they were still set to the dummy streams. \vskip 10pt \formatdef{462pt}{\lisp{}(HASTTYWINDOWP \arg{}PROC\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Returns \lisp{}T\rm{} if the process \arg{}PROC\rm{} has a tty window; \lisp{}NIL\rm{} otherwise. If \arg{}PROC\rm{} is \lisp{}NIL\rm{}, it defaults to the current process. \parshape 1 0pt 462pt {} Other system resources that are typically changed by \lisp{}RESETFORM\rm{}, \lisp{}RESETLST\rm{}, \lisp{}RESETVARS\rm{} are all global entities. In the multiprocessing environment, these constructs are suspect, as there is no provision for {\lquotes}undoing{\rquotes} them when a process switch occurs. For example, in the current release of Interlisp-D, it is not possible to set the print radix to 8 inside only one process, as the print radix is a global entity. Note that \lisp{}RESETFORM\rm{} and similar expressions are perfectly valid in the process world, and even quite useful, when they manipulate things strictly within one process. The process world is arranged so that deleting a process also unwinds any \lisp{}RESETxxx\rm{} expressions that were performed in the process and are still waiting to be unwound, exactly as if a control-D had reset the process to the top. Additionally, there is an implicit \lisp{}RESETLST\rm{} at the top of each process, so that \lisp{}RESETSAVE\rm{} can be used as a way of providing {\lquotes}cleanup{\rquotes} functions for when a process is deleted. For these, the value of \lisp{}RESETSTATE\rm{} (page X.XX) is \lisp{}NIL\rm{} if the process finished normally, \lisp{}ERROR\rm{} if it was aborted by an error, \lisp{}RESET\rm{} if the process was explicitly deleted, and \lisp{}HARDRESET\rm{} if the process is being restarted (after a \lisp{}HARDRESET\rm{} or a \lisp{}RESTART.PROCESS\rm{}). \vskip10pt \bf{}\noindent\save0\hbox{1.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Typein and the TTY Process \rm{}\penalty 2000 \penalty 2000 \mark{Typein and the TTY Process} \penalty 2000 \vskip10pt \penalty 2000 There is one global resource, the keyboard, that is particularly problematic to share among processes. Consider, for example, having two processes both performing \lisp{}(READ T)\rm{}. Since the keyboard input routines block while there is no input, both processes would spend most of their time blocking, and it would simply be a matter of chance which process received each character of typein. To resolve such dilemmas, the system designates a distinguished process, termed the \sl{}tty process\rm{}, that is assumed to be the process that is involved in terminal interaction. Any typein from the keyboard goes to that process. If a process other than the tty process requests keyboard input, it blocks until it becomes the tty process. When the tty process is switched (in any of the ways described further below), any typeahead that occurred before the switch is saved and associated with the current tty process. Thus, it is always the case that keystrokes are sent to the process that is the tty process at the time of the keystrokes, regardless of when that process actually gets around to reading them. It is less immediately obvious how to handle keyboard interrupt characters, as their action is asynchronous and not always tied to typein. Interrupt handling is described on page X.XX. \vskip10pt \bf{}\noindent\save0\hbox{1.6.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Switching the TTY Process \rm{}\penalty 2000 \penalty 2000 \mark{Switching the TTY Process} \penalty 2000 \vskip10pt \penalty 2000 Any process can make itself be the tty process by calling \lisp{}TTY.PROCESS\rm{}. \vskip 10pt \formatdef{462pt}{\lisp{}(TTY.PROCESS \arg{}PROC\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Returns the handle of the current tty process. In addition, if \arg{}PROC\rm{} is non-\lisp{}NIL\rm{}, makes it be the tty process. The special case of \arg{}PROC\rm{} = \lisp{}T\rm{} is interpreted to mean the executive process; this is sometimes useful when a process wants to explicitly give up being the tty process. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(TTY.PROCESSP \arg{}PROC\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92 pt 370pt {} \noindent True if \arg{}PROC\rm{} is the tty process; \arg{}PROC\rm{} defaults to the running process. Thus, \lisp{}(TTY.PROCESSP)\rm{} is true if the caller is the tty process. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(WAIT.FOR.TTY)\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Efficiently waits until \lisp{}(TTY.PROCESSP)\rm{} is true. \lisp{}WAIT.FOR.TTY\rm{} is called internally by the system functions that read from the terminal; user code thus need only call it in special cases. \parshape 1 0pt 462pt {} In some cases, such as in functions invoked as a result of mouse action or a user's typed-in call, it is reasonable for the function to invoke \lisp{}TTY.PROCESS\rm{} itself so that it can take subsequent user type in. In other cases, however, this is too undisciplined; it is desirable to let the user designate which process typein should be directed to. This is most conveniently done by mouse action. The system supports the model that {\lquotes}to type to a process, you click in its window.{\rquotes} To cooperate with this model, any process desiring keyboard input should put its process handle as the \lisp{}PROCESS\rm{} property of its window(s). To handle the common case, the function \lisp{}TTYDISPLAYSTREAM\rm{} does this automatically when the ttydisplaystream is switched to a new window. A process can own any number of windows; clicking in any of those windows gives the process the tty. This mechanism suffices for most casual process writers. For example, if a process wants all its input{\char'57}output interaction to occur in a particular window that it has created, it should just make that window be its tty window by calling \lisp{}TTYDISPLAYSTREAM\rm{}. Thereafter, it can \lisp{}PRINT\rm{} or \lisp{}READ\rm{} to{\char'57}from the \lisp{}T\rm{} stream; if the process is not the tty process at the time that it calls \lisp{}READ\rm{}, it will block until the user clicks in the window. For those needing tighter control over the tty, the default behavior can be overridden or supplemented. The remainder of this section describes the mechanisms involved. There is a window property \lisp{}WINDOWENTRYFN\rm{} that controls whether and how to switch the tty to the process owning a window. The mouse handler, before invoking any normal \lisp{}BUTTONEVENTFN\rm{}, specifically notices the case of a button going down in a window that belongs to a process (i.e., has a \lisp{}PROCESS\rm{} window property) that is not the tty process. In this case, it invokes the window's \lisp{}WINDOWENTRYFN\rm{} of one argument (\arg{}WINDOW\rm{}). \lisp{}WINDOWENTRYFN\rm{} defaults to \lisp{}GIVE.TTY.PROCESS\rm{}: \vskip 10pt \formatdef{462pt}{\lisp{}(GIVE.TTY.PROCESS \arg{}WINDOW\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent If \arg{}WINDOW\rm{} has a \lisp{}PROCESS\rm{} property, performs \lisp{}(TTY.PROCESS (WINDOWPROP \arg{}WINDOW\lisp{} 'PROCESS))\rm{} and then invokes \arg{}WINDOW\rm{}'s \lisp{}BUTTONEVENTFN\rm{} function (or \lisp{}RIGHTBUTTONFN\rm{} if the right button is down). \parshape 1 0pt 462pt {} There are some cases where clicking in a window does not always imply that the user wants to talk to that window. For example, clicking in a text editor window with a shift key held down means to {\lquotes}shift-select{\rquotes} some piece of text into the input buffer of the \sl{}current\rm{} tty process. The editor supports this by supplying a \lisp{}WINDOWENTRYFN\rm{} that performs \lisp{}GIVE.TTY.PROCESS\rm{} if no shift key is down, but goes into its shift-select mode, without changing the tty process, if a shift key is down. The shift-select mode performs a \lisp{}BKSYSBUF\rm{} of the selected text when the shift key is let up, the \lisp{}BKSYSBUF\rm{} feeding input to the current tty process. Sometimes a process wants to be notified when it becomes the tty process, or stops being the tty process. For example, Chat (page X.XX) turns off all keyboard interrupt characters while it is the tty process, so that they can be passed transparently to the remote host. To support this, there are two process properties, \lisp{}TTYEXITFN\rm{} and \lisp{}TTYENTRYFN\rm{}. The actions taken by \lisp{}TTY.PROCESS\rm{} when it switches the tty to a new process are as follows: the former tty process's \lisp{}TTYEXITFN\rm{} is called with two arguments (\arg{}OLDTTYPROCESS\rm{} \arg{}NEWTTYPROCESS\rm{}); the new process is made the tty process; finally, the new tty process's \lisp{}TTYENTRYFN\rm{} is called with two arguments (\arg{}NEWTTYPROCESS\rm{} \arg{}OLDTTYPROCESS\rm{}). Normally the \lisp{}TTYENTRYFN\rm{} and \lisp{}TTYEXITFN\rm{} need only their first argument, but the other process involved in the switch is supplied for completeness. In the present system, most processes want to interpret the keyboard in the same way, so it is considered the responsibility of any process that changes the keyboard interpretation to restore it to the normal state by its \lisp{}TTYEXITFN\rm{}. A window is {\lquotes}owned{\rquotes} by the last process that anyone gave as the window's \lisp{}PROCESS\rm{} property. Ordinarily there is no conflict here, as processes tend to own disjoint sets of windows (though, of course, cooperating processes can certainly try to confuse each other). The only likely problem arises with that most global of windows, \lisp{}PROMPTWINDOW\rm{}. Programs should not be tempted to read from \lisp{}PROMPTWINDOW\rm{}. This is not usually necessary anyway, as the first attempt to read from \lisp{}T\rm{} in a process that has not set its \lisp{}TTYDISPLAYSTREAM\rm{} to its own window causes a tty window to be created for the process (see page X.XX). \vskip10pt \bf{}\noindent\save0\hbox{1.6.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Handling of Interrupts \rm{}\penalty 2000 \penalty 2000 \mark{Handling of Interrupts} \penalty 2000 \vskip10pt \penalty 2000 At the time that a keyboard interrupt character (page X.XX) is struck, any process could be running, and some decision must be made as to which process to actually interrupt. To the extent that keyboard interrupts are related to typein, most interrupts are taken in the tty process; however, the following are handled specially: \vskip 10pt \vskip-10pt \parshape 1 69pt 393pt {}\save0\hbox{\lisp{}RESET\rm{}, \lisp{}ERROR\rm{}}\noindent\ifdimen 1wd0>62pt{\hskip-69pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-69pt\box0\hskip0pt plus 1000pt minus 1000pt}}(normally control-D and control-E) These interrupts are taken in the mouse process, if the mouse is not in its idle state; otherwise they are taken in the tty process. Thus, control-E can be used to abort some mouse-invoked window action, such as the Shape command. As a consequence, note that if the mouse invokes some lengthy computation that the user thinks of as {\lquotes}background{\rquotes}, control-E still aborts it, even though that may not have been what the user intended. Such lengthy computations, for various reasons, should generally be performed by spawning a separate process to perform them. The \lisp{}RESET\rm{} interrupt in a process other than the executive is interpreted exactly as if an error unwound the process to its top level: if the process was designated \lisp{}RESTARTABLE\rm{} = \lisp{}T\rm{}, it is restarted; otherwise it is killed. \parshape 1 0 pt 462pt {} \vskip 10pt \vskip-10pt \parshape 1 69pt 393pt {}\save0\hbox{\lisp{}HELP\rm{}}\noindent\ifdimen 1wd0>62pt{\hskip-69pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-69pt\box0\hskip0pt plus 1000pt minus 1000pt}}(Initially control-H) A menu of processes is presented to the user, who is asked to select which one the interrupt should occur in. The current tty process appears with a * next to its name at the top of the menu. The menu also includes an entry {\lquotes}[Spawn Mouse]{\rquotes}, for the common case of needing a mouse because the mouse process is currently tied up running someone's \lisp{}BUTTONEVENTFN\rm{}; selecting this entry spawns a new mouse process, and no break occurs. \parshape 1 0pt 462pt {} \vskip 10pt \vskip-10pt \parshape 1 69pt 393pt {}\save0\hbox{\lisp{}BREAK\rm{}}\noindent\ifdimen 1wd0>62pt{\hskip-69pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-69pt\box0\hskip0pt plus 1000pt minus 1000pt}}(Initially control-B) Performs the \lisp{}HELP\rm{} interrupt always in the tty process. \parshape 1 0pt 462pt {} \vskip 10pt \vskip-10pt \parshape 1 69pt 393pt {}\save0\hbox{\lisp{}RUBOUT\rm{}}\noindent\ifdimen 1wd0>62pt{\hskip-69pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-69pt\box0\hskip0pt plus 1000pt minus 1000pt}}(Initially <del>) This interrupt clears typeahead in \sl{}all\rm{} processes. \parshape 1 0pt 462pt {} \vskip 10pt \vskip-10pt \parshape 1 69 pt 393pt {}\save0\hbox{\lisp{}RAID\rm{}, \lisp{}STACK OVERFLOW\rm{}, \lisp{}STORAGE FULL\rm{}}\noindent\ifdimen 1wd0>62pt{\hskip-69pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-69pt\box0\hskip0pt plus 1000pt minus 1000pt}}These interrupts always occur in whatever process was running at the time the interrupt struck. In the cases of \lisp{}STACK OVERFLOW\rm{} and \lisp{}STORAGE FULL\rm{}, this means that the interrupt is more likely to strike in the offending process (especially if it is a {\lquotes}runaway{\rquotes} process that is not blocking). Note, however, that this process is still not necessarily the guilty party; it could be an innocent bystander that just happened to use up the last of a resource prodigiously consumed by some other process. \parshape 1 0pt 462pt {} \vskip10pt \bf{}\noindent\save0\hbox{1.7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Keeping the Mouse Alive \rm{}\penalty 2000 \penalty 2000 \mark{Keeping the Mouse Alive} \penalty 2000 \vskip10pt \penalty 2000 Since the window mouse handler runs in its own process, it is not available while a window's \lisp{}BUTTONEVENTFN\rm{} function (or any of the other window functions invoked by mouse action) is running. This leads to two sorts of problems: (1) a long computation underneath a \lisp{}BUTTONEVENTFN\rm{} deprives the user of the mouse for other purposes, and (2) code that runs as a \lisp{}BUTTONEVENTFN\rm{} cannot rely on other \lisp{}BUTTONEVENTFN\rm{}s running, which means that there some pieces of code that run differently from normal when run under the mouse process. These problems are addressed by the following functions: \vskip 10pt \formatdef{462pt}{\lisp{}(SPAWN.MOUSE \arg{}{---}\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Spawns another mouse process, allowing the mouse to run even if it is currently {\lquotes}tied up{\rquotes} under the current mouse process. This function is intended mainly to be typed in at the Lisp executive when the user notices the mouse is busy. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(ALLOW.BUTTON.EVENTS)\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Performs a \lisp{}(SPAWN.MOUSE)\rm{} only when called underneath the mouse process. This should be called (once, on entry) by any function that relies on \lisp{}BUTTONEVENTFN\rm{}s for completion, if there is any possibility that the function will itself be invoked by a mouse function. \parshape 1 0pt 462pt {} It never hurts, at least logically, to call \lisp{}SPAWN.MOUSE\rm{} or \lisp{}ALLOW.BUTTON.EVENTS\rm{} needlessly, as the mouse process arranges to quietly kill itself if it returns from the user's \lisp{}BUTTONEVENTFN\rm{} and finds that another mouse process has sprung up in the meantime. (There is, of course, some computational expense.) \vskip10pt \bf{}\noindent\save0\hbox{1.8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Debugging Processes \rm{}\penalty 2000 \penalty 2000 \mark{Debugging Processes} \penalty 2000 \vskip10pt \penalty 2000 \vskip 10pt \formatdef{462pt}{\lisp{}(PROCESS.STATUS.WINDOW \arg{}WHERE\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Puts up a window that provides several debugging commands for manipulating running processes. If the window is already up, \lisp{}PROCESS.STATUS.WINDOW\rm{} refreshes it. If \arg{}WHERE\rm{} is a position, the window is placed in that position; otherwise, the user is prompted for a position. The window consists of two menus. The first is a menu of all the processes at the moment. Commands in the second menu operate on the process selected in the first menu. The commands are: \vskip 10pt \vskip-10pt \parshape 1 128 pt 334pt {}\save0\hbox{\lisp{}BT\rm{}, \lisp{}BTV\rm{}, \lisp{}BTV*\rm{}, \lisp{}BTV!\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Performs a backtrace of the selected process. The first time, it prompts for a window in which to display the backtrace. \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}WHO?\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Changes the selection to the tty process, i.e., the one currently in control of the keyboard. \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}KBD{\char'137}\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Associates the keyboard with the selected process; i.e., makes the selected process be the tty process. \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}INFO\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}If the selected process has an \lisp{}INFOHOOK\rm{}, calls it. The hook may be a function, which is then applied to two arguments, the process and the button (\lisp{}LEFT\rm{} or \lisp{}MIDDLE\rm{}) used to invoke \lisp{}INFO\rm{}, or a form, which is simply \lisp{}EVAL\rm{}'ed. The \lisp{}APPLY\rm{} or \lisp{}EVAL\rm{} happens in the context of the selected process, using \lisp{}PROCESS.APPLY\rm{} or \lisp{}PROCESS.EVAL\rm{}. The info hook can be set using \lisp{}PROCESSPROP\rm{}. \parshape 1 92 pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}KILL\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Deletes the selected process. \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}RESTART\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Restarts the selected process. \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}WAKE\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Wakes the selected process. Prompts for a value to wake it with (see \lisp{}WAKE.PROCESS\rm{}). \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128 pt 334pt {}\save0\hbox{\lisp{}SUSPEND\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Suspends the selected process; i.e., causes it to block indefinitely (until explicitly woken). \parshape 1 92pt 370pt {} \vskip 10pt \vskip-10pt \parshape 1 128pt 334pt {}\save0\hbox{\lisp{}BREAK\rm{}}\noindent\ifdimen 1wd0>32pt{\hskip-36pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-36pt\box0\hskip0pt plus 1000pt minus 1000pt}}Enter a break under the selected process. This has the side effect of waking the process with the value returned from the break. \parshape 1 92pt 370pt {} \parshape 1 0pt 462pt {} Currently, the process status window runs under the mouse process, like other menus, so if the mouse is unavailable (e.g., a mouse function is performing an extensive computation), you may be unable to use the process status window (you can try \lisp{}SPAWN.MOUSE\rm{}, of course). \vskip10pt \bf{}\noindent\save0\hbox{1.9}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Non-Process Compatibility \rm{}\penalty 2000 \penalty 2000 \mark{Non-Process Compatibility} \penalty 2000 \vskip10pt \penalty 2000 This section describes some considerations for authors of programs that ran in the old single-process Interlisp-D environment, and now want to make sure they run properly in the Multi-processing world. The biggest problem to watch out for is code that runs underneath the mouse handler. Writers of mouse handler functions should remember that in the process world the mouse handler runs in its own process, and hence (a) you cannot depend on finding information on the stack (stash it in the window instead), and (b) while your function is running, the mouse is not available (if you have any non-trivial computation to do, spawn a process to do it, notify one of your existing processes to do it, or use \lisp{}PROCESS.EVAL\rm{} to run it under some other process). The following functions are meaningful even if the process world is not on: \lisp{}BLOCK\rm{} (invokes the system background routine, which includes handling the mouse); \lisp{}TTY.PROCESS\rm{}, \lisp{}THIS.PROCESS\rm{} (both return \lisp{}NIL\rm{}); and \lisp{}TTY.PROCESSP\rm{} (returns \lisp{}T\rm{}, i.e., anyone is allowed to take tty input). In addition, the following two functions exist in both worlds: \vskip 10pt \formatdef{462pt}{\lisp{}(EVAL.AS.PROCESS \arg{}FORM\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92pt 370pt {} \noindent Same as \lisp{}(ADD.PROCESS \arg{}FORM\lisp{} 'RESTARTABLE 'NO)\rm{}, when processes are running, \lisp{}EVAL\rm{} when not. This is highly recommended for mouse functions that perform any non-trivial activity. \parshape 1 0pt 462pt {} \vskip 10pt \formatdef{462pt}{\lisp{}(EVAL.IN.TTY.PROCESS \arg{}FORM WAITFORRESULT\lisp{})\arg{}\lisp{}\rm{}}{Function} \penalty 2000\vskip-10pt\penalty 2000 \parshape 1 92 pt 370pt {} \noindent Same as \lisp{}(PROCESS.EVAL (TTY.PROCESS) \arg{}FORM\lisp{} \arg{}WAITFORRESULT\lisp{})\rm{}, when processes are running, \lisp{}EVAL\rm{} when not. \parshape 1 0pt 462pt {} Most of the process functions that do not take a process argument can be called even if processes aren't running. \lisp{}ADD.PROCESS\rm{} creates, but does not run, a new process (it runs when \lisp{}PROCESSWORLD\rm{} is called). \vfill\end