Previous Section Next Chapter Table of Contents Glossary Index

Chapter 7. Programming with Threads

7.7. Threads Dictionary

[Function]

all-processes => result
Obtain a fresh list of all known Lisp threads.

Values:

result---a list of all lisp processes (threads) known to Clozure CL.

Description:

Returns a list of all lisp processes (threads) known to Clozure CL as of the precise instant it's called. It's safe to traverse this list and to modify the cons cells that comprise that list (it's freshly consed.) Since other threads can create and kill threads at any time, there's generally no way to get an "accurate" list of all threads, and (generally) no sense in which such a list can be accurate.

[Function]

make-process name &key persistent priority class initargs stack-size vstack-size tstack-size initial-bindings use-standard-initial-bindings => process
Creates and returns a new process.

Arguments and Values:

name---a string, used to identify the process.

persistent---if true, requests that information about the process be retained by SAVE-APPLICATION so that an equivalent process can be restarted when a saved image is run. The default is nil.

priority---ignored. It shouldn't be ignored of course, but there are complications on some platforms. The default is 0.

class---the class of process object to create; should be a subclass of CCL:PROCESS. The default is CCL:PROCESS.

initargs---Any additional initargs to pass to MAKE-INSTANCE. The default is ().

stack-size---the size, in bytes, of the newly-created process's control stack; used for foreign function calls and to save function return address context. The default is CCL:*DEFAULT-CONTROL-STACK-SIZE*.

vstack-size---the size, in bytes, of the newly-created process's value stack; used for lisp function arguments, local variables, and other stack-allocated lisp objects. The default is CCL:*DEFAULT-VALUE-STACK-SIZE*.

tstack-size---the size, in bytes, of the newly-created process's temp stack; used for the allocation of dynamic-extent objects. The default is CCL:*DEFAULT-TEMP-STACK-SIZE*.

use-standard-initial-bindings---when true, the global "standard initial bindings" are put into effect in the new thread before. See DEF-STANDARD-INITIAL-BINDING. "standard" initial bindings are put into effect before any bindings specified by :initial-bindings are. The default is t. This option is deprecated: the correct behavior of many Clozure CL components depends on thread-local bindings of many special variables being in effect.

initial-bindings---an alist of (symbol . valueform) pairs, which can be used to initialize special variable bindings in the new thread. Each valueform is used to compute the value of a new binding of symbol in the execution environment of the newly-created thread. The default is nil.

process---the newly-created process.

Description:

Creates and returns a new lisp process (thread) with the specified attributes. process will not begin execution immediately; it will need to be preset (given an initial function to run, as by process-preset) and enabled (allowed to execute, as by process-enable) before it's able to actually do anything.

If valueform is a function, it is called, with no arguments, in the execution environment of the newly-created thread; the primary value it returns is used for the binding of the corresponding symbol.

Otherwise, valueform is evaluated in the execution environment of the newly-created thread, and the resulting value is used.

[Function]

process-suspend process => result
Suspends a specified process.

Arguments and Values:

process---a lisp process (thread).

result---T if process had been runnable and is now suspended; NIL otherwise. That is, T if process's process-suspend-count transitioned from 0 to 1.

Description:

Suspends process, preventing it from running, and stopping it if it was already running. This is a fairly expensive operation, because it involves a few calls to the OS. It also risks creating deadlock if used improperly, for instance, if the process being suspended owns a lock or other resource which another process will wait for.

Each call to process-suspend must be reversed by a matching call to process-resume before process is able to run. What process-suspend actually does is increment the process-suspend-count of process.

A process can't suspend itself, though this once worked and this documentation claimed has claimed that it did.

Notes:

process-suspend was previously called process-disable. process-enable now names a function for which there is no obvious inverse, so process-disable is no longer defined.

[Function]

process-resume process => result
Resumes a specified process which had previously been suspended by process-suspend.

Arguments and Values:

process---a lisp process (thread).

result---T if process had been suspended and is now runnable; NIL otherwise. That is, T if process's process-suspend-count transitioned from to 0.

Description:

Undoes the effect of a previous call to process-suspend; if all such calls are undone, makes the process runnable. Has no effect if the process is not suspended. What process-resume actually does is decrement the process-suspend-count of process, to a minimum of 0.

Notes:

This was previously called PROCESS-ENABLE; process-enable now does something slightly different.

[Function]

process-suspend-count process => result
Returns the number of currently-pending suspensions applicable to a given process.

Arguments and Values:

process---a lisp process (thread).

result---The number of "outstanding" process-suspend calls on process, or NIL if process has expired.

Description:

An "outstanding" process-suspend call is one which has not yet been reversed by a call to process-resume. A process expires when its initial function returns, although it may later be reset.

A process is runnable when it has a process-suspend-count of 0, has been preset as by process-preset, and has been enabled as by process-enable. Newly-created processes have a process-suspend-count of 0.

[Function]

process-preset process function &rest args => result
Sets the initial function and arguments of a specified process.

Arguments and Values:

process---a lisp process (thread).

function---a function, designated by itself or by a symbol which names it.

args---a list of values, appropriate as arguments to function.

result---undefined.

Description:

Typically used to initialize a newly-created or newly-reset process, setting things up so that when process becomes enabled, it will begin execution by applying function to args. process-preset does not enable process, although a process must be process-preset before it can be enabled. Processes are normally enabled by process-enable.

[Function]

process-enable process &optional timeout
Begins executing the initial function of a specified process.

Arguments and Values:

process---a lisp process (thread).

timeout---a time interval in seconds. May be any non-negative real number the floor of which fits in 32 bits. The default is 1.

result---undefined.

Description:

Tries to begin the execution of process. An error is signaled if process has never been process-preset. Otherwise, process invokes its initial function.

process-enable attempts to synchronize with process, which is presumed to be reset or in the act of resetting itself. If this attempt is not successful within the time interval specified by timeout, a continuable error is signaled, which offers the opportunity to continue waiting.

A process cannot meaningfully attempt to enable itself.

Notes:

It would be nice to have more discussion of what it means to synchronize with the process.

[Function]

process-run-function process-specifier function &rest args => process
Creates a process, presets it, and enables it.

Arguments and Values:

name---a string, used to identify the process. Passed to make-process.

function---a function, designated by itself or by a symbol which names it. Passed to preset-process.

persistent---a boolean, passed to make-process.

priority---ignored.

class---a subclass of CCL:PROCESS. Passed to make-process.

initargs---a list of any additional initargs to pass to make-process.

stack-size---a size, in bytes. Passed to make-process.

vstack-size---a size, in bytes. Passed to make-process.

tstack-size---a size, in bytes. Passed to make-process.

process---the newly-created process.

Description:

Creates a lisp process (thread) via make-process, presets it via process-preset, and enables it via process-enable. This means that process will immediately begin to execute. process-run-function is the simplest way to create and run a process.

[Function]

process-interrupt process function &rest args => result
Arranges for the target process to invoke a specified function at some point in the near future, and then return to what it was doing.

Arguments and Values:

process---a lisp process (thread).

function---a function.

args---a list of values, appropriate as arguments to function.

result---the result of applying function to args if process is the current-process, otherwise NIL.

Description:

Arranges for process to apply function to args at some point in the near future (interrupting whatever process was doing.) If function returns normally, process resumes execution at the point at which it was interrupted.

process must be in an enabled state in order to respond to a process-interrupt request. It's perfectly legal for a process to call process-interrupt on itself.

process-interrupt uses asynchronous POSIX signals to interrupt threads. If the thread being interrupted is executing lisp code, it can respond to the interrupt almost immediately (as soon as it has finished pseudo-atomic operations like consing and stack-frame initialization.)

If the interrupted thread is blocking in a system call, that system call is aborted by the signal and the interrupt is handled on return.

It is still difficult to reliably interrupt arbitrary foreign code (that may be stateful or otherwise non-reentrant); the interrupt request is handled when such foreign code returns to or enters lisp.

Notes:

It would probably be better for result to always be NIL, since the present behavior is inconsistent.

Process-interrupt works by sending signals between threads, via the C function #_pthread_signal. It could be argued that it should be done in one of several possible other ways under Darwin, to make it practical to asynchronously interrupt things which make heavy use of the Mach nanokernel.

[Variable]

*CURRENT-PROCESS*
Bound in each process, to that process itself.

Value Type:

A lisp process (thread).

Initial Value:

Bound separately in each process, to that process itself.

Description:

Used when lisp code needs to find out what process it is executing in. Shouldn't be set by user code.

See Also:
all-processes

[Function]

process-reset process &optional kill-option => result
Causes a specified process to cleanly exit from any ongoing computation.

Arguments and Values:

process---a lisp process (thread).

kill-option---an internal argument, must be nil.

result---undefined.

Description:

Causes process to cleanly exit from any ongoing computation and enter a state where it can be process-preset. This is implemented by signaling a condition of type PROCESS-RESET; user-defined condition handlers should generally refrain from attempting to handle conditions of this type.

The kill-option argument is for internal use only and should not be specified by user code

A process can meaningfully reset itself.

There is in general no way to know precisely when process has completed the act of resetting or killing itself; a process which has either entered the limbo of the reset state or exited has few ways of communicating either fact. process-enable can reliably determine when a process has entered the "limbo of the reset state", but can't predict how long the clean exit from ongoing computation might take: that depends on the behavior of unwind-protect cleanup forms, and of the OS scheduler.

Resetting a process other than *current-process* involves the use of process-interrupt.

[Function]

process-reset-and-enable process => result
Reset and enable the specified process, which may not be the current process.

Arguments and Values:

process---a lisp process (thread), which may not be the current process.

result---undefined.

Description:

Equivalent to calling (process-reset process) and (process-enable process).

[Function]

process-kill process => result
Causes a specified process to cleanly exit from any ongoing computation, and then exit.

Arguments and Values:

process---a lisp process (thread).

result---undefined.

Description:

Causes process to cleanly exit from any ongoing computation, and then exit.

[Function]

process-abort process &optional condition => NIL
Causes a specified process to process an abort condition, as if it had invoked abort.

Arguments and Values:

process---a lisp process (thread).

condition---a lisp condition. The default is NIL.

Description:

Entirely equivalent to calling (process-interrupt process (lambda () (abort condition))). Causes process to transfer control to the applicable handler or restart for abort.

If condition is non-NIL, process-abort does not consider any handlers which are explicitly bound to conditions other than condition.

[Variable]

*TICKS-PER-SECOND*
Bound to the clock resolution of the OS scheduler.

Value Type:

A positive integer.

Initial Value:

The clock resolution of the OS scheduler. Currently, both LinuxPPC and DarwinPPC yield an initial value of 100.

Description:

This value is ordinarily of marginal interest at best, but, for backward compatibility, some functions accept timeout values expressed in "ticks". This value gives the number of ticks per second.

[Function]

process-whostate process => whostate
Returns a string which describes the status of a specified process.

Description:

This information is primarily for the benefit of debugging tools. whostate is a terse report on what process is doing, or not doing, and why.

If the process is currently waiting in a call to process-wait or process-wait-with-timeout, its process-whostate will be the value which was passed to that function as whostate.

Notes:

This should arguably be SETFable, but doesn't seem to ever have been.

[Function]

process-allow-schedule
Used for cooperative multitasking; probably never necessary.

Description:

Advises the OS scheduler that the current thread has nothing useful to do and that it should try to find some other thread to schedule in its place. There's almost always a better alternative, such as waiting for some specific event to occur. For example, you could use a lock or semaphore.

Notes:

This is a holdover from the days of cooperative multitasking. All modern general-purpose operating systems use preemptive multitasking.

[Function]

process-wait whostate function &rest args => result
Causes the current lisp process (thread) to wait for a given predicate to return true.

Arguments and Values:

whostate---a string, which will be the value of process-whostate while the process is waiting.

function---a function, designated by itself or by a symbol which names it.

args---a list of values, appropriate as arguments to function.

result---NIL.

Description:

Causes the current lisp process (thread) to repeatedly apply function to args until the call returns a true result, then returns NIL. After each failed call, yields the CPU as if by process-allow-schedule.

As with process-allow-schedule, it's almost always more efficient to wait for some specific event to occur; this isn't exactly busy-waiting, but the OS scheduler can do a better job of scheduling if it's given the relevant information. For example, you could use a lock or semaphore.

[Function]

process-wait-with-timeout whostate ticks function args => result
Causes the current thread to wait for a given predicate to return true, or for a timeout to expire.

Arguments and Values:

whostate---a string, which will be the value of process-whostate while the process is waiting.

ticks---either a positive integer expressing a duration in "ticks" (see *ticks-per-second*), or NIL.

function---a function, designated by itself or by a symbol which names it.

args---a list of values, appropriate as arguments to function.

result---T if process-wait-with-timeout returned because its function returned true, or NIL if it returned because the duration ticks has been exceeded.

Description:

If ticks is NIL, behaves exactly like process-wait, except for returning T. Otherwise, function will be tested repeatedly, in the same kind of test/yield loop as in process-wait until either function returns true, or the duration ticks has been exceeded.

Having already read the descriptions of process-allow-schedule and process-wait, the astute reader has no doubt anticipated the observation that better alternatives should be used whenever possible.

[Macro]

without-interrupts &body body => result
Evaluates its body in an environment in which process-interrupt requests are deferred.

Arguments and Values:

body---an implicit progn.

result---the primary value returned by body.

Description:

Executes body in an environment in which process-interrupt requests are deferred. As noted in the description of process-interrupt, this has nothing to do with the scheduling of other threads; it may be necessary to inhibit process-interrupt handling when (for instance) modifying some data structure (for which the current thread holds an appropriate lock) in some manner that's not reentrant.

[Macro]

with-interrupts-enabled &body body => result
Evaluates its body in an environment in which process-interrupt requests have immediate effect.

Arguments and Values:

body---an implicit progn.

result---the primary value returned by body.

Description:

Executes body in an environment in which process-interrupt requests have immediate effect.

[Function]

make-lock &optional name => lock
Creates and returns a lock object, which can be used for synchronization between threads.

Arguments and Values:

name---any lisp object; saved as part of lock. Typically a string or symbol which may appear in the process-whostates of threads which are waiting for lock.

lock---a newly-allocated object of type CCL:LOCK.

Description:

Creates and returns a lock object, which can be used to synchronize access to some shared resource. lock is initially in a "free" state; a lock can also be "owned" by a thread.

[Macro]

with-lock-grabbed (lock) &body body
Waits until a given lock can be obtained, then evaluates its body with the lock held.

Arguments and Values:

lock---an object of type CCL:LOCK.

body---an implicit progn.

result---the primary value returned by body.

Description:

Waits until lock is either free or owned by the calling thread, then executes body with the lock owned by the calling thread. If lock was free when with-lock-grabbed was called, it is restored to a free state after body is executed.

[Function]

grab-lock lock
Waits until a given lock can be obtained, then obtains it.

Arguments and Values:

lock---an object of type CCL:LOCK.

Description:

Blocks until lock is owned by the calling thread.

The macro with-lock-grabbed could be defined in terms of grab-lock and release-lock, but it is actually implemented at a slightly lower level.

[Function]

release-lock lock
Relinquishes ownership of a given lock.

Arguments and Values:

lock---an object of type CCL:LOCK.

Description:

Signals an error of type CCL:LOCK-NOT-OWNER if lock is not already owned by the calling thread; otherwise, undoes the effect of one previous grab-lock. If this means that release-lock has now been called on lock the same number of times as grab-lock has, lock becomes free.

[Function]

try-lock lock => result
Obtains the given lock, but only if it is not necessary to wait for it.

Arguments and Values:

lock---an object of type CCL:LOCK.

result---T if lock has been obtained, or NIL if it has not.

Description:

Tests whether lock can be obtained without blocking - that is, either lock is already free, or it is already owned by *current-process*. If it can, causes it to be owned by the calling lisp process (thread) and returns T. Otherwise, the lock is already owned by another thread and cannot be obtained without blocking; NIL is returned in this case.

[Function]

make-read-write-lock => read-write-lock
Creates and returns a read-write lock, which can be used for synchronization between threads.

Arguments and Values:

read-write-lock---a newly-allocated object of type CCL:READ-WRITE-LOCK.

Description:

Creates and returns an object of type CCL::READ-WRITE-LOCK. A read-write lock may, at any given time, belong to any number of lisp processes (threads) which act as "readers"; or, it may belong to at most one process which acts as a "writer". A read-write lock may never be held by a reader at the same time as a writer. Initially, read-write-lock has no readers and no writers.

Notes:

There probably should be some way to atomically "promote" a reader, making it a writer without releasing the lock, which could otherwise cause delay.

[Macro]

with-read-lock (read-write-lock) &body body => result
Waits until a given lock is available for read-only access, then evaluates its body with the lock held.

Arguments and Values:

read-write-lock---an object of type CCL:READ-WRITE-LOCK.

body---an implicit progn.

result---the primary value returned by body.

Description:

Waits until read-write-lock has no writer, ensures that *current-process* is a reader of it, then executes body.

After executing body, if *current-process* was not a reader of read-write-lock before with-read-lock was called, the lock is released. If it was already a reader, it remains one.

[Macro]

with-write-lock (read-write-lock) &body body
Waits until the given lock is available for write access, then executes its body with the lock held.

Arguments and Values:

read-write-lock---an object of type CCL:READ-WRITE-LOCK.

body---an implicit progn.

result---the primary value returned by body.

Description:

Waits until read-write-lock has no readers and no writer other than *current-process*, then ensures that *current-process* is the writer of it. With the lock held, executes body.

After executing body, if *current-process* was not the writer of read-write-lock before with-write-lock was called, the lock is released. If it was already the writer, it remains the writer.

[Function]

make-semaphore => semaphore
Creates and returns a semaphore, which can be used for synchronization between threads.

Arguments and Values:

semaphore---a newly-allocated object of type CCL:SEMAPHORE.

Description:

Creates and returns an object of type CCL:SEMAPHORE. A semaphore has an associated "count" which may be incremented and decremented atomically; incrementing it represents sending a signal, and decrementing it represents handling that signal. semaphore has an initial count of 0.

[Function]

signal-semaphore semaphore => result
Atomically increments the count of a given semaphore.

Arguments and Values:

semaphore---an object of type CCL:SEMAPHORE.

result---an integer representing an error identifier which was returned by the underlying OS call.

Description:

Atomically increments semaphore's "count" by 1; this may enable a waiting thread to resume execution.

Notes:

result should probably be interpreted and acted on by signal-semaphore, because it is not likely to be meaningful to a lisp program, and the most common cause of failure is a type error.

[Function]

wait-on-semaphore semaphore => result
Waits until the given semaphore has a positive count which can be atomically decremented.

Arguments and Values:

semaphore---an object of type CCL:SEMAPHORE.

result---an integer representing an error identifier which was returned by the underlying OS call.

Description:

Waits until semaphore has a positive count that can be atomically decremented; this will succeed exactly once for each corresponding call to SIGNAL-SEMAPHORE.

Notes:

result should probably be interpreted and acted on by wait-on-semaphore, because it is not likely to be meaningful to a lisp program, and the most common cause of failure is a type error.

[Function]

timed-wait-on-semaphore semaphore timeout => result
Waits until the given semaphore has a positive count which can be atomically decremented, or until a timeout expires.

Arguments and Values:

semaphore---An object of type CCL:SEMAPHORE.

timeout---a time interval in seconds. May be any non-negative real number the floor of which fits in 32 bits. The default is 1.

result---T if timed-wait-on-semaphore returned because it was able to decrement the count of semaphore; NIL if it returned because the duration timeout has been exceeded.

Description:

Waits until semaphore has a positive count that can be atomically decremented, or until the duration timeout has elapsed.

[Function]

process-input-wait fd &optional timeout
Waits until input is available on a given file-descriptor.

Arguments and Values:

fd---a file descriptor, which is a non-negative integer used by the OS to refer to an open file, socket, or similar I/O connection. See ccl::stream-device.

timeout---either NIL or a time interval in milliseconds. Must be a non-negative integer. The default is NIL.

Description:

Wait until input is available on fd. This uses the select() system call, and is generally a fairly efficient way of blocking while waiting for input. More accurately, process-input-wait waits until it's possible to read from fd without blocking, or until timeout, if it is not NIL, has been exceeded.

Note that it's possible to read without blocking if the file is at its end - although, of course, the read will return zero bytes.

Notes:

process-input-wait has a timeout parameter, and process-output-wait does not. This inconsistency should probably be corrected.

[Function]

process-output-wait fd &optional timeout
Waits until output is possible on a given file descriptor.

Arguments and Values:

fd---a file descriptor, which is a non-negative integer used by the OS to refer to an open file, socket, or similar I/O connection. See ccl::stream-device.

timeout---either NIL or a time interval in milliseconds. Must be a non-negative integer. The default is NIL.

Description:

Wait until output is possible on fd or until timeout, if it is not NIL, has been exceeded. This uses the select() system call, and is generally a fairly efficient way of blocking while waiting to output.

If process-output-wait is called on a network socket which has not yet established a connection, it will wait until the connection is established. This is an important use, often overlooked.

Notes:

process-input-wait has a timeout parameter, and process-output-wait does not. This inconsistency should probably be corrected.

[Macro]

with-terminal-input &body body => result
Executes its body in an environment with exclusive read access to the terminal.

Arguments and Values:

body---an implicit progn.

result---the primary value returned by body.

Description:

Requests exclusive read access to the standard terminal stream, *terminal-io*. Executes body in an environment with that access.

[Variable]

*REQUEST-TERMINAL-INPUT-VIA-BREAK*
Controls how attempts to obtain ownership of terminal input are made.

Value Type:

A boolean.

Initial Value:

NIL.

Description:

Controls how attempts to obtain ownership of terminal input are made. When NIL, a message is printed on *TERMINAL-IO*; it's expected that the user will later yield control of the terminal via the :Y toplevel command. When T, a BREAK condition is signaled in the owning process; continuing from the break loop will yield the terminal to the requesting process (unless the :Y command was already used to do so in the break loop.)

[Toplevel Command]

(:y p)
Yields control of terminal input to a specified lisp process (thread).

Arguments and Values:

p---a lisp process (thread), designated either by an integer which matches its process-serial-number, or by a string which is equal to its process-name.

Description:

:Y is a toplevel command, not a function. As such, it can only be used interactively, and only from the initial process.

The command yields control of terminal input to the process p, which must have used with-terminal-input to request access to the terminal input stream.

[Function]

join-process process &optional default => values
Waits for a specified process to complete and returns the values that that process's initial function returned.

Arguments and Values:

process---a process, typically created by process-run-function or by make-process

default---A default value to be returned if the specified process doesn't exit normally.

values---The values returned by the specified process's initial function if that function returns, or the value of the default argument, otherwise.

Description:

Waits for the specified process to terminate. If the process terminates "normally" (if its initial function returns), returns the values that that initial function returnes. If the process does not terminate normally (e.g., if it's terminated via process-kill and a default argument is provided, returns the value of that default argument. If the process doesn't terminate normally and no default argument is provided, signals an error.

A process can't successfully join itself, and only one process can successfully receive notification of another process's termination.


Previous Section Next Chapter Table of Contents Glossary Index