Paste number 1644: BORDEAUX-MP

Paste number 1644: BORDEAUX-MP
Pasted by: dan_b
When:10 years, 5 months ago
Share:Tweet this! | http://paste.lisp.org/+19O
Channel:#lisp
Paste contents:
Raw Source | XML | Display As
BORDEAUX-MP is a proposed standard for a minimal MP/Threading
interface.  This is similar to the CLIM-SYS threading and lock
support, but for the following broad differences:

1) Some behaviours are defined in additional detail: attention has
been given to special variable interaction, whether and when cleanup
forms are run.  Some behaviours are defined in less detail: an
implementation that does not support multiple processes is not
required to use a new list (nil) for a lock, for example.

2) Many functions which would be difficult, dangerous or inefficient
to provide on some implementations have been removed.  Chiefly these
are functions such as process-wait which expect for efficiency that
the process scheduler is written in Lisp and 'hookable', which can't
sensibly be done if the scheduler is external to the Lisp image, or
the system has more than one CPU.

3) Unbalanced ACQUIRE-LOCK and RELEASE-LOCK functions have been added 

4) Posix-style condition variables have been added, as it's not
otherwise possible to implement them correctly using the other
operations that are specified.

Terminology note: to remain consistent with the vocabulary of existing
Lisp environments, the term <b>process</b> as used here describes a
context of execution which shares its Lisp environment with other such
processes.  This is <i>not</i> the concept of a process in some
operating systems (e.g. Unix, NT) in which each OS process has an
independent address space and cannot access or alter objects in other
processes.  What we call a "process" here is typically known as a
"thread" in those circles.

Processes (in the Lisp sense) may be implemented using whatever
applicable techniques are provided by the operating system: user-space
scheduling, kernel-based LWPs or anything else that does the job.

Some parts of this specification can also be implemented in a Lisp
that does not support multiple processes.  Process creation and some
process inspection operations will not work, but the locking functions
are still present (though they may do nothing) so that thread-safe
code can be compiled on both threaded and single-thread
implementations without need of conditionals.

To avoid conflict with existing MP/threading interfaces in
implementations, these symbols live in the BORDEAUX-MP package.
Implementations and/or users may also make them visible or exported in
other more traditionally named packages.

* Process Creation

make-process function &key name [Function]

Creates a process named NAME. The new process will evaluate the
function FUNCTION. On systems that do not support multi-processing,
make-process will signal an error.  

Initial values of special variables in the new process are
implementation-defined.  For example, they may be the same as in the
process that called make-process, or set from the global values of the
variables, or from a configurable list.

The new thread may bind special variables: the new bindings are local
to that thread.  If it assigns to special variables without rebinding
them, the effect is implementation-defined.

current-process [Function]

Returns the process object for the calling process. This is the same
kind of object as would be returned by MAKE-PROCESS.

processp object [Predicate]

Returns true if object is a process, otherwise NIL.

process-name process [Function]

Returns the name of the process, as supplied to MAKE-PROCESS


* Atomic operations

atomic-incf reference [Function]
atomic-decf reference [Function]

Increments (or decrements) the fixnum value referred to by reference
as a single, atomic operation.  If the operation would take the value
out of fixnum range, behaviour is undefined.

* Resource contention: locks and recursive locks

make-lock &optional name [Function]

Creates a lock whose name is name.  If the system does not support
multiple processes this will still work, but the lock is just not
useful for very much.

acquire-lock lock wait-p [Function]

Acquire the lock LOCK for the calling process.  If the lock is not
available, and if WAIT-P is supplied and non-NIL, wait until it is.

This specification does not define what happens if a process attempts
to acquire a lock that it already holds.  For applications that
require locks to be safe when acquired recursively, see instead
MAKE-RECURSIVE-LOCK and friends.

release-lock lock [Function]

Release LOCK.  It is an error to call this unless the lock has
previously been acquired (and not released) by the same process.  If
other processes are waiting for the lock, the ACQUIRE-LOCK call in 
one of them will now be able to continue.

with-lock-held (place) &body body [Macro]

Evaluates BODY with the lock named by PLACE, which is a reference to a
lock created by MAKE-LOCK.  WITH-LOCK-HELD is implemented as if by use
of ACQUIRE-LOCK, RELEASE-LOCK and UNWIND-PROTECT.

If the process is interrupted and unable to acquire the lock, BODY
will not be evaluated.

make-recursive-lock &optional name [Function]

Creates a recursive lock whose name is NAME.  A recursive lock differs
from an ordinary lock in that a process that already holds the
recursive lock can acquire it again without blocking.  The process
must then release the lock twice before it becomes available for
another process.

acquire-recursive-lock lock [Function]

As for ACQUIRE-LOCK, but for recursive locks.

release-recursive-lock lock [Function]

Release the recursive LOCK.  The lock will only become free after as
many Release operations as there have been Acquire operations.  See
RELEASE-LOCK for other information.

with-recursive-lock-held (place &key timeout) &body body [Macro]

Evaluates BODY with the recursive lock named by PLACE, which is a
reference to a recursive lock created by MAKE-RECURSIVE-LOCK.  See
WITH-LOCK-HELD etc etc

* Resource contention: condition variables

Condition variables are for use when you have a shared resource with
some kind of state, and the decision as to which process may run next
is dependent on that state.  For example: a buffer with readers and a
writer, where the readers can only run when there is data in the
buffer, and the writer can only refill the buffer when it is empty.

There are three parts to any system involving a condition variable

 - the condition itself.  In this example it would be "buffer is (not)
empty" and "buffer is not empty".  This is not apparent in the actual
code.

 - a lock to protect the sections of code that evaluate the condition.

 - a condition-variable object; this is essentially a queue of
processes waiting for the condition to change.

make-condition-variable () [function]

Returns a new condition-variable object for use with CONDITION-WAIT
and CONDITION-NOTIFY.

condition-wait (condition-variable lock)  [function]

Atomically release LOCK and enqueue ourselves waiting for
CONDITION-VARIABLE.  The process will resume when another thread has
notified us using CONDITION-NOTIFY, or we are interrupted, or in other
implementation-dependent circumstances: the caller must always test
the condition on waking before continuing normal processing.

However and for whatever reason the process is resumed, the system
always reacquires LOCK before returning to the caller.  It is an error
to call this unless from the thread that holds LOCK.

In an implementation that does not support multiple processes, this
function signals an error.

condition-notify (condition-variable)  [function]

Notify one or more of the processes waiting for CONDITION-VARIABLE.
The caller needs to acquire the lock associated with the condition
variable before calling this.

In an implementation that does not support multiple processes, this
function has no effect.

process-yield [Function]

Allows other processes to run.  It may be necessary or desirable to
call this periodically in some implementations; others may schedule
processes automatically.  On systems that do not support
multi-processing, this does nothing.


* Introspection/debugging

The following functions may be provided for debugging purposes, but
are not advised to be called from normal user code.

all-processes [Function]

Returns a sequence of all of the processes.

process-interrupt process function [Function]

Interrupt PROCESS and cause it to evaluate FUNCTION before continuing
with the interrupted path of execution.  This may not be a good idea
if PROCESS is holding locks or doing anything important.  On systems
that do not support multiple processes, this function signals an
error.

destroy-process process [Function]

Terminates the process PROCESS, which is an object as returned by
MAKE-PROCESS.  This should be used with caution: it is
implementation-defined whether the process runs cleanup forms or
releases its locks first.

Destroying the calling process is an error.

This paste has no annotations.

Colorize as:
Show Line Numbers

Lisppaste pastes can be made by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively.