Extensions

SBCL is derived from CMU CL, which implements many extensions to the ANSI standard. SBCL doesn't support as many extensions as CMU CL, but it still has quite a few.

Things Which Might Be In The Next ANSI Standard

SBCL provides extensive support for calling external C code, described in its own chapter.

SBCL provides additional garbage collection functionality not specified by ANSI. Weak pointers allow references to objects to be maintained without keeping them from being GCed. And "finalization" hooks are available to cause code to be executed when an object has been GCed.

SBCL supports Gray streams, user-overloadable CLOS classes whose instances can be used as Lisp streams (e.g. passed as the first argument to format). Additionally, the bundled contrib module sb-simple-streams implements a subset of the Franz Allegro simple-streams proposal.

SBCL supports a MetaObject Protocol which is intended to be compatible with AMOP; present exceptions to this (as distinct from current bugs) are:

  • the abstract metaobject class is not present in the class hierarchy;

  • the standard-object and funcallable-standard-object classes are disjoint;

  • compute-effective-method only returns one value, not two;

  • the system-supplied :around method for compute-slots specialized on funcallable-standard-class does not respect the requested order from a user-supplied primary method.

Threading (a.k.a Multiprocessing)

SBCL (as of version 0.8.3, on Linux x86 only) supports a fairly low-level threading interface that maps onto the host operating system's concept of threads or lightweight processes.

Lisp-level view

A rudimentary interface to creating and managing multiple threads can be found in the sb-thread package. This is intended for public consumption, so look at the exported symbols and their documentation strings.

Dynamic bindings to symbols are per-thread. Signal handlers are per-thread.

Mutexes and condition variables are available for managing access to shared data: see

  • (apropos "mutex" :sb-thread)
  • (apropos "condition" :sb-thread)
  • and the waitqueue structure

and poke around in their documentation strings.

Sessions

If the user has multiple views onto the same Lisp image (for example, using multiple terminals, or a windowing system, or network access) they are typically set up as multiple `sessions' such that each view has its own collection of foreground/background/stopped threads. A thread which wishes to create a new session can use the sb-thread:with-new-session to remove itself from the current session (which it shares with its parent and siblings) and create a fresh one. See also sb-thread:make-listener-thread.

Within a single session, threads arbitrate between themselves for the user's attention. A thread may be in one of three notional states: foreground, background, or stopped. When a background process attempts to print a repl prompt or to enter the debugger, it will stop and print a message saying that it has stopped. The user at his leisure may switch to that thread to find out what it needs. If a background thread enters the debugger, selecting any restart will put it back into the background before it resumes. Arbitration for the input stream is managed by calls to sb-thread:get-foreground (which may block) and sb-thread:release-foreground.

sb-ext:quit terminates all threads in the current session, but leaves other sessions running

Implementation (Linux x86)

On Linux x86, this is implemented using clone() and does not involve pthreads. This is not because there is anything wrong with pthreads per se, but there is plenty wrong (from our perspective) with LinuxThreads. SBCL threads are mapped 1:1 onto Linux tasks which share a VM but nothing else - each has its own process id and can be seen in e.g. ps output.

Per-thread local bindings for special variables is achieved using the %fs segment register to point to a per-thread storage area. This may cause interesting results if you link to foreign code that expects threading or creates new threads, and the thread library in question uses %fs in an incompatible way.

There are two implementation mechanisms for queueing. If SBCL was built on an NPTL-capable Linux system (2.6 or some vendor 2.4 ports) with the :SB-FUTEX feature, queuing will be done using the sys_futex() system call if it's available at runtime. Otherwise it will fall back to using sigtimedwait() to sleep and a signal (SIG_DEQUEUE, one of the POSIX RT signals) to wake.

Garbage collection is done with the existing Conservative Generational GC. Allocation is done in small (typically 8k) regions : each thread has its own region so this involves no stopping. However, when a region fills, a lock must be obtained while another is allocated, and when a collection is required, all processes are stopped. This is achieved by sending them signals, which may make for interesting behaviour if they are interrupted in system calls. The streams interface is believed to handle the required system call restarting correctly, but this may be a consideration when making other blocking calls e.g. from foreign library code.

Large amounts of the SBCL library have not been inspected for thread-safety. Some of the obviously unsafe areas have large locks around them, so compilation and fasl loading, for example, cannot be parallelized. Work is ongoing in this area.

A new thread by default is created in the same POSIX process group and session as the thread it was created by. This has an impact on keyboard interrupt handling: pressing your terminal's intr key (typically Control-C) will interrupt all processes in the foreground process group, including Lisp threads that SBCL considers to be notionally `background'. This is undesirable, so background threads are set to ignore the SIGINT signal.

sb-thread:make-listener-thread in addition to creating a new Lisp session makes a new POSIX session, so that pressing Control-C in one window will not interrupt another listener - this has been found to be embarrassing.

Support For Unix

The UNIX command line can be read from the variable sb-ext:*posix-argv*. The UNIX environment can be queried with the sb-ext:posix-getenv function.

The SBCL system can be terminated with sb-ext:quit, (but see notes above about threads and sessions) optionally returning a specified numeric value to the calling Unix process. The normal Unix idiom of terminating on end of file on input is also supported.

Customization Hooks for Users

The behaviour of require when called with only one argument is implementation-defined. In SBCL it calls functions on the user-settable list sb-ext:*module-provider-functions* - see the require documentation string for details.

The toplevel repl prompt may be customized, and the function that reads user input may be replaced completely.

Tools To Help Developers

SBCL provides a profiler and other extensions to the ANSI trace facility. See the online function documentation for trace for more information.

The debugger supports a number of options. Its documentation is accessed by typing help at the debugger prompt.

Documentation for inspect is accessed by typing help at the inspect prompt.

Interface To Low-Level SBCL Implementation

SBCL has the ability to save its state as a file for later execution. This functionality is important for its bootstrapping process, and is also provided as an extension to the user See the documentation for sb-ext:save-lisp-and-die for more information.

Note

SBCL has inherited from CMU CL various hooks to allow the user to tweak and monitor the garbage collection process. These are somewhat stale code, and their interface might need to be cleaned up. If you have urgent need of them, look at the code in src/code/gc.lisp and bring it up on the developers' mailing list.

Note

SBCL has various hooks inherited from CMU CL, like sb-ext:float-denormalized-p, to allow a program to take advantage of IEEE floating point arithmetic properties which aren't conveniently or efficiently expressible using the ANSI standard. These look good, and their interface looks good, but IEEE support is slightly broken due to a stupid decision to remove some support for infinities (because it wasn't in the ANSI spec and it didn't occur to me that it was in the IEEE spec). If you need this stuff, take a look at the code and bring it up on the developers' mailing list.

Efficiency Hacks

The sb-ext:purify function causes SBCL first to collect all garbage, then to mark all uncollected objects as permanent, never again attempting to collect them as garbage. This can cause a large increase in efficiency when using a primitive garbage collector, or a more moderate increase in efficiency when using a more sophisticated garbage collector which is well suited to the program's memory usage pattern. It also allows permanent code to be frozen at fixed addresses, a precondition for using copy-on-write to share code between multiple Lisp processes. is less important with modern generational garbage collectors.

The sb-ext:truly-the declares the type of the result of the operations, producing its argument; the declaration is not checked. In short: don't use it.

The sb-ext:freeze-type declaration declares that a type will never change, which can make type testing (typep, etc.) more efficient for structure types.

The sb-ext:constant-function declaration specifies that a function will always return the same value for the same arguments, which may allow the compiler to optimize calls to it. This is appropriate for functions like sqrt, but is not appropriate for functions like aref, which can change their return values when the underlying data are changed.