5 The Multitasking Facility

5.5 Reference pages

*all-processes* Variable

Syntax:*all-processes*

The variable*all-processes* contains a list of all the processes that currently exist.

You must not change the value of this variable.

> *all-processes*
(#<Process Initial 79F40B> #<Process Idle 79F463>)

check-stack-remaining Function

Syntax:check-stack-remaining words

The functioncheck-stack-remaining checks the remaining stack space. If there are fewer words of stack space remaining than are specified, the function creates a new process and enters the Debugger in that process.

The words argument specifies the number of 32-bit words of stack space that the process needs.

You can use the functionget-stack-remaining to find the number of words of remaining stack space on the current process's stack.

> (check-stack-remaining 100) 
NIL 

> (check-stack-remaining 10000000) ; an absurdly large number >>Error: #<Process Initial 6D0123> couldn't obtain needed 10000000 words of stack-space INVOKE-DEBUGGER: Required arg 0 (CONDITION): #<Condition SIMPLE-ERROR 92BD7B> 0: Abort to top level in #<Process Initial 6D0123> 1: Enter debugger in #<Process Initial 6D0123>; clobber more stack space 2: Kill process #<Process Stack problems 92BAB3> 3: Restart process #<Process Stack problems 92BAB3>

-> 0 Abort to top level in #<Process Initial 6D0123> Back to Lisp Top Level

See Also: get-stack-remaining

*current-process* Variable

Syntax: *current-process*

The variable*current-process* contains the process that is currently running.

When a process is waiting because it has calledprocess-wait or process-wait-with-timeout, the process's wait function is always evaluated with*current-process* bound to the waiting process.

You must not change the value of this variable.

> *current-process*
#<Process Initial 79F40B>

> (defun newtask () (setq *temp* *current-process*)) NEWTASK

> (make-process :name "Newtask" :function 'newtask :stack-size 1000) #<Process Newtask 79FBE3>

> *temp* #<Process Newtask 79FBE3>

deactivate-process Function

activate-process Function

Syntax:deactivate-process process

Syntax:activate-process process

The functiondeactivate-process prevents a specified process from running until the functionactivate-process is invoked with the process as an argument.

The functionactivate-process allows a process to run that has been stopped by a call todeactivate-process.

The process argument specifies the process that is allowed to run or that is prevented from running. Both functions return the process argument as a result.

A process is activated by default when it is created.

> (defvar *wake-up-subprocess* nil)
*WAKE-UP-SUBPROCESS*

> (defun work () (loop (process-wait "Wakeup call" 'symbol-value '*wake-up-subprocess*) (format t "I am awake.~%") (setf *wake-up-subprocess* nil))) WORK

> (setf subprocess (make-process :name "example" :function 'work)) #<Process example 61353B>

> (setf *wake-up-subprocess* t) T I am awake.

> (deactivate-process subprocess) #<Process example 61353B>

> (setf *wake-up-subprocess* t) T

> (activate-process subprocess) #<Process example 61353B> I am awake.

get-stack-remaining Function

Syntax:get-stack-remaining&optional stack-group

The functionget-stack-remaining returns the number of words of stack space that can be used before the stack will overflow.

One memory segment contains 64 kilobytes, or 16,384 words.

See Also: check-stack-remaining

*inhibit-scheduling* Variable

Syntax:*inhibit-scheduling*

The value of the variable*inhibit-scheduling* ist if process switching is currently inhibited; otherwise, it isnil.

The functionswith-scheduling-inhibited andwith-scheduling-allowed prevent and allow the scheduler to switch processes respectively.

You must not change the value of this variable.

> *inhibit-scheduling*
NIL

> (with-scheduling-inhibited *inhibit-scheduling*) T

See Also: with-scheduling-inhibited, with-scheduling-allowed

*initial-io* Variable

Syntax:*initial-io*

The variable*initial-io* stores the value of the stream that communicates with the user when normal stream input and output has failed or when the scheduler encounters an internal error. This stream must be able to work without scheduling. Generally, the interaction stream that was opened when Lisp started up is used.

> (eq *initial-io* *terminal-io*)
T

> *initial-io* #<Stream SPLIT-STREAM 69DA3B>

See Also: using-initial-io

*initial-process* Variable

Syntax:*initial-process*

The variable*initial-process* contains the initial process, which is the process that exists when Lisp is first started.

You cannot kill or restart the initial process. You must not change the value of this variable.

> *initial-process*
#<Process Initial 79F40B>

interrupt-process Function

Syntax:interrupt-process process function&rest args

The functioninterrupt-process interrupts the execution of a specified process and invokes a specified function. The process resumes its previous computation when the interruption returns.

The process argument specifies the process that is interrupted; it is returned as the value ofinterrupt-process.

The function argument specifies the function that is invoked, which is called an interruption. The function is applied to args the next time that the specified process is scheduled; the process is not allowed to complete computation. The process resumes computation if the interruption returns.

Interruptions are implicitly run with interruptions inhibited. Thus, no other interruption can run on this process until one of the following events occurs:

If the specified process is waiting because of a call toprocess-wait or to a related function, the process wakes up to perform the interruption. If the interruption exits normally, the process resumes waiting. If the interruption performs athrow to a tag outside ofprocess-wait, the process performs the throw normally and does not return to its waiting state.

> (defun sleep-until-throw () 
      (catch 'wakeup 
             (process-wait-forever "Asleep"))) 
SLEEP-UNTIL-THROW 

> (setf sleeper (make-process :name "sleeper" :function 'sleep-until-throw)) #<Process sleeper 6C3DFB>

> (process-whostate sleeper) "Asleep" (progn (interrupt-process sleeper #'(lambda () (format t "I am process ~A~%" *current-process*))) (sleep 5)) I am process #<Process sleeper 6C3DFB> NIL

> (process-whostate sleeper) "Asleep"

> (interrupt-process sleeper #'(lambda () (throw 'wakeup nil))) #<Process sleeper 6C3DFB>

> (process-whostate sleeper) "Dead"

See Also: with-interruptions-allowed,with-interruptions-inhibited

*keyboard-interrupt-process* Variable

Syntax:*keyboard-interrupt-process*

The variable*keyboard-interrupt-process* contains the process that should receive the interruption when a keyboard interrupt character is typed.

The default value of this variable is the initial process, but you can set the value to any process. The macro with-keyboard-interrupt changes the value of the interrupt process during the execution of the specified forms.

If you type a second interrupt character before the interrupt process has entered the Debugger, the Multitasking Facility starts a new process that immediately enters the Debugger by using the initial I/O stream. This behavior is a special case; you would only need to type a second interrupt character if the process is stuck and cannot enter the Debugger on its own.

> *keyboard-interrupt-process* 
#<Process Initial 6A219B>
See Also: with-keyboard-interrupt-process

kill-process Function

Syntax:kill-process process&key :suppress-unwind-protects

By default, the functionkill-process runs the specified process, executes cleanup forms, kills the process, and returns its resources. The process cannot be restarted.

The process argument specifies the process that is killed, which is returned as the value ofkill-process.

If the value of the:suppress-unwind-protects keyword argument isnil, cleanup forms inside of the process that are introduced by the Common Lisp special formunwind-protect are executed before the process is killed; this value is the default.

If the keyword argument has a non-nil value, the function kills the specified process without running it and disposes of its resources immediately. This method of killing a process is dangerous and should only be used as a last resort when a more reasonable method will not work. Files in the process are not closed, locks are not released, and all other details of process cleanup are lost forever.

It is an error to activate, deactivate, or interrupt a process that has been killed.

> (defun job () 
        (unwind-protect 
             (process-wait-forever) 
        (format t "Unwind the stack of process ~A~%" 
                                *current-process*))) 
JOB 

> (setf job1 (make-process :name "job1" :function 'job)) #<Process job1 6C239B>

> (progn (kill-process job1) (process-allow-schedule)) Unwind the stack of process #<Process job1 6C239B> T

> (setf job2 (make-process :name "job2" :function 'job)) #<Process job2 6C265B>

> (progn (kill-process job2 :suppress-unwind-protects t) (process-allow-schedule)) T

let-globally Macro

Syntax:let-globally ({var | (var value)}*) {declaration}* {form}*

The macrolet-globally creates new variables and then uses the Common Lisp special formsetq to set the values of those variables. It executes a series of forms and then uses the special formunwind-protect to restore the variable bindings that were in effect before the macro call.

The value arguments are evaluated first, in the order in which they are given. The var arguments are then set to the corresponding values in parallel. If you do not specify a value for a given var argument, that var is bound tonil. If you use the list (var value) but do not specify a value for the var argument, a warning is signaled.

The form arguments are executed in order. The result returned bylet-globally is the value or values returned by the last form that is executed. If there are no form arguments,nil is returned.

The declaration arguments specify declarations that are made with the Common Lisp special formdeclare.

The variable bindings are set rather than dynamically bound; thus, the bindings are available to other processes. However, any variables that are bound in the current process are changed locally. Thus, the new values are not visible to other processes.

> (defparameter *a* 100)
*A*
> (defun work ()
    (let-globally ((*a* 120))
      (process-wait-forever)))
WORK

> (setq subprocess (make-process :name "work" :function 'work)) #<Process work 615BF3>

> *a* 120

> (kill-process subprocess) #<Process work 615BF3>

> *a* 100

make-process Function

Syntax:make-process&key :name :function :args :stack-size :priority :wait-function :wait-args :restart-action

The functionmake-process creates and returns a process.

You can specify the following keyword options tomake-process:

This keyword argument must be a string.

This keyword argument is a function, called the initial function, that starts up the process. You must specify this keyword argument.

This keyword argument is list of arguments to the initial function.

This keyword argument is the maximum number of words in the stack for this process. If the process exceeds the specified stack size, the results are unpredictable. If this keyword argument is omitted ornil, the default stack size is 5000 32-bit words.

This keyword argument specifies the priority ranking of a process. The default value is 100. Smaller values mean that a process has greater priority. These values are absolute; that is, a process's priority does not increase or decrease over time.

This keyword argument specifies the wait function that is used by the scheduler to test whether the process should run. The wait function must return a non-nil value when applied to its arguments before the scheduler can run the process associated with it. If this keyword argument is omitted, the scheduler runs the process.

This keyword argument is a list of arguments that are used by the wait function.

This keyword argument controls the fate of the process when an image that has been saved on disk is started up. It can have one of the following values:

  • The value:flush means that this process will not exist in the saved image; this value is the default.

  • The value:restart means that the process will run its initial function again when the image is restarted.

In neither case does the functiondisksave save the current state of a running process.

A top-level function is responsible for running the initial function tomake-process. If the initial function returns, the scheduler kills the process by invoking the functionkill-process.

The process begins to run at the next scheduler cycle if its wait function allows.

;; The function SET-ALARM creates a process that prints a given 
;; message at a given time.  The message is printed to the stream
;; that is the value of *TERMINAL-IO* when SET-ALARM is called.
;; This stream is passed as an argument to the initial function of 
;; the process.
> (defun set-alarm (universal-time message)
    "Sets an alarm for the given time"
    (make-process :name "Alarm"
                  :stack-size 3000
                  :function #'alarm-top-level
                  :args (list *terminal-io* 
                           universal-time message)))
SET-ALARM

;; This is the top-level function of the alarm process. It ;; determines how much time remains until the alarm goes off, and ;; then it goes to sleep. > (defun alarm-top-level (*terminal-io* utime message) (let* ((now (get-universal-time)) (time (- utime now))) (sleep time) (format t "~&[~A]~%" message))) ALARM-TOP-LEVEL

See Also: kill-process

process-active-p Function

process-alive-p Function

process-in-the-debugger-p Function

Syntax:process-active-p process

Syntax:process-alive-p process

Syntax:process-in-the-debugger process

These functions test the state of the specified process.

The functionprocess-in-the-debugger-p is true if its process argument is in the Debugger; otherwise, it is false.

A process that is in the Debugger is active.

> (defun laziness ()
     (process-wait-forever "Snore"))
LAZINESS

> (setq lazy-process (make-process :name "Lazy" :function 'laziness)) #<Process Lazy 6EE9FB>

> (and (process-active-p lazy-process) (process-alive-p lazy-process)) T

> (process-alive-p lazy-process) T

> (deactivate-process lazy-process) #<Process Lazy 6EE9FB>

> (process-active-p lazy-process) NIL

> (process-alive-p lazy-process) T

> (kill-process lazy-process) #<Process Lazy 6EE9FB>

> (or (process-active-p lazy-process) (process-alive-p lazy-process)) NIL

> (process-in-the-debugger-p *current-process*) NIL

> (error "An error") >>Error: An error

EVAL: Required arg 0 (EXPRESSION): (ERROR "An error") :A 0: Abort to Lisp Top Level -> (process-in-the-debugger-p *current-process*) T ->

See Also: process-state

process-allow-schedule Function

Syntax: process-allow-schedule

The functionprocess-allow-schedule suspends the current process for one scheduler cycle to allow other processes to run.

process-lock Macro

process-unlock Macro

with-process-lock Macro

Syntax:process-lock place&optional lock-value action wait-state

Syntax:process-unlock place&optional lock-value action

Syntax:with-process-lock(place &optional lock-value&key:action :wait-state :flag) {form}*

The macrosprocess-lock,process-unlock, andwith-process-lock provide a conventional interface for preventing data shared among multiple processes from being modified by more than one process at a time.

For all of these macros, the place argument can be any location that is a valid argument to the Common Lisp macrosetf; this location can contain any Lisp value. If the value of place isnil, the lock is considered to be a free lock. If place has any non-nil value, it is considered to be a locked lock.

The lock-value argument specifies the process to store in the place location; the default value is the value of the variable *current-process*.

Forprocess-lock, the wait-state optional argument is a Lisp string that is used as a whostate argument to the functionprocess-wait. This string is displayed as the state of the process.

The macroprocess-lock attempts to lock the location specified by place as follows:

Note: You can use the return value ofprocess-lock to distinguish between the case where place is free and the case where place is already locked by the process specified in the lock-value argument. If you found the lock to be free, you can safely unlock it, while if you found it locked, you might want to let it be unlocked by the enclosing context.

The macroprocess-unlock attempts to free the location specified by the place argument. If the value of the place argument is lock-value, the macro frees the lock by changing the value tonil. The optional action argument to process-unlock specifies what happens when the value of the place argument is not lock-value; this argument can have one of the following values:

In this case,process-unlock returns the message:lock-not-locked or:locked-by-different-process to describe the current state of the lock.

In this case, a continuable error is signaled; this value is the default.

Since a lock can change afterprocess-unlock has exited, you should not rely on these values to always reflect the current state of the system.

The macrowith-process-lock temporarily locks a location specified by place, evaluates the form arguments, and then frees the place location. The action that is taken depends on the value of the:action keyword argument as follows:

In all cases, the body is run only if the lock is held by the current process.

The:wait-state keyword argument towith-process-lock is a Lisp string that is used as a whostate argument to the functionprocess-wait. This string displays the state of the process.

The:flag keyword argument is used to signal whether the process is acquiring this lock for the first time (as opposed to already owning it). The:flag keyword argument is a symbol which is used as a variable to be locally bound over the execution of the body ofwith-process-lock. The variable is true if this is a newly acquired lock.

;;; The following safe deposit example uses locks to ensure the
;;; consistency of the accounts and thus to prevent errors:
> (defun safe-deposit (amount account)
    ;; This lock prevents the race between reading the balance and
    ;; writing the new balance.
    (with-process-lock ((account-lock account))
      (incf (account-balance account) amount)))
SAFE-DEPOSIT

> (defun safe-withdraw (amount account) ;; This lock prevents the race between reading the balance and ;; writing the new balance. (with-process-lock ((account-lock account)) (decf (account-balance account) amount))) SAFE-WITHDRAW

;;; SAFE-TRANSFER must lock both accounts before updating either. ;;; To avoid deadlocks, it locks the accounts in order. In ;;; addition, interruptions must be inhibited so that the update ;;; completes. > (defun safe-transfer (amount from-account to-account) (if (< (account-number from-account) (account-number to-account)) ;; From account has a lower number. (with-process-lock ((account-lock from-account)) (with-process-lock ((account-lock to-account)) (with-interruptions-inhibited (safe-withdraw amount from-account) (safe-deposit amount to-account)))) ;; To account has a lower number. (with-process-lock ((account-lock to-account)) (with-process-lock ((account-lock from-account)) (with-interruptions-inhibited (safe-withdraw amount from-account) (safe-deposit amount to-account)))))) SAFE-TRANSFER

> (defun safe-transfer-random (account1 account2) (if (zerop (random 2)) (safe-transfer (random 20) account1 account2) (safe-transfer (random 20) account2 account1))) SAFE-TRANSFER-RANDOM

;;; To be certain that processes are not in a critical section, ;;; this function interrupts the processes to get them to kill ;;; themselves. (This precaution isn't necessary in this example ;;; because there is no critical code outside the locked regions, ;;; but it is good form.) > (defun test-safe () (let ((peters-account (make-account :Balance 100)) (pauls-account (make-account :Balance 100)) (*scheduling-quantum* 10)) (let (p1 p2) (unwind-protect (progn (setq p1 (make-process :name "transfer1" :function #'(lambda () (loop (safe-transfer-random peters-account pauls-account)))) p2 (make-process :name "transfer2" :function #'(lambda () (loop (safe-transfer-random pauls-account peters-account))))) (process-wait-with-timeout "sleep" 5 #'(lambda () nil)))

;; Since peters-account is created before pauls-account ;; it must have a lower number. (with-process-lock ((account-lock peters-account)) (with-process-lock ((account-lock pauls-account)) (when p1 (interrupt-process p1 #'(lambda () (kill-process p1)))) (when p2 (interrupt-process p2 #'(lambda () (kill-process p2))))))) (format t "~%Total $~d." (+ (account-balance peters-account) (account-balance pauls-account)))))) TEST-SAFE

> (loop (test-safe)) Total $200. Total $200. Total $200. Total $200. Total $200. Total $200. Total $200. Total $200. Total $200. Total $200. ...

;;; The following examples deal with various attempts to unlock ;;; a process. ;;; ;;; The default action for PROCESS-UNLOCK is to signal an error ;;; if the lock is not already locked. ;;; > (setq *my-place* nil) NIL

> (process-unlock *my-place*) >>Error: Attempting to unlock a lock that isn't locked.

;;; Here's how we could have safely unlocked the lock: > (process-unlock *my-place* *current-process* :ignore) :LOCK-NOT-LOCKED >

;;; WITH-PROCESS-LOCK does the work of locking and unlocking ;;; the process for you. However, you may choose to unlock the ;;; lock prematurely, within the body of WITH-PROCESS-LOCK. > (setq *my-place* nil) NIL

> (with-process-lock (*my-place*) (process-unlock *my-place*) (print "here")) "here" "here" >

;;; Finally, we illustrate the use of the :flag keyword argument ;;; to WITH-PROCESS-LOCK. ;;; We use the :flag keyword argument to see whether some ;;; enclosing context has already grabbed the lock. ;;; If so, we won't try to unlock the lock early. ;;; If we are freshly grabbing the lock, then we can safely ;;; unlock it, which we might want to do to make it available ;;; as soon as possible.

> (defun hurry-up-and-wait () (with-process-lock (*my-place* *CURRENT-PROCESS* :action :abort :flag not-already-grabbed-p) (if not-already-grabbed-p (progn (print "I grabbed the lock!") (print "I might as well unlock it early.") (process-unlock *my-place*)) (progn (print "I didn't freshly grab this lock.") (print "I better not unlock it."))) (print "Imagine this part taking a long time.") nil)) HURRY-UP-AND-WAIT

> (hurry-up-and-wait) "I didn't freshly grab this lock." "I better not unlock it." "Imagine this part taking a long time." NIL

> (process-lock *my-place*) T

> (hurry-up-and-wait) "I didn't need to grab the lock." "I better not unlock it." "Imagine this part taking a long time." NIL >

process-name Function

process-state Function

process-whostate Function

process-initial-function Function

process-initial-arguments Function

process-wait-function Function

process-wait-arguments Function

process-interruptions Function

Syntax:process-name process

Syntax:process-state process

Syntax:process-whostate process

Syntax:process-initial-function process

Syntax:process-initial-arguments process

Syntax:process-wait-function process

Syntax:process-wait-arguments process

Syntax:process-interruptions process

These functions return information about the specified process.

The functionprocess-name returns a string that was given as the name argument tomake-process when the process was created.

The functionprocess-state returns one of the following keywords to describe the current state of the process:

This value indicates that the process is either running or is waiting to run.

This value indicates that the process has been deactivated by the functiondeactivate-process.

This value indicates that the process has been killed by the function kill-process.

The functionprocess-whostate returns a string that describes the current state of the process. If the process state is:killed, the string"Killed" is returned. If the process state is:active or:inactive, the function returns one of the following values:

The functionprocess-initial-function returns the function specified as the:function keyword argument tomake-process when the process was created. This function is called the initial function, and it is the first function to call the process.

The functionprocess-initial-arguments returns a list of the arguments to the initial function for the process.

If a process is waiting, the functionprocess-wait-function returns the function specified by the wait-function argument to eitherprocess-wait,process-wait-forever, orprocess-wait-with-timeout.

If a process is waiting, the functionprocess-wait-arguments returns any arguments to the wait function specified in eitherprocess-wait,process-wait-forever, orprocess-wait-with-timeout.

The functionprocess-interruptions returns a list of the interruptions pending for the specified process. Each element of the list is a list whose car is the interruption function and whose cdr is the list of arguments to that function.

You can use the Common Lisp macrosetf with all of these functions; however, no error checking is performed, and errors can seriously damage the scheduler.

> (defun newtask-work (x)
    (loop 
      (process-wait "Non-NIL" 'symbol-value x)
      (format t "~&~S has value ~S~%" x (symbol-value x))
       (set x nil)))
NEWTASK-WORK

> (defvar *temp* nil) *TEMP*

> (setq process (make-process :name "Newtask" :function 'newtask-work :args '(*temp*) :stack-size 1000)) #<Process Newtask 7A1FF3>

> (process-name process) "Newtask"

> (process-state process) :ACTIVE

> (process-whostate process) "Non-NIL"

> (process-initial-function process) NEWTASK-WORK

> (process-initial-arguments process) (*TEMP*)

> (process-wait-function process) SYMBOL-VALUE

> (process-wait-arguments process) (*TEMP*)

> (setf (process-name process) "New Newtask") "New Newtask"

> process #<Process New Newtask 7A1FF3>

> (setq lazy-process (make-process :name "lazy" :function 'process-wait-forever)) #<Process lazy 61982B>

> (with-scheduling-inhibited (interrupt-process lazy-process #'format t "I'm interrupted~%") (process-interruptions lazy-process)) ((#<Compiled-Function FORMAT 1DBDEF> T "I'm interrupted~%")) I'm interrupted

See Also: make-process

processp Function

Syntax:processp object

The functionprocessp is true if its object argument is a process; otherwise, it is false.

> (processp *current-process*)
T

> (processp 26) NIL

process-plist Function

Syntax:process-plist process

The functionprocess-plist accesses the property list that is associated with the specified process.

Since the value returned is a property list, you can use a call to this function as the place argument for the Common Lisp functiongetf.

> (setf (process-plist *initial-process*)
        '(type initial other-name "initial process"))
(TYPE INITIAL OTHER-NAME "initial process")

> (getf (process-plist *initial-process*) 'type) INITIAL

> (setf (getf (process-plist *initial-process*) 'color) 'green) GREEN

> (process-plist *initial-process*) (COLOR GREEN TYPE INITIAL OTHER-NAME "initial process")

process-suspend-functions Function

process-resume-functions Function

Syntax:process-suspend-functions process

Syntax:process-resume-functions process

The functionprocess-suspend-functions returns a list of functions that are executed just before the scheduler switches from the specified process to a new process.

The functionprocess-resume-functions returns a list of functions that are executed before the scheduler switches to the specified process.

Each item on the list must be either a function or the name of a function of zero arguments. You can use the Common Lisp macrosetf to modify this list.

> (setf lazy-process
        (make-process :name "Lazy" 
                      :function #'process-wait-forever))
#<Process Lazy 970156>

> (defun resume-function () (format t "~&Resuming ~S~%" *current-process*)) RESUME-FUNCTION

> (push 'resume-function (process-resume-functions lazy-process)) (RESUME-FUNCTION)

> (push #'(lambda () (format t "~&Suspending process ~S~%" *current-process*)) (process-suspend-functions lazy-process)) (#<Interpreted-Function (LAMBDA NIL (FORMAT T "~&Suspending process ~S~%" *CURRENT-PROCESS*)) 976206>) > (interrupt-process lazy-process #'ignore nil) #<Process Lazy 970156>

> Resuming #<Process Lazy 970156> Suspending process #<Process Lazy 970156>

process-wait Function

process-wait-with-timeout Function

process-wait-forever Function

Syntax:process-wait whostate function&rest args

Syntax:process-wait-with-timeout whostate seconds function&rest args

Syntax:process-wait-forever&optional whostate

These functions suspend the current process:

The whostate argument specifies a string that can be displayed as the state of the process. If you do not specify this argument to the functionprocess-wait-forever, the default value is"Wait Forever".

The seconds argument toprocess-wait-with-timeout is a numeric value that specifies the number of seconds to wait.

The function argument is evaluated in the process that invokedprocess-wait,process-wait-with-timeout, or process-wait-forever; at this time, process scheduling is inhibited. If the function that was invoked immediately returns a non-nil value, no processes are switched, and the calling process does not wait.

Since these functions are called from another process inside the scheduler, they must not depend on the values of any special variables. When the function argument is called, the special variable *current-process* is bound to the process whose wait function is being called. Thus, the wait function can find out the value of a special variable in its process by using the functionsymbol-process-value.

A process suspended by any of these functions can be restarted if the functioninterrupt-process is used to execute a Common Lispthrow to a tag outside of the function that suspended the process.

It is an error to use the functionsprocess-wait,process-wait-with-timeout, orprocess-wait-forever when scheduling is inhibited.

*quitting-lisp* Variable

Syntax:*quitting-lisp*

The variable*quitting-lisp* has a non-nil value when any process has called the functionquit; otherwise, its value isnil.

When the variable*quitting-lisp* is non-nil, no new processes can be created, and no process can be deactivated.

Suppose that you have the following code:

(defmacro dont-let-x-change (&body body)
  '(unwind-protect
       (progn ,@body)
    (when (and (did-x-change)
               (y-or-n-p "Shall I set X back?"))
      (restore-x))))

If you get an error inside the body and decide to call the functionquit, you receive the"Shall I set X back?" query. Since you are quitting Lisp, you can prevent the query with the following modified version of the code:

(defmacro dont-let-x-change (&body body)
  '(unwind-protect
       (progn ,@body)
    (unless *quitting-lisp*
      (when (and (did-x-change)
                 (y-or-n-p "Shall I set X back?"))
        (restore-x)))))

> *quitting-lisp* NIL

> (unwind-protect (quit) (format t "~&The value of *quitting-lisp* is ~A~2%" *quitting-lisp*)) The value of *quitting-lisp* is T

restart-process Function

Syntax:restart-process process

The functionrestart-process restarts a specified process.

The restarted process first runs any cleanup forms that are introduced by the Common Lisp special formunwind-protect. Then it reapplies its initial function, which was specified when the process was created, to its initial arguments.

The process argument specifies the process that is restarted.

You cannot restart the initial process or any process that has been killed.

> (setq *a* 0)
0

> (setq silly-process (make-process :name "silly" :function #'(lambda () (incf *a*) (process-wait-forever)))) #<Process silly 6C2DDB>

> *a* 1

> (restart-process silly-process) #<Process silly 6C2DDB>

> *a* 2

*scheduling-quantum* Variable

Syntax:*scheduling-quantum*

The variable*scheduling-quantum* contains the amount of time in milliseconds that a process can run before the scheduler interrupts it to run new processes.

Although setting this variable to a small value increases response time, it also increases scheduler overhead.

show-processes Function

Syntax:show-processes

The functionshow-processes prints information about every process, including the current status of each process.

An asterisk in the left margin denotes the current process.

All output is sent to the stream that is the value of the Common Lisp variable*standard-output*.

> (show-processes)
* #<Process Initial 632F6B> "Run" state ACTIVE wait-fn TRUE initial-fn NIL
  #<Process Idle 632FC3> "Run" state ACTIVE wait-fn TRUE initial-fn 
    IDLE-TOP-LEVEL
NIL

> (defun do-nothing () (process-wait-forever)) DO-NOTHING > (make-process :name "Do Nothing" :function 'do-nothing) #<Process Do Nothing 6891EB>

> (show-processes) #<Process Do Nothing 6891EB> "Wait Forever" state ACTIVE wait-fn FALSE initial-fn DO-NOTHING * #<Process Initial 632F6B> "Run" state ACTIVE wait-fn TRUE initial-fn NIL #<Process Idle 632FC3> "Run" state ACTIVE wait-fn TRUE initial-fn IDLE-TOP-LEVEL NIL

symbol-global-value Function

Syntax:symbol-global-value symbol

The functionsymbol-global-value returns the global value of the variable associated with the specified symbol; it ignores any values for the symbol that are dynamically bound in processes. An error is signaled if the variable is unbound.

The symbol argument can be any Lisp symbol. You can use the functionsymbol-global-boundp to test whether the symbol has an associated value.

You can use the Common Lisp macrosetf with this function to modify the specified symbol.

> (defvar *temp* 100)
*TEMP*

> (let ((*temp* 120)) (format t "*temp*'s dynamic value is ~D; global value is ~D~%" *temp* (symbol-global-value '*temp*))) *temp*'s dynamic value is 120; global value is 100 NIL

See Also: symbol-global-boundp

symbol-global-boundp Function

symbol-process-boundp Function

symbol-dynamically-boundp Function

Syntax:symbol-global-boundp symbol

Syntax:symbol-process-boundp symbol process

Syntax:symbol-dynamically-boundp symbol&optional process

These functions test the binding of variables associated with specified symbols within a process.

The functionsymbol-dynamically-boundp is true if its symbol argument is dynamically bound inside the given process; it is false if the process has no dynamic bindings for the symbol.

The symbol argument can be any Lisp symbol.

If you omit the optional process argument for symbol-dynamically-boundp, the value of the variable*current-process* is used.

> (defun describe-bindings (symbol proc)
    (format t "Global ~A, process ~A, dynamically ~A"
      (symbol-global-boundp symbol)
      (symbol-process-boundp symbol proc)
      (symbol-dynamically-boundp symbol proc)))
DESCRIBE-BINDINGS

> (defvar *a* t) *A*

> (describe-bindings '*a* *current-process*) Global T, process T, dynamically NIL NIL

> (let ((*a* t)) (describe-bindings '*a* *current-process*)) Global T, process T, dynamically T NIL

> (let ((*a* t)) (makunbound '*a*) (describe-bindings '*a* *current-process*)) Global T, process NIL, dynamically T NIL

> (makunbound '*a*) *A*

> (describe-bindings '*a* *current-process*) Global NIL, process NIL, dynamically NIL NIL

> (let ((*a* t)) (describe-bindings '*a* *current-process*)) Global NIL, process T, dynamically T NIL

> (let ((*a* t)) (makunbound '*a*) (describe-bindings '*a* *current-process*)) Global NIL, process NIL, dynamically T NIL

See Also: symbol-global-value, symbol-process-value

symbol-process-value Function

Syntax:symbol-process-value symbol process

The functionsymbol-process-value returns the global or dynamic value of the variable associated with the specified symbol as if the given process were current. If the symbol is not bound in the process, the function returns the global value. An error is signaled if the variable is unbound.

The symbol argument can be any Lisp symbol. You can use the functionsymbol-process-boundp to test whether the symbol has an associated value.

You can use the Common Lisp macrosetf with this function to modify the specified symbol in the process.

> (proclaim '(special *a*))
T

> (defun waiter () (let ((*a* 20)) (process-wait-forever))) WAITER

> (setq waiter (make-process :name "WAITER" :function 'waiter)) #<Process WAITER 60F333>

> (symbol-process-value '*a* waiter) 20

> (setf (symbol-process-value '*a* waiter) 25) 25

> (interrupt-process waiter #'(lambda () (format t "*a* has value ~D~%" *a*))) #<Process WAITER 60F333> *a* has value 25

See Also: symbol-process-boundp

using-initial-io Macro

Syntax:using-initial-io {form}*

The macrousing-initial-io disables the scheduler during the execution of its form arguments and binds the Common Lisp variable*terminal-io* to the value specified by the variable*initial-io*.

> (using-initial-io
    (error "Things are really messed up badly."))
>>Error: Things are really messed up badly.

EVAL: Required arg 0 (EXPRESSION): (USING-INITIAL-IO (ERROR "Things are really messed up badly.")) :A 0: Abort to Lisp Top Level -> :a Abort to Lisp Top Level Back to Lisp Top Level

See Also: *initial-io*

with-interruptions-allowed Macro

with-interruptions-inhibited Macro

Syntax:with-interruptions-allowed {form}*

Syntax:with-interruptions-inhibited {form}*

The macroswith-interruptions-allowed and with-interruptions-inhibited specify whether a process can be interrupted.

The macrowith-interruptions-allowed allows interruptions to occur during the execution of the form arguments; it locally suppresses the effect ofwith-interruptions-inhibited.

Whenever a process is interrupted, it suspends its own execution to let the forms specified by the interruption run. The macrowith-interruptions-inhibited prevents a process from being interrupted so that the specified form arguments can execute normally.

The specified form arguments towith-interruptions-inhibited eventually run to completion within normal scheduling unless an error occurs. You cannot interrupt the execution of the forms from outside of the body of the macro.

Any interruptions that occur from within the body ofwith-interruptions-inhibited are deferred until the execution of the form arguments is complete.

> (with-interruptions-inhibited  
     (interrupt-process
         *current-process* #'format t "Running the interruption~%")  
     (format t "I am at point A~&")  
     (with-interruptions-allowed  
         (format t "I am at point B~&"))  
     (format t "I am at point C~&")) 
I am at point A 
Running the interruption 
I am at point B 
I am at point C 
NIL 

See Also: interrupt-process

with-keyboard-interrupt-process Macro

Syntax:with-keyboard-interrupt-process process {form}*

The macrowith-keyboard-interrupt-process sets the variable*keyboard-interrupt-process* to the given process and executes the form arguments.

When the form arguments have finished executing, the old value of*keyboard-interrupt-process* is restored if its value has not changed; otherwise, the new value of*keyboard-interrupt-process* is kept.

See Also: *keyboard-interrupt-process*

with-scheduling-allowed Macro

with-scheduling-inhibited Macro

Syntax:with-scheduling-allowed {form}*

Syntax:with-scheduling-inhibited {form}*

The macroswith-scheduling-allowed andwith-scheduling-inhibited determine whether the scheduler can block a process.

The macrowith-scheduling-allowed allows the scheduler to switch processes during the execution of the form arguments; it locally suppresses the effect ofwith-scheduling-inhibited.

The macrowith-scheduling-inhibited prohibits the scheduler from switching processes during the execution of the form arguments.

Any attempts to block the current process from within the body ofwith-scheduling-inhibited signal an error.


The Advanced User's Guide - 9 SEP 1996

Generated with Harlequin WebMaker