This manual is part of the SBCL software system. See the README file for more information.This manual is largely derived from the manual for the CMUCL system, which was produced at Carnegie Mellon University and later released into the public domain. This manual is in the public domain and is provided with absolutely no warranty. See the COPYING and CREDITS files for more information.
Your primary source of SBCL support should probably be the mailing list sbcl-help: in addition to other users SBCL developers monitor this list and are available for advice. As an anti-spam measure subscription is required for posting:
https://lists.sourceforge.net/lists/listinfo/sbcl-help
Remember that the people answering your question are volunteers, so you stand a much better chance of getting a good answer if you ask a good question.
Before sending mail, check the list archives at either
http://sourceforge.net/mailarchive/forum.php?forum_name=sbcl-help
or
http://news.gmane.org/gmane.lisp.steel-bank.general
to see if your question has been answered already. Checking the bug database is also worth it See Reporting Bugs, to see if the issue is already known.
For general advice on asking good questions, see
http://www.catb.org/~esr/faqs/smart-questions.html.
There is no formal organization developing SBCL, but if you need a paid support arrangement or custom SBCL development, we maintain the list of companies and consultants below. Use it to identify service providers with appropriate skills and interests, and contact them directly.
The SBCL project cannot verify the accuracy of the information or the competence of the people listed, and they have provided their own blurbs below: you must make your own judgement of suitability from the available information - refer to the links they provide, the CREDITS file, mailing list archives, CVS commit messages, and so on. Please feel free to ask for advice on the sbcl-help list.
(At present, no companies or consultants wish to advertise paid support or custom SBCL development in this manual).
SBCL uses Launchpad to track bugs. The bug database is available at
https://bugs.launchpad.net/sbcl
Reporting bugs there requires registering at Launchpad. However, bugs can also be reported on the mailing list sbcl-bugs, which is moderated but does not require subscribing.
Simply send email to sbcl-bugs@lists.sourceforge.net and the bug will be checked and added to Launchpad by SBCL maintainers.
Please include enough information in a bug report that someone reading it can reproduce the problem, i.e. don't write
Subject: apparent bug in PRINT-OBJECT (or *PRINT-LENGTH*?) PRINT-OBJECT doesn't seem to work with *PRINT-LENGTH*. Is this a bug?
but instead
Subject: apparent bug in PRINT-OBJECT (or *PRINT-LENGTH*?) In sbcl-1.2.3 running under OpenBSD 4.5 on my Alpha box, when I compile and load the file (DEFSTRUCT (FOO (:PRINT-OBJECT (LAMBDA (X Y) (LET ((*PRINT-LENGTH* 4)) (PRINT X Y))))) X Y) then at the command line type (MAKE-FOO) the program loops endlessly instead of printing the object.
A more in-depth discussion on reporting bugs effectively can be found at
http://www.chiark.greenend.org.uk/~sgtatham/bugs.html.
If you run into a signal related bug, you are getting fatal errors
such as signal N is [un]blocked
or just hangs, and you want to
send a useful bug report then:
:sb-ldb
, see
base-target-features.lisp-expr) and change #define QSHOW_SIGNAL 0
to
#define QSHOW_SIGNAL 1
in src/runtime/runtime.h.
kill -ABRT <pidof sbcl>
.
ba
.
gdb -p <pidof sbcl>
and get backtraces for all threads:
thread apply all ba
.
thread apply all call
backtrace_from_fp($ebp, 100)
. Substitute $ebp
with $rbp
on x86-64. The backtraces will appear in the stdout of the SBCL
process.
SBCL is a mostly-conforming implementation of the ANSI Common Lisp standard. This manual focuses on behavior which is specific to SBCL, not on behavior which is common to all implementations of ANSI Common Lisp.
Essentially every type of non-conformance is considered a bug. (The exceptions involve internal inconsistencies in the standard.) See Reporting Bugs.
SBCL comes with numerous extensions, some in core and some in modules
loadable with require
. Unfortunately, not all of these
extensions have proper documentation yet.
asdf
is a flexible and popular protocol-oriented system
definition tool by Daniel Barlow. see the asdf manual, for
more information.
sb-alien
package allows interfacing with C-code, loading shared
object files, etc. See Foreign Function Interface.
sb-grovel
can be used to partially automate generation of
foreign function interface definitions. See sb-grovel.
serve-event
) for doing
non-blocking IO on multiple streams without using threads.
sb-mop
package provides a metaobject protocol for the Common
Lisp Object System as described in Art of Metaobject Protocol.
sequence
class. See Extensible Sequences.
sb-bsd-sockets
is a low-level networking interface, providing
both TCP and UDP sockets. See Networking.
sb-introspect
module offers numerous introspective extensions,
including access to function lambda-lists and a cross referencing
facility.
sb-ext
contains a number of functions for running external
processes, accessing environment variables, etc.
sb-posix
module provides a lispy interface to standard POSIX
facilities.
sb-gray
is an implementation of Gray Streams. See Gray Streams.
sb-simple-streams
is an implementation of the simple
streams API proposed by Franz Inc. See Simple Streams.
sb-profile
is a exact per-function profiler. See Deterministic Profiler.
sb-sprof
is a statistical profiler, capable of call-graph
generation and instruction level profiling, which also supports
allocation profiling. See Statistical Profiler.
sb-aclrepl
provides an Allegro CL -style toplevel for SBCL,
as an alternative to the classic CMUCL-style one. See sb-aclrepl.
sb-cltl2
module provides compiler-let
and environment
access functionality described in Common Lisp The Language, 2nd
Edition which were removed from the language during the ANSI
standardization process.
:executable
argument to Function sb-ext:save-lisp-and-die can produce a `standalone' executable
containing both an image of the current Lisp session and an SBCL
runtime.
sb-rotate-byte
provides an efficient primitive for bitwise
rotation of integers, an operation required by e.g. numerous
cryptographic algorithms, but not available as a primitive in ANSI
Common Lisp. See sb-rotate-byte.
sb-rt
module is a simple yet attractive regression and
unit-test framework.
sb-md5
is an implementation of the MD5 message digest algorithm
for Common Lisp, using the modular arithmetic optimizations provided
by SBCL. See sb-md5.
The information in this section describes some of the ways that SBCL deals with choices that the ANSI standard leaves to the implementation.
Declarations are generally treated as assertions. This general principle, and its implications, and the bugs which still keep the compiler from quite satisfying this principle, are discussed in Declarations as Assertions.
SBCL fasl-format is binary compatible only with the exact SBCL version it was generated with. While this is obviously suboptimal, it has proven more robust than trying to maintain fasl compatibility across versions: accidentally breaking things is far too easy, and can lead to hard to diagnose bugs.
The following snippet handles fasl recompilation automatically for ASDF-based systems, and makes a good candidate for inclusion in the user or system initialization file (see Initialization Files.)
(require :asdf) ;;; If a fasl was stale, try to recompile and load (once). (defmethod asdf:perform :around ((o asdf:load-op) (c asdf:cl-source-file)) (handler-case (call-next-method o c) ;; If a fasl was stale, try to recompile and load (once). (sb-ext:invalid-fasl () (asdf:perform (make-instance 'asdf:compile-op) c) (call-next-method))))
SBCL is essentially a compiler-only implementation of Common Lisp.
That is, for all but a few special cases, eval
creates a lambda
expression, calls compile
on the lambda expression to create a
compiled function, and then calls funcall
on the resulting
function object. A more traditional interpreter is also available on
default builds; it is usually only called internally. This is
explicitly allowed by the ANSI standard, but leads to some oddities;
e.g. at default settings, functionp
and
compiled-function-p
are equivalent, and they collapse into the
same function when SBCL is built without the interpreter.
SBCL is quite strict about ANSI's definition of defconstant
.
ANSI says that doing defconstant
of the same symbol more than
once is undefined unless the new value is eql
to the old value.
Conforming to this specification is a nuisance when the “constant”
value is only constant under some weaker test like string=
or
equal
.
It's especially annoying because, in SBCL, defconstant
takes
effect not only at load time but also at compile time, so that just
compiling and loading reasonable code like
(defconstant +foobyte+ '(1 4))
runs into this undefined behavior. Many implementations of Common Lisp try to help the programmer around this annoyance by silently accepting the undefined code and trying to do what the programmer probably meant.
SBCL instead treats the undefined behavior as an error. Often such
code can be rewritten in portable ANSI Common Lisp which has the
desired behavior. E.g., the code above can be given an exactly defined
meaning by replacing defconstant
either with
defparameter
or with a customized macro which does the right
thing, e.g.
(defmacro define-constant (name value &optional doc) `(defconstant ,name (if (boundp ',name) (symbol-value ',name) ,value) ,@(when doc (list doc))))
or possibly along the lines of the defconstant-eqx
macro used
internally in the implementation of SBCL itself. In circumstances
where this is not appropriate, the programmer can handle the condition
type sb-ext:defconstant-uneql
, and choose either the
continue or abort restart as appropriate.
SBCL gives style warnings about various kinds of perfectly legal code, e.g.
defmethod
without a preceding defgeneric
;
defun
s of the same symbol in different units;
*foo*
style,
and lexical variables unconventionally named in the *foo*
style
This causes friction with people who point out that other ways of
organizing code (especially avoiding the use of defgeneric
) are
just as aesthetically stylish. However, these warnings should be read
not as “warning, bad aesthetics detected, you have no style” but
“warning, this style keeps the compiler from understanding the code
as well as you might like.” That is, unless the compiler warns about
such conditions, there's no way for the compiler to warn about some
programming errors which would otherwise be easy to overlook. (Related
bug: The warning about multiple defun
s is pointlessly annoying
when you compile and then load a function containing defun
wrapped in eval-when
, and ideally should be suppressed in that
case, but still isn't as of SBCL 0.7.6.)
Though SBCL can be used running “bare”, the recommended mode of development is with an editor connected to SBCL, supporting not only basic lisp editing (paren-matching, etc), but providing among other features an integrated debugger, interactive compilation, and automated documentation lookup.
Currently SLIME1 (Superior Lisp Interaction Mode for Emacs) together with Emacs is recommended for use with SBCL, though other options exist as well.
SLIME can be downloaded from http://www.common-lisp.net/project/slime/.
CLHS (Common Lisp Hyperspec) is a hypertext version of the ANSI standard, made freely available by LispWorks – an invaluable reference.
See: http://www.lispworks.com/reference/HyperSpec/index.html
SBCL can generate stand-alone executables. The generated executables
include the SBCL runtime itself, so no restrictions are placed on
program functionality. For example, a deployed program can call
compile
and load
, which requires the compiler to be present
in the executable. For further information, See Function sb-ext:save-lisp-and-die.
The SBCL website at http://www.sbcl.org/ has some general information, plus links to mailing lists devoted to SBCL, and to archives of these mailing lists. Subscribing to the mailing lists sbcl-help and sbcl-announce is recommended: both are fairly low-volume, and help you keep abreast with SBCL development.
Documentation for non-ANSI extensions for various commands is
available online from the SBCL executable itself. The extensions
for functions which have their own command prompts (e.g. the debugger,
and inspect
) are documented in text available by typing
help at their command prompts. The extensions for functions
which don't have their own command prompt (such as trace
) are
described in their documentation strings, unless your SBCL was
compiled with an option not to include documentation strings, in which
case the documentation strings are only readable in the source code.
Besides this user manual both SBCL source and binary distributions include some other SBCL-specific documentation files, which should be installed along with this manual on your system, e.g. in /usr/local/share/doc/sbcl/.
If you're interested in the development of the SBCL system itself, then subscribing to sbcl-devel is a good idea.
SBCL internals documentation – besides comments in the source – is currently maintained as a wiki-like website: http://sbcl-internals.cliki.net/.
Some low-level information describing the programming details of the conversion from CMUCL to SBCL is available in the doc/FOR-CMUCL-DEVELOPERS file in the SBCL distribution, though it is not installed by default.
The Common Lisp internet community is fairly diverse: news://comp.lang.lisp is fairly high volume newsgroup, but has a rather poor signal/noise ratio. Various special interest mailing lists and IRC tend to provide more content and less flames. http://www.lisp.org and http://www.cliki.net contain numerous pointers places in the net where lispers talks shop.
For a wealth of information about free Common Lisp libraries and tools we recommend checking out CLiki: http://www.cliki.net/.
If you're not a programmer and you're trying to learn, many introductory Lisp books are available. However, we don't have any standout favorites. If you can't decide, try checking the Usenet news://comp.lang.lisp FAQ for recent recommendations.
If you are an experienced programmer in other languages but need to learn about Common Lisp, some books stand out:
You can work productively with SBCL without knowing or understanding anything about where it came from, how it is implemented, or how it extends the ANSI Common Lisp standard. However, a little knowledge can be helpful in order to understand error messages, to troubleshoot problems, to understand why some parts of the system are better debugged than others, and to anticipate which known bugs, known performance problems, and missing extensions are likely to be fixed, tuned, or added.
SBCL is descended from CMUCL, which is itself descended from Spice Lisp, including early implementations for the Mach operating system on the IBM RT, back in the 1980s. Some design decisions from that time are still reflected in the current implementation:
SBCL also inherited some newer architectural features from CMUCL. The most important is that on some architectures it has a generational garbage collector (“GC”), which has various implications (mostly good) for performance. These are discussed in another chapter, Efficiency.
SBCL has diverged from CMUCL in that SBCL is now essentially a
“compiler-only implementation” of Common Lisp. This is a change in
implementation strategy, taking advantage of the freedom “any of these
facilities might share the same execution strategy” guaranteed in the
ANSI specification section 3.1 (“Evaluation”). It does not mean SBCL
can't be used interactively, and in fact the change is largely invisible
to the casual user, since SBCL still can and does execute code
interactively by compiling it on the fly. (It is visible if you know how
to look, like using compiled-function-p
; and it is visible in the
way that SBCL doesn't have many bugs which behave differently in
interpreted code than in compiled code.) What it means is that in SBCL,
the eval
function only truly “interprets” a few easy kinds of
forms, such as symbols which are boundp
. More complicated forms
are evaluated by calling compile
and then calling funcall
on the returned result.
The direct ancestor of SBCL is the x86 port of CMUCL. This port was in some ways the most cobbled-together of all the CMUCL ports, since a number of strange changes had to be made to support the register-poor x86 architecture. Some things (like tracing and debugging) do not work particularly well there. SBCL should be able to improve in these areas (and has already improved in some other areas), but it takes a while.
On the x86 SBCL – like the x86 port of CMUCL – uses a conservative GC. This means that it doesn't maintain a strict separation between tagged and untagged data, instead treating some untagged data (e.g. raw floating point numbers) as possibly-tagged data and so not collecting any Lisp objects that they point to. This has some negative consequences for average time efficiency (though possibly no worse than the negative consequences of trying to implement an exact GC on a processor architecture as register-poor as the X86) and also has potentially unlimited consequences for worst-case memory efficiency. In practice, conservative garbage collectors work reasonably well, not getting anywhere near the worst case. But they can occasionally cause odd patterns of memory usage.
The fork from CMUCL was based on a major rewrite of the system bootstrap process. CMUCL has for many years tolerated a very unusual “build” procedure which doesn't actually build the complete system from scratch, but instead progressively overwrites parts of a running system with new versions. This quasi-build procedure can cause various bizarre bootstrapping hangups, especially when a major change is made to the system. It also makes the connection between the current source code and the current executable more tenuous than in other software systems – it's easy to accidentally “build” a CMUCL system containing characteristics not reflected in the current version of the source code.
Other major changes since the fork from CMUCL include
To run SBCL type sbcl at the command line.
You should end up in the toplevel REPL (read, eval, print -loop), where you can interact with SBCL by typing expressions.
$ sbcl This is SBCL 0.8.13.60, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. * (+ 2 2) 4 * (exit) $
See also Command Line Options and Stopping SBCL.
To run SBCL as an inferior-lisp from Emacs in your .emacs do something like:
;;; The SBCL binary and command-line arguments (setq inferior-lisp-program "/usr/local/bin/sbcl --noinform")
For more information on using SBCL with Emacs, see Editor Integration.
Standard Unix tools that are interpreters follow a common command line
protocol that is necessary to work with “shebang scripts”. SBCL supports
this via the --script
command line option.
Example file (hello.lisp):
#!/usr/local/bin/sbcl --script (write-line "Hello, World!")
Usage examples:
$ ./hello.lisp Hello, World!
$ sbcl --script hello.lisp Hello, World!
SBCL can be stopped at any time by calling sb-ext:exit
,
optionally returning a specified numeric value to the calling process.
See Threading for information about terminating individual threads.
Terminates the process, causing
sbcl
to exit withcode
.code
defaults to 0 whenabort
is false, and 1 when it is true.When
abort
is false (the default), current thread is first unwound,*exit-hooks*
are run, other threads are terminated, and standard output streams are flushed beforesbcl
calls exit(3)--
at which point atexit(3) functions will run. If multiple threads callexit
withabort
being false, the first one to call it will complete the protocol.When
abort
is true,sbcl
exits immediately by calling _exit(2) without unwinding stack, or calling exit hooks. Note that _exit(2) does not call atexit(3) functions unlike exit(3).Recursive calls to
exit
causeexit
to behave as itabort
was true.
timeout
controls waiting for other threads to terminate whenabort
isnil
. Once current thread has been unwound and*exit-hooks*
have been run, spawning new threads is prevented and all other threads are terminated by callingterminate-thread
on them. The system then waits for them to finish usingjoin-thread
, waiting at most a totaltimeout
seconds for all threads to join. Those threads that do not finish in time are simply ignored while the exit protocol continues.timeout
defaults to*exit-timeout*
, which in turn defaults to 60.timeout
nil
means to wait indefinitely.Note that
timeout
applies only tojoin-thread
, not*exit-hooks*
. Sinceterminate-thread
is asynchronous, getting multithreaded application termination with complex cleanups right using it can be tricky. To perform an orderly synchronous shutdown use an exit hook instead of relying on implicit thread termination.Consequences are unspecified if serious conditions occur during
exit
excepting errors from*exit-hooks*
, which cause warnings and stop execution of the hook that signaled, but otherwise allow the exit process to continue normally.
By default SBCL also exits on end of input, caused either by user pressing Control-D on an attached terminal, or end of input when using SBCL as part of a shell pipeline.
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.
Save a "core image", i.e. enough information to restart a Lisp process later in the same state, in the file of the specified name. Only global state is preserved: the stack is unwound in the process.
The following
&key
arguments are defined:
:toplevel
- The function to run when the created core file is resumed. The default function handles command line toplevel option processing and runs the top level read-eval-print loop. This function returning is equivalent to
(sb-ext:exit :code 0)
being called.
toplevel
functions should always provide anabort
restart: otherwise code they call will run without one.:executable
- If true, arrange to combine the
sbcl
runtime and the core image to create a standalone executable. If false (the default), the core image will not be executable on its own. Executable images always behave as if they were passed the –noinform runtime option.:save-runtime-options
- If true, values of runtime options –dynamic-space-size and –control-stack-size that were used to start
sbcl
are stored in the standalone executable, and restored when the executable is run. This also inhibits normal runtime option processing, causing all command line arguments to be passed to the toplevel. Meaningless if:executable
isnil
.:purify
- If true (the default on cheneygc), do a purifying
gc
which moves all dynamically allocated objects into static space. This takes somewhat longer than the normalgc
which is otherwise done, but it's only done once, and subsequent GC's will be done less often and will take less time in the resulting core file. See thepurify
function. This parameter has no effect on platforms using the generational garbage collector.:root-structures
- This should be a list of the main entry points in any newly loaded systems. This need not be supplied, but locality and/or
gc
performance may be better if they are. Meaningless if:purify
isnil
. See thepurify
function.:environment-name
- This is also passed to the
purify
function when:purify
ist
. (rarely used):compression
- This is only meaningful if the runtime was built with the
:sb-core-compression
feature enabled. Ifnil
(the default), saves to uncompressed core files. If:sb-core-compression
was enabled at build-time, the argument may also be an integer from -1 to 9, corresponding to zlib compression levels, ort
(which is equivalent to the default compression level, -1).:application-type
- Present only on Windows and is meaningful only with
:executable
t
. Specifies the subsystem of the executable,:console
or:gui
. The notable difference is that:gui
doesn't automatically create a console window. The default is:console
.The save/load process changes the values of some global variables:
*standard-output*
,*debug-io*
, etc.- Everything related to open streams is necessarily changed, since the
os
won't let us preserve a stream across save and load.*default-pathname-defaults*
- This is reinitialized to reflect the working directory where the saved core is loaded.
save-lisp-and-die
interacts withsb-alien:load-shared-object:
see its documentation for details.On threaded platforms only a single thread may remain running after
sb-ext:*save-hooks*
have run. Applications using multiple threads can besave-lisp-and-die
friendly by registering a save-hook that quits any additional threads, and an init-hook that restarts them.This implementation is not as polished and painless as you might like:
This isn't because we like it this way, but just because there don't seem to be good quick fixes for either limitation and no one has been sufficiently motivated to do lengthy fixes.
- It corrupts the current Lisp image enough that the current process needs to be killed afterwards. This can be worked around by forking another process that saves the core.
- There is absolutely no binary compatibility of core images between different runtime support programs. Even runtimes built from the same sources at different times are treated as incompatible for this purpose.
This is a list of functions which are called in an unspecified order before creating a saved core image. Unused by
sbcl
itself: reserved for user and applications.
In cases where the standard initialization files have already been loaded into the saved core, and alternative ones should be used (or none at all), SBCL allows customizing the initfile pathname computation.
Designator for a function of zero arguments called to obtain a pathname designator for the default sysinit file, or
nil
. If the function returnsnil
, no sysinit file is used unless one has been specified on the command-line.
Designator for a function of zero arguments called to obtain a pathname designator or a stream for the default userinit file, or
nil
. If the function returnsnil
, no userinit file is used unless one has been specified on the command-line.
To facilitate distribution of SBCL applications using external resources, the filesystem location of the SBCL core file being used is available from Lisp.
SBCL can also be configured to exit if an unhandled error occurs, which is mainly useful for acting as part of a shell pipeline; doing so under most other circumstances would mean giving up large parts of the flexibility and robustness of Common Lisp. See Debugger Entry.
Command line options can be considered an advanced topic; for ordinary interactive use, no command line arguments should be necessary.
In order to understand the command line argument syntax for SBCL, it is helpful to understand that the SBCL system is implemented as two components, a low-level runtime environment written in C and a higher-level system written in Common Lisp itself. Some command line arguments are processed during the initialization of the low-level runtime environment, some command line arguments are processed during the initialization of the Common Lisp system, and any remaining command line arguments are passed on to user code.
The full, unambiguous syntax for invoking SBCL at the command line is:
sbcl runtime-option* --end-runtime-options
toplevel-option* --end-toplevel-options
user-options*
For convenience, the --end-runtime-options
and
--end-toplevel-options
elements can be omitted. Omitting these
elements can be convenient when you are running the program
interactively, and you can see that no ambiguities are possible with
the option values you are using. Omitting these elements is probably a
bad idea for any batch file where any of the options are under user
control, since it makes it impossible for SBCL to detect erroneous
command line input, so that erroneous command line arguments will be
passed on to the user program even if they was intended for the
runtime system or the Lisp system.
--core
corefilename--dynamic-space-size
megabytes--control-stack-size
megabytes--noinform
--noprint
and
--disable-debugger
options.
--disable-ldb
--lose-on-corruption
--script
filename--noinform
--disable-ldb
--lose-on-corruption
--end-runtime-options
--script
filename. See the
description of --script
as a toplevel option below. If there
are no other command line arguments following --script
, the
filename argument can be omitted.
--merge-core-pages
--no-merge-core-pages
--default-merge-core-pages
--help
--version
In the future, runtime options may be added to control behaviour such as lazy allocation of memory.
Runtime options, including any –end-runtime-options option, are stripped out of the command line before the Lisp toplevel logic gets a chance to see it.
--sysinit
filename--no-sysinit
--sysinit
option is ignored.
--userinit
filename--no-userinit
--userinit
option is ignored.
--eval
command--eval
option can be used, and all will be
read and executed, in the order they appear on the command line.
--load
filename--eval '(load "
filename")'
. The
special syntax is intended to reduce quoting headaches when invoking
SBCL from shell scripts.
--noprint
--noinform
runtime
option, this makes it easier to write Lisp "scripts" which work
cleanly in Unix pipelines.
--disable-debugger
--eval
and
--load
options. See sb-ext:disable-debugger
for details.
See Debugger Entry.
--script
filename--no-userinit
--no-sysinit
--disable-debugger
--end-toplevel-options
.
Causes the system to load the specified file instead of entering the read-eval-print-loop, and exit afterwards. If the file begins with a shebang line, it is ignored.
If there are no other command line arguments following, the filename can be omitted: this causes the script to be loaded from standard input instead. Shebang lines in standard input script are currently not ignored.
In either case, if there is an unhandled error (e.g. end of file, or a
broken pipe) on either standard input, standard output, or standard
error, the script silently exits with code 0. This allows e.g. safely
piping output from SBCL to head -n1
or similar.
SBCL processes initialization files with read
and eval
,
not load
; hence initialization files can be used to set startup
*package*
and *readtable*
, and for proclaiming a global
optimization policy.
Defaults to $SBCL_HOME/sbclrc, or if that doesn't exist to
/etc/sbclrc. Can be overridden with the command line option
--sysinit
or --no-sysinit
.
The system initialization file is intended for system administrators and software packagers to configure locations of installed third party modules, etc.
Defaults to $HOME/.sbclrc. Can be overridden with the
command line option --userinit
or --no-userinit
.
The user initialization file is intended for personal customizations, such as loading certain modules at startup, defining convenience functions to use in the REPL, handling automatic recompilation of FASLs (see FASL Format), etc.
Neither initialization file is required.
SBCL provides hooks into the system initialization and exit.
This is a list of functions which are called in an unspecified order when a saved core image starts up, after the system itself has been initialized. Unused by
sbcl
itself: reserved for user and applications.
This is a list of functions which are called in an unspecified order when
sbcl
process exits. Unused bysbcl
itself: reserved for user and applications. Using(sb-ext:exit :abort t)
, or calling exit(3) directly will circumvent these hooks.
This chapter will discuss most compiler issues other than efficiency, including compiler error messages, the SBCL compiler's unusual approach to type safety in the presence of type declarations, the effects of various compiler optimization policies, and the way that inlining and open coding may cause optimized code to differ from a naive translation. Efficiency issues are sufficiently varied and separate that they have their own chapter, Efficiency.
The compiler can be quite verbose in its diagnostic reporting, rather more then some users would prefer – the amount of noise emitted can be controlled, however.
To control emission of compiler diagnostics (of any severity other
than error
: see Diagnostic Severity) use the
sb-ext:muffle-conditions
and sb-ext:unmuffle-conditions
declarations, specifying the type of condition that is to be muffled
(the muffling is done using an associated muffle-warning
restart).
Global control:
;;; Muffle compiler-notes globally (declaim (sb-ext:muffle-conditions sb-ext:compiler-note))
Local control:
;;; Muffle compiler-notes based on lexical scope (defun foo (x) (declare (optimize speed) (fixnum x) (sb-ext:muffle-conditions sb-ext:compiler-note)) (values (* x 5) ; no compiler note from this (locally (declare (sb-ext:unmuffle-conditions sb-ext:compiler-note)) ;; this one gives a compiler note (* x -5))))
Syntax: type*
Muffles the diagnostic messages that would be caused by compile-time signals of given types.
Syntax: type*
Cancels the effect of a previous
sb-ext:muffle-conditions
declaration.
Various details of how the compiler messages are printed can be
controlled via the alist
sb-ext:*compiler-print-variable-alist*
.
an association list describing new bindings for special variables to be used by the compiler for error-reporting, etc. Eg.
((*PRINT-LENGTH* . 10) (*PRINT-LEVEL* . 6) (*PRINT-PRETTY* . NIL))The variables in the
car
positions are bound to the values in thecdr
during the execution of some debug commands. When evaluating arbitrary expressions in the debugger, the normal values of the printer control variables are in effect.Initially empty,
*compiler-print-variable-alist*
is Typically used to specify bindings for printer control variables.
For information about muffling warnings signaled outside of the compiler, see Customization Hooks for Users.
There are four levels of compiler diagnostic severity:
The first three levels correspond to condition classes which are
defined in the ANSI standard for Common Lisp and which have special
significance to the compile
and compile-file
functions.
These levels of compiler error severity occur when the compiler
handles conditions of these classes.
The fourth level of compiler error severity, note, corresponds
to the sb-ext:compiler-note
, and is used for problems which are
too mild for the standard condition classes, typically hints about how
efficiency might be improved. The sb-ext:code-deletion-note
, a
subtype of compiler-note
, is signalled when the compiler
deletes user-supplied code after proving that the code in question is
unreachable.
Future work for SBCL includes expanding this hierarchy of types to allow more fine-grained control over emission of diagnostic messages.
Class precedence list:
compiler-note, condition, t
Root of the hierarchy of conditions representing information discovered by the compiler that the user might wish to know, but which does not merit a
style-warning
(or any more serious condition).
Class precedence list:
code-deletion-note, compiler-note, condition, t
A condition type signalled when the compiler deletes code that the user has written, having proved that it is unreachable.
The messages emitted by the compiler contain a lot of detail in a terse format, so they may be confusing at first. The messages will be illustrated using this example program:
(defmacro zoq (x) `(roq (ploq (+ ,x 3)))) (defun foo (y) (declare (symbol y)) (zoq y))
The main problem with this program is that it is trying to add
3
to a symbol. Note also that the functions roq
and
ploq
aren't defined anywhere.
When processing this program, the compiler will produce this warning:
; file: /tmp/foo.lisp ; in: DEFUN FOO ; (ZOQ Y) ; --> ROQ PLOQ ; ==> ; (+ Y 3) ; ; caught WARNING: ; Asserted type NUMBER conflicts with derived type (VALUES SYMBOL &OPTIONAL).
In this example we see each of the six possible parts of a compiler diagnostic:
with-compilation-unit
is used to delay undefined warnings.
defun
for
foo
.
compile
or in the top level form read from the source file. In
this example, the expansion of the zoq
macro was responsible
for the message.
roq
and ploq
. These calls resulted from the
expansion of the zoq
macro.
y
.
+
requires that its arguments are all of type number
,
the compiler has derived that y
will evaluate to a
symbol
. Note that ‘(VALUES SYMBOL &OPTIONAL)’ expresses
that y
evaluates to precisely one value.
Note that each part of the message is distinctively marked:
Each part of the message is more specific than the preceding one. If consecutive messages are for nearby locations, then the front part of the messages would be the same. In this case, the compiler omits as much of the second message as in common with the first. For example:
; file: /tmp/foo.lisp ; in: DEFUN FOO ; (ZOQ Y) ; --> ROQ ; ==> ; (PLOQ (+ Y 3)) ; ; caught STYLE-WARNING: ; undefined function: PLOQ ; ==> ; (ROQ (PLOQ (+ Y 3))) ; ; caught STYLE-WARNING: ; undefined function: ROQ
In this example, the file, definition and original source are identical for the two messages, so the compiler omits them in the second message. If consecutive messages are entirely identical, then the compiler prints only the first message, followed by: ‘[Last message occurs repeats times]’ where repeats is the number of times the message was given.
If the source was not from a file, then no file line is printed. If the actual source is the same as the original source, then the processing path and actual source will be omitted. If no forms intervene between the original source and the actual source, then the processing path will also be omitted.
The original source displayed will almost always be a list. If the actual source for an message is a symbol, the original source will be the immediately enclosing evaluated list form. So even if the offending symbol does appear in the original source, the compiler will print the enclosing list and then print the symbol as the actual source (as though the symbol were introduced by a macro.)
When the actual source is displayed (and is not a symbol), it will always be code that resulted from the expansion of a macro or a source-to-source compiler optimization. This is code that did not appear in the original source program; it was introduced by the compiler.
Keep in mind that when the compiler displays a source form in an diagnostic message, it always displays the most specific (innermost) responsible form. For example, compiling this function
(defun bar (x) (let (a) (declare (fixnum a)) (setq a (foo x)) a))
gives this error message
; file: /tmp/foo.lisp ; in: DEFUN BAR ; (LET (A) ; (DECLARE (FIXNUM A)) ; (SETQ A (FOO X)) ; A) ; ; caught WARNING: ; Asserted type FIXNUM conflicts with derived type (VALUES NULL &OPTIONAL).
This message is not saying “there is a problem somewhere in this
let
” – it is saying that there is a problem with the
let
itself. In this example, the problem is that a
's
nil
initial value is not a fixnum
.
The processing path is mainly useful for debugging macros, so if you don't write macros, you can probably ignore it. Consider this example:
(defun foo (n) (dotimes (i n *undefined*)))
Compiling results in this error message:
; in: DEFUN FOO ; (DOTIMES (I N *UNDEFINED*)) ; --> DO BLOCK LET TAGBODY RETURN-FROM ; ==> ; (PROGN *UNDEFINED*) ; ; caught WARNING: ; undefined variable: *UNDEFINED*
Note that do
appears in the processing path. This is because
dotimes
expands into:
(do ((i 0 (1+ i)) (#:g1 n)) ((>= i #:g1) *undefined*) (declare (type unsigned-byte i)))
The rest of the processing path results from the expansion of
do
:
(block nil (let ((i 0) (#:g1 n)) (declare (type unsigned-byte i)) (tagbody (go #:g3) #:g2 (psetq i (1+ i)) #:g3 (unless (>= i #:g1) (go #:g2)) (return-from nil (progn *undefined*)))))
In this example, the compiler descended into the block
,
let
, tagbody
and return-from
to reach the
progn
printed as the actual source. This is a place where the
“actual source appears in explanation” rule was applied. The
innermost actual source form was the symbol *undefined*
itself,
but that also appeared in the explanation, so the compiler backed out
one level.
One of the most important features of the SBCL compiler (similar to the original CMUCL compiler, also known as Python) is its fairly sophisticated understanding of the Common Lisp type system and its conservative approach to the implementation of type declarations.
These two features reward the use of type declarations throughout development, even when high performance is not a concern. Also, as discussed in the chapter on performance (see Efficiency), the use of appropriate type declarations can be very important for performance as well.
The SBCL compiler also has a greater knowledge of the Common Lisp
type system than other compilers. Support is incomplete only for types
involving the satisfies
type specifier.
The SBCL compiler treats type declarations differently from most other Lisp compilers. Under default compilation policy the compiler doesn't blindly believe type declarations, but considers them assertions about the program that should be checked: all type declarations that have not been proven to always hold are asserted at runtime.
Remaining bugs in the compiler's handling of types unfortunately provide some exceptions to this rule, see Implementation Limitations.
CLOS slot types form a notable exception. Types declared using the
:type
slot option in defclass
are asserted if and only
if the class was defined in safe code and the slot access
location is in safe code as well. This laxness does not pose
any internal consistency issues, as the CLOS slot types are not
available for the type inferencer, nor do CLOS slot types provide any
efficiency benefits.
There are three type checking policies available in SBCL, selectable
via optimize
declarations.
Used when (or (>= safety 2) (>= safety speed 1))
.
(or (integer -17 -7) (integer 7 17))
is simplified
into (integer -17 17)
.
Note: it is relatively easy to corrupt the heap when weak type checks are used if the program contains type-errors.
Used when (and (< safety 2) (< safety speed))
Note: any type errors in code where type checks are not performed are liable to corrupt the heap.
Used when (= safety 0)
.
Precise checking means that the check is done as though typep
had been called with the exact type specifier that appeared in the
declaration.
If a variable is declared to be (integer 3 17)
then its value
must always be an integer between 3
and 17
. If multiple
type declarations apply to a single variable, then all the
declarations must be correct; it is as though all the types were
intersected producing a single and
type specifier.
To gain maximum benefit from the compiler's type checking, you should
always declare the types of function arguments and structure slots as
precisely as possible. This often involves the use of or
,
member
, and other list-style type specifiers.
Since SBCL's compiler does much more comprehensive type checking than most Lisp compilers, SBCL may detect type errors in programs that have been debugged using other compilers. These errors are mostly incorrect declarations, although compile-time type errors can find actual bugs if parts of the program have never been tested.
Some incorrect declarations can only be detected by run-time type
checking. It is very important to initially compile a program with
full type checks (high safety
optimization) and then test this
safe version. After the checking version has been tested, then you can
consider weakening or eliminating type checks. This applies
even to previously debugged programs, because the SBCL compiler does
much more type inference than other Common Lisp compilers, so an
incorrect declaration can do more damage.
The most common problem is with variables whose constant initial value doesn't match the type declaration. Incorrect constant initial values will always be flagged by a compile-time type error, and they are simple to fix once located. Consider this code fragment:
(prog (foo) (declare (fixnum foo)) (setq foo ...) ...)
Here foo
is given an initial value of nil
, but is
declared to be a fixnum
. Even if it is never read, the initial
value of a variable must match the declared type. There are two ways
to fix this problem. Change the declaration
(prog (foo) (declare (type (or fixnum null) foo)) (setq foo ...) ...)
or change the initial value
(prog ((foo 0)) (declare (fixnum foo)) (setq foo ...) ...)
It is generally preferable to change to a legal initial value rather than to weaken the declaration, but sometimes it is simpler to weaken the declaration than to try to make an initial value of the appropriate type.
Another declaration problem occasionally encountered is incorrect
declarations on defmacro
arguments. This can happen when a
function is converted into a macro. Consider this macro:
(defmacro my-1+ (x) (declare (fixnum x)) `(the fixnum (1+ ,x)))
Although legal and well-defined Common Lisp code, this meaning of this definition is almost certainly not what the writer intended. For example, this call is illegal:
(my-1+ (+ 4 5))
This call is illegal because the argument to the macro is (+ 4
5)
, which is a list
, not a fixnum
. Because of macro
semantics, it is hardly ever useful to declare the types of macro
arguments. If you really want to assert something about the type of
the result of evaluating a macro argument, then put a the
in
the expansion:
(defmacro my-1+ (x) `(the fixnum (1+ (the fixnum ,x))))
In this case, it would be stylistically preferable to change this macro back to a function and declare it inline.
Some more subtle problems are caused by incorrect declarations that can't be detected at compile time. Consider this code:
(do ((pos 0 (position #\a string :start (1+ pos)))) ((null pos)) (declare (fixnum pos)) ...)
Although pos
is almost always a fixnum
, it is nil
at the end of the loop. If this example is compiled with full type
checks (the default), then running it will signal a type error at the
end of the loop. If compiled without type checks, the program will go
into an infinite loop (or perhaps position
will complain
because (1+ nil)
isn't a sensible start.) Why? Because if you
compile without type checks, the compiler just quietly believes the
type declaration. Since the compiler believes that pos
is
always a fixnum
, it believes that pos
is never
nil
, so (null pos)
is never true, and the loop exit test
is optimized away. Such errors are sometimes flagged by unreachable
code notes, but it is still important to initially compile and test
any system with full type checks, even if the system works fine when
compiled using other compilers.
In this case, the fix is to weaken the type declaration to (or
fixnum null)
2.
Note that there is usually little performance penalty for weakening a
declaration in this way. Any numeric operations in the body can still
assume that the variable is a fixnum
, since nil
is not a
legal numeric argument. Another possible fix would be to say:
(do ((pos 0 (position #\a string :start (1+ pos)))) ((null pos)) (let ((pos pos)) (declare (fixnum pos)) ...))
This would be preferable in some circumstances, since it would allow a
non-standard representation to be used for the local pos
variable in the loop body.
Ideally, the compiler would consider all type declarations to be assertions, so that adding type declarations to a program, no matter how incorrect they might be, would never cause undefined behavior. However, the compiler is known to fall short of this goal in two areas:
For example,
(defun foo (x) (the integer (bar x)))
causes the following compiler diagnostic to be emitted:
; note: type assertion too complex to check: ; (VALUES INTEGER &REST T).
A partial workaround is instead write:
(defun foo (x) (the (values integer &optional) (bar x)))
These are important issues, but are not necessarily easy to fix, so they may, alas, remain in the system for a while.
Compiler policy is controlled by the optimize
declaration,
supporting all ANSI optimization qualities (debug
,
safety
, space
, and speed
).3
For effects of various optimization qualities on type-safety and debuggability see Declarations as Assertions and Debugger Policy Control.
Ordinarily, when the speed
quality is high, the compiler emits
notes to notify the programmer about its inability to apply various
optimizations. For selective muffling of these notes See Controlling Verbosity.
The value of space
mostly influences the compiler's decision
whether to inline operations, which tend to increase the size of
programs. Use the value 0
with caution, since it can cause the
compiler to inline operations so indiscriminately that the net effect
is to slow the program by causing cache misses or even swapping.
Print all global optimization settings, augmented by
spec
.
Assign a minimum value to an optimization quality.
quality
is the name of the optimization quality to restrict, andmin
(defaulting to zero) is the minimum allowed value.Returns the alist describing the current policy restrictions.
If
quality
isnil
or not given, nothing is done.Otherwise, if
min
is zero or not given, any existing restrictions ofquality
are removed. Ifmin
is between one and three inclusive, it becomes the new minimum value for the optimization quality: any future proclamations or declarations of the quality with a value less thenmin
behave as if the value wasmin
instead.This is intended to be used interactively, to facilitate recompiling large bodies of code with eg. a known minimum safety.
See also
:policy
option inwith-compilation-unit
.
experimental
interface:
Subject to change.
Affects compilations that take place within its dynamic extent. It is intended to be eg. wrapped around the compilation of all files in the same system.
Following options are defined:
:override
Boolean-Form- One of the effects of this form is to delay undefined warnings until the end of the form, instead of giving them at the end of each compilation. If
override
isnil
(the default), then the outermostwith-compilation-unit
form grabs the undefined warnings. Specifyingoverride
true causes that form to grab any enclosed warnings, even if it is enclosed by anotherwith-compilation-unit
.:policy
Optimize-Declaration-Form- Provides dynamic scoping for global compiler optimization qualities and restrictions, limiting effects of subsequent
optimize
proclamations and calls tosb-ext:restrict-compiler-policy
to the dynamic scope ofbody
.If
override
is false, specifiedpolicy
is merged with current global policy. Ifoverride
is true, current global policy, including any restrictions, is discarded in favor of the specifiedpolicy
.Supplying
policy
nil
is equivalent to the option not being supplied at all, ie. dynamic scoping of policy does not take place.This option is an SBCL-specific experimental extension: Interface subject to change.
:source-namestring
Namestring-Form- Attaches the value returned by the Namestring-Form to the internal debug-source information as the namestring of the source file. Normally the namestring of the input-file for
compile-file
is used: this option can be used to provide source-file information for functions compiled usingcompile
, or to override the input-file ofcompile-file
.If both an outer and an inner
with-compilation-unit
provide asource-namestring
, the inner one takes precedence. Unaffected by:override
.This is an SBCL-specific extension.
:source-plist
Plist-Form- Attaches the value returned by the Plist-Form to internal debug-source information of functions compiled in within the dynamic extent of
body
.Primarily for use by development environments, in order to eg. associate function definitions with editor-buffers. Can be accessed using
sb-introspect:definition-source-plist
.If an outer
with-compilation-unit
form also provide asource-plist
, it is appended to the end of the providedsource-plist
. Unaffected by:override
.This is an SBCL-specific extension.
Examples:
;; Prevent proclamations from the file leaking, and restrict ;; SAFETY to 3 -- otherwise uses the current global policy. (with-compilation-unit (:policy '(optimize)) (restrict-compiler-policy 'safety 3) (load "foo.lisp")) ;; Using default policy instead of the current global one, ;; except for DEBUG 3. (with-compilation-unit (:policy '(optimize debug) :override t) (load "foo.lisp")) ;; Same as if :POLICY had not been specified at all: SAFETY 3 ;; proclamation leaks out from WITH-COMPILATION-UNIT. (with-compilation-unit (:policy nil) (declaim (optimize safety)) (load "foo.lisp"))
If the compiler can prove at compile time that some portion of the program cannot be executed without a type error, then it will give a warning at compile time.
It is possible that the offending code would never actually be executed at run-time due to some higher level consistency constraint unknown to the compiler, so a type warning doesn't always indicate an incorrect program.
For example, consider this code fragment:
(defun raz (foo) (let ((x (case foo (:this 13) (:that 9) (:the-other 42)))) (declare (fixnum x)) (foo x)))
Compilation produces this warning:
; in: DEFUN RAZ ; (CASE FOO (:THIS 13) (:THAT 9) (:THE-OTHER 42)) ; --> LET COND IF COND IF COND IF ; ==> ; (COND) ; ; caught WARNING: ; This is not a FIXNUM: ; NIL
In this case, the warning means that if foo
isn't any of
:this
, :that
or :the-other
, then x
will be
initialized to nil
, which the fixnum
declaration makes
illegal. The warning will go away if ecase
is used instead of
case
, or if :the-other
is changed to t
.
This sort of spurious type warning happens moderately often in the expansion of complex macros and in inline functions. In such cases, there may be dead code that is impossible to correctly execute. The compiler can't always prove this code is dead (could never be executed), so it compiles the erroneous code (which will always signal an error if it is executed) and gives a warning.
The compiler handles errors that happen during macroexpansion, turning
them into compiler errors. If you want to debug the error (to debug a
macro), you can set *break-on-signals*
to error
. For
example, this definition:
(defun foo (e l) (do ((current l (cdr current)) ((atom current) nil)) (when (eq (car current) e) (return current))))
gives this error:
; in: DEFUN FOO ; (DO ((CURRENT L (CDR CURRENT)) ; ((ATOM CURRENT) NIL)) ; (WHEN (EQ (CAR CURRENT) E) (RETURN CURRENT))) ; ; caught ERROR: ; (in macroexpansion of (DO # #)) ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.) ; DO step variable is not a symbol: (ATOM CURRENT)
SBCL's compiler does not attempt to recover from read errors when reading a source file, but instead just reports the offending character position and gives up on the entire source file.
Since Common Lisp forbids the redefinition of standard functions, the compiler can have special knowledge of these standard functions embedded in it. This special knowledge is used in various ways (open coding, inline expansion, source transformation), but the implications to the user are basically the same:
trace
macro. Special-casing of standard functions can be
inhibited using the notinline
declaration, but even then some
phases of analysis such as type inferencing are applied by the
compiler.
When a function call is open coded, inline code whose effect is
equivalent to the function call is substituted for that function
call. When a function call is closed coded, it is usually left
as is, although it might be turned into a call to a different function
with different arguments. As an example, if nthcdr
were to be
open coded, then
(nthcdr 4 foobar)
might turn into
(cdr (cdr (cdr (cdr foobar))))
or even
(do ((i 0 (1+ i)) (list foobar (cdr foobar))) ((= i 4) list))
If nth
is closed coded, then
(nth x l)
might stay the same, or turn into something like
(car (nthcdr x l))
In general, open coding sacrifices space for speed, but some functions
(such as car
) are so simple that they are always
open-coded. Even when not open-coded, a call to a standard function
may be transformed into a different function call (as in the last
example) or compiled as static call. Static function call uses
a more efficient calling convention that forbids redefinition.
By default SBCL implements eval
by calling the native code
compiler.
SBCL also includes an interpreter for use in special cases where using the compiler is undesirable, for example due to compilation overhead. Unlike in some other Lisp implementations, in SBCL interpreted code is not safer or more debuggable than compiled code.
Toggle between different evaluator implementations. If set to
:compile
, an implementation ofeval
that calls the compiler will be used. If set to:interpret
, an interpreter will be used.
This chapter documents the debugging facilities of SBCL, including
the debugger, single-stepper and trace
, and the effect of
(optimize debug)
declarations.
When you enter the debugger, it looks something like this:
debugger invoked on a TYPE-ERROR in thread 11184: The value 3 is not of type LIST. You can type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [ABORT ] Reduce debugger level (leaving debugger, returning to toplevel). 1: [TOPLEVEL] Restart at toplevel READ/EVAL/PRINT loop. (CAR 1 3) 0]
The first group of lines describe what the error was that put us in
the debugger. In this case car
was called on 3
, causing
a type-error
.
This is followed by the “beginner help line”, which appears only if
sb-ext:*debug-beginner-help-p*
is true (default).
Next comes a listing of the active restart names, along with their descriptions – the ways we can restart execution after this error. In this case, both options return to top-level. Restarts can be selected by entering the corresponding number or name.
The current frame appears right underneath the restarts, immediately followed by the debugger prompt.
The debugger is invoked when:
error
is called, and the condition it signals is not handled.
break
is called, or signal
is called with a condition
that matches the current *break-on-signals*
.
invoke-debugger
function.
When the debugger is invoked by a condition, ANSI mandates that the
value of *debugger-hook*
, if any, be called with two arguments:
the condition that caused the debugger to be invoked and the previous
value of *debugger-hook*
. When this happens,
*debugger-hook*
is bound to NIL to prevent recursive errors.
However, ANSI also mandates that *debugger-hook*
not be invoked
when the debugger is to be entered by the break
function. For
users who wish to provide an alternate debugger interface (and thus
catch break
entries into the debugger), SBCL provides
sb-ext:*invoke-debugger-hook*
, which is invoked during any
entry into the debugger.
This is either
nil
or a designator for a function of two arguments, to be run when the debugger is about to be entered. The function is run with*invoke-debugger-hook*
bound tonil
to minimize recursive errors, and receives as arguments the condition that triggered debugger entry and the previous value of*invoke-debugger-hook*
This mechanism is an
sbcl
extension similar to the standard*debugger-hook*
. In contrast to*debugger-hook*
, it is observed byinvoke-debugger
even when called bybreak
.
The debugger is an interactive read-eval-print loop much like the normal top level, but some symbols are interpreted as debugger commands instead of being evaluated. A debugger command starts with the symbol name of the command, possibly followed by some arguments on the same line. Some commands prompt for additional input. Debugger commands can be abbreviated by any unambiguous prefix: help can be typed as ‘h’, ‘he’, etc.
The package is not significant in debugger commands; any symbol with
the name of a debugger command will work. If you want to show the
value of a variable that happens also to be the name of a debugger
command you can wrap the variable in a progn
to hide it from
the command loop.
The debugger prompt is “frame]
”, where frame is
the number of the current frame. Frames are numbered starting from
zero at the top (most recent call), increasing down to the bottom.
The current frame is the frame that commands refer to.
It is possible to override the normal printing behaviour in the
debugger by using the sb-ext:*debug-print-variable-alist*
.
an association list describing new bindings for special variables to be used within the debugger. Eg.
((*PRINT-LENGTH* . 10) (*PRINT-LEVEL* . 6) (*PRINT-PRETTY* . NIL))The variables in the
car
positions are bound to the values in thecdr
during the execution of some debug commands. When evaluating arbitrary expressions in the debugger, the normal values of the printer control variables are in effect.Initially empty,
*debug-print-variable-alist*
is typically used to provide bindings for printer control variables.
A stack frame is the run-time representation of a call to a function; the frame stores the state that a function needs to remember what it is doing. Frames have:
These commands move to a new stack frame and print the name of the function and the values of its arguments in the style of a Lisp function call:
Move up to the next higher frame. More recent function calls are considered to be higher on the stack.
Move to the highest frame, that is, the frame where the debugger was entered.
Move to the frame with the specified number. Prompts for the number if not supplied. The frame with number 0 is the frame where the debugger was entered.
A frame is printed to look like a function call, but with the actual argument values in the argument positions. So the frame for this call in the source:
(myfun (+ 3 4) 'a)
would look like this:
(MYFUN 7 A)
All keyword and optional arguments are displayed with their actual values; if the corresponding argument was not supplied, the value will be the default. So this call:
(subseq "foo" 1)
would look like this:
(SUBSEQ "foo" 1 3)
And this call:
(string-upcase "test case")
would look like this:
(STRING-UPCASE "test case" :START 0 :END NIL)
The arguments to a function call are displayed by accessing the argument variables. Although those variables are initialized to the actual argument values, they can be set inside the function; in this case the new value will be displayed.
&rest
arguments are handled somewhat differently. The value of
the rest argument variable is displayed as the spread-out arguments to
the call, so:
(format t "~A is a ~A." "This" 'test)
would look like this:
(FORMAT T "~A is a ~A." "This" 'TEST)
Rest arguments cause an exception to the normal display of keyword
arguments in functions that have both &rest
and &key
arguments. In this case, the keyword argument variables are not
displayed at all; the rest arg is displayed instead. So for these
functions, only the keywords actually supplied will be shown, and the
values displayed will be the argument values, not values of the
(possibly modified) variables.
If the variable for an argument is never referenced by the function, it will be deleted. The variable value is then unavailable, so the debugger prints ‘#<unused-arg>’ instead of the value. Similarly, if for any of a number of reasons the value of the variable is unavailable or not known to be available (see Variable Access), then ‘#<unavailable-arg>’ will be printed instead of the argument value.
Note that inline expansion and open-coding affect what frames are present in the debugger, see Debugger Policy Control.
If a function is defined by defun
it will appear in backtrace
by that name. Functions defined by labels
and flet
will
appear as (FLET
name)
and (LABELS
name)
respectively.
Anonymous lambdas will appear as (LAMDBA
lambda-list)
.
Sometimes the compiler introduces new functions that are used to implement a user function, but are not directly specified in the source. This is mostly done for argument type and count checking.
With recursive functions, an additional external
frame may
appear before the frame representing the first call to the recursive
function. This is a consequence of the way the compiler works: there
is nothing odd with your program. You may also see cleanup
frames during the execution of unwind-protect
cleanup code, and
optional
for variable argument entry points.
The compiler is “properly tail recursive.” If a function call is in a tail-recursive position, the stack frame will be deallocated at the time of the call, rather than after the call returns. Consider this backtrace:
(BAR ...) (FOO ...)
Because of tail recursion, it is not necessarily the case that
FOO
directly called BAR
. It may be that FOO
called some other function FOO2
which then called BAR
tail-recursively, as in this example:
(defun foo () ... (foo2 ...) ...) (defun foo2 (...) ... (bar ...)) (defun bar (...) ...)
Usually the elimination of tail-recursive frames makes debugging more pleasant, since these frames are mostly uninformative. If there is any doubt about how one function called another, it can usually be eliminated by finding the source location in the calling frame. See Source Location Printing.
The elimination of tail-recursive frames can be prevented by disabling
tail-recursion optimization, which happens when the debug
optimization quality is greater than 2
.
See Debugger Policy Control.
The debugger operates using special debugging information attached to the compiled code. This debug information tells the debugger what it needs to know about the locations in the code where the debugger can be invoked. If the debugger somehow encounters a location not described in the debug information, then it is said to be unknown. If the code location for a frame is unknown, then some variables may be inaccessible, and the source location cannot be precisely displayed.
There are three reasons why a code location could be unknown:
debug
optimization quality. See Debugger Policy Control.
safety
optimization
quality.
In the last two cases, the values of argument variables are accessible, but may be incorrect. For more details on when variable values are accessible, Variable Value Availability.
It is possible for an interrupt to happen when a function call or return is in progress. The debugger may then flame out with some obscure error or insist that the bottom of the stack has been reached, when the real problem is that the current stack frame can't be located. If this happens, return from the interrupt and try again.
There are two ways to access the current frame's local variables in
the debugger: list-locals and sb-debug:var
.
The debugger doesn't really understand lexical scoping; it has just one namespace for all the variables in the current stack frame. If a symbol is the name of multiple variables in the same function, then the reference appears ambiguous, even though lexical scoping specifies which value is visible at any given source location. If the scopes of the two variables are not nested, then the debugger can resolve the ambiguity by observing that only one variable is accessible.
When there are ambiguous variables, the evaluator assigns each one a
small integer identifier. The sb-debug:var
function uses this
identifier to distinguish between ambiguous variables. The
list-locals command prints the identifier. In the
following example, there are two variables named X
. The first
one has identifier 0 (which is not printed), the second one has
identifier 1.
X = 1 X#1 = 2
This command prints the name and value of all variables in the current frame whose name has the specified prefix. prefix may be a string or a symbol. If no prefix is given, then all available variables are printed. If a variable has a potentially ambiguous name, then the name is printed with a “
#
identifier” suffix, where identifier is the small integer used to make the name unique.
This function returns the value of the variable in the current frame with the specified name. If supplied, identifier determines which value to return when there are ambiguous variables.
When name is a symbol, it is interpreted as the symbol name of the variable, i.e. the package is significant. If name is an uninterned symbol (gensym), then return the value of the uninterned variable with the same name. If name is a string,
sb-debug:var
interprets it as the prefix of a variable name that must unambiguously complete to the name of a valid variable.identifier is used to disambiguate the variable name; use list-locals to find out the identifiers.
The value of a variable may be unavailable to the debugger in portions of the program where Lisp says that the variable is defined. If a variable value is not available, the debugger will not let you read or write that variable. With one exception, the debugger will never display an incorrect value for a variable. Rather than displaying incorrect values, the debugger tells you the value is unavailable.
The one exception is this: if you interrupt (e.g., with <C-c>) or if there is an unexpected hardware error such as “‘bus error’” (which should only happen in unsafe code), then the values displayed for arguments to the interrupted frame might be incorrect.4 This exception applies only to the interrupted frame: any frame farther down the stack will be fine.
The value of a variable may be unavailable for these reasons:
debug
optimization quality may have omitted debug
information needed to determine whether the variable is available.
Unless a variable is an argument, its value will only be available when
debug
is at least 2
.
debug
optimization quality is 3
.
debug
optimization quality is 3
.
compilation-speed
optimization quality, but most
source-level optimizations are done under all compilation policies.
(LET ((var1 var2)) ...)
In this case, var1
is substituted with var2
.
Since it is especially useful to be able to get the arguments to a
function, argument variables are treated specially when the
speed
optimization quality is less than 3
and the
debug
quality is at least 1
. With this compilation
policy, the values of argument variables are almost always available
everywhere in the function, even at unknown locations. For
non-argument variables, debug
must be at least 2
for
values to be available, and even then, values are only available at
known locations.
When the debugger command loop establishes variable bindings for available variables, these variable bindings have lexical scope and dynamic extent.5 You can close over them, but such closures can't be used as upward function arguments.
You can also set local variables using setq
, but if the
variable was closed over in the original source and never set, then
setting the variable in the debugger may not change the value in all
the functions the variable is defined in. Another risk of setting
variables is that you may assign a value of a type that the compiler
proved the variable could never take on. This may result in bad
things happening.
One of the debugger's capabilities is source level debugging of compiled code. These commands display the source location for the current frame:
This command displays the file that the current frame's function was defined from (if it was defined from a file), and then the source form responsible for generating the code that the current frame was executing. If context is specified, then it is an integer specifying the number of enclosing levels of list structure to print.
The source form for a location in the code is the innermost list present
in the original source that encloses the form responsible for generating
that code. If the actual source form is not a list, then some enclosing
list will be printed. For example, if the source form was a reference
to the variable *some-random-special*
, then the innermost
enclosing evaluated form will be printed. Here are some possible
enclosing forms:
(let ((a *some-random-special*)) ...) (+ *some-random-special* ...)
If the code at a location was generated from the expansion of a macro or a source-level compiler optimization, then the form in the original source that expanded into that code will be printed. Suppose the file /usr/me/mystuff.lisp looked like this:
(defmacro mymac () '(myfun)) (defun foo () (mymac) ...)
If foo
has called myfun
, and is waiting for it to
return, then the source command would print:
; File: /usr/me/mystuff.lisp (MYMAC)
Note that the macro use was printed, not the actual function call form,
(myfun)
.
If enclosing source is printed by giving an argument to
source or vsource, then the actual source form is
marked by wrapping it in a list whose first element is
‘#:***HERE***’. In the previous example, source 1
would
print:
; File: /usr/me/mystuff.lisp (DEFUN FOO () (#:***HERE*** (MYMAC)) ...)
If the code was defined from Lisp by compile
or
eval
, then the source can always be reliably located. If the
code was defined from a fasl file created by
compile-file
, then the debugger gets the source forms it
prints by reading them from the original source file. This is a
potential problem, since the source file might have moved or changed
since the time it was compiled.
The source file is opened using the truename
of the source file
pathname originally given to the compiler. This is an absolute pathname
with all logical names and symbolic links expanded. If the file can't
be located using this name, then the debugger gives up and signals an
error.
If the source file can be found, but has been modified since the time it was compiled, the debugger prints this warning:
; File has been modified since compilation: ; filename ; Using form offset instead of character position.
where filename is the name of the source file. It then proceeds using a robust but not foolproof heuristic for locating the source. This heuristic works if:
If the heuristic doesn't work, the displayed source will be wrong, but will probably be near the actual source. If the “shape” of the top-level form in the source file is too different from the original form, then an error will be signaled. When the heuristic is used, the source location commands are noticeably slowed.
Source location printing can also be confused if (after the source was
compiled) a read-macro you used in the code was redefined to expand
into something different, or if a read-macro ever returns the same
eq
list twice. If you don't define read macros and don't use
##
in perverted ways, you don't need to worry about this.
Source location information is only available when the debug
optimization quality is at least 2
. If source location
information is unavailable, the source commands will give an error
message.
If source location information is available, but the source location is unknown because of an interrupt or unexpected hardware error (see Unknown Locations and Interrupts), then the command will print:
Unknown location: using block start.
and then proceed to print the source location for the start of the basic block enclosing the code location. It's a bit complicated to explain exactly what a basic block is, but here are some properties of the block start location:
if
,
cond
, or
) will intervene between the block start and the
true location (but note that some conditionals present in the original
source could be optimized away.) Function calls do not end
basic blocks.
block
special form are totally unrelated to the compiler's
basic block.
In other words, the true location lies between the printed location and the next conditional (but watch out because the compiler may have changed the program on you.)
The compilation policy specified by optimize
declarations
affects the behavior seen in the debugger. The debug
quality
directly affects the debugger by controlling the amount of debugger
information dumped. Other optimization qualities have indirect but
observable effects due to changes in the way compilation is done.
Unlike the other optimization qualities (which are compared in relative value
to evaluate tradeoffs), the debug
optimization quality is directly
translated to a level of debug information. This absolute interpretation
allows the user to count on a particular amount of debug information being
available even when the values of the other qualities are changed during
compilation. These are the levels of debug information that correspond to the
values of the debug
quality:
0
> 0
0
gives level 0
plus all argument
variables. Values will only be accessible if the argument variable is
never set and speed
is not 3
. SBCL allows any real
value for optimization qualities. It may be useful to specify
0.5
to get backtrace argument display without argument
documentation.
1
1
provides argument documentation (printed argument lists) and
derived argument/result type information. This makes describe
more informative, and allows the compiler to do compile-time argument
count and type checking for any calls compiled at run-time. This is
the default.
2
1
plus all interned local variables, source location
information, and lifetime information that tells the debugger when
arguments are available (even when speed
is 3
or the
argument is set).
> 2
2
gives level 2
and in addition
disables tail-call optimization, so that the backtrace will contain
frames for all invoked functions, even those in tail positions.
3
2
plus all uninterned variables. In addition, lifetime
analysis is disabled (even when speed
is 3
), ensuring
that all variable values are available at any known location within
the scope of the binding. This has a speed penalty in addition to the
obvious space penalty.
> (max speed space)
debug
is greater than both speed
and space
,
the command return can be used to continue execution by
returning a value from the current stack frame.
> (max speed space compilation-speed)
debug
is greater than all of speed
, space
and
compilation-speed
the code will be steppable (see Single Stepping).
As you can see, if the speed
quality is 3
, debugger performance is
degraded. This effect comes from the elimination of argument variable
special-casing (see Variable Value Availability). Some degree of
speed/debuggability tradeoff is unavoidable, but the effect is not too drastic
when debug
is at least 2
.
In addition to inline
and notinline
declarations, the
relative values of the speed
and space
qualities also
change whether functions are inline expanded.
If a function is inline expanded, then
there will be no frame to represent the call, and the arguments will
be treated like any other local variable. Functions may also be
“semi-inline”, in which case there is a frame to represent the call,
but the call is to an optimized local version of the function, not to
the original function.
These commands get you out of the debugger.
Invokes the nth restart case as displayed by the
error
command. If n is not specified, the available restart cases are reported.
Calls
continue
on the condition given todebug
. If there is no restart case named continue, then an error is signaled.
Calls
abort
on the condition given todebug
. This is useful for popping debug command loop levels or aborting to top level, as the case may be.
Returns value from the current stack frame. This command is available when the
debug
optimization quality is greater than bothspeed
andspace
. Care must be taken that the value is of the same type as SBCL expects the stack frame to return.
Restarts execution of the current stack frame. This command is available when the
debug
optimization quality is greater than bothspeed
andspace
and when the frame is for is a global function. If the function is redefined in the debugger before the frame is restarted, the new function will be used.
Most of these commands print information about the current frame or function, but a few show general information.
Calls
describe
on the current function and displays the number of local variables.
Displays the current function call as it would be displayed by moving to this frame.
Prints the condition given to
invoke-debugger
and the active proceed cases.
Displays all the frames from the current to the bottom. Only shows n frames if specified. The printing is controlled by
*debug-print-variable-alist*
.
The tracer causes selected functions to print their arguments and their results whenever they are called. Options allow conditional printing of the trace information and conditional breakpoints on function entry or exit.
trace
{Option Global-Value}* {Name {Option Value}*}*
trace
is a debugging tool that provides information when specified functions are called. In its simplest form:(TRACE NAME-1 NAME-2 ...)The NAMEs are not evaluated. Each may be a symbol, denoting an individual function, or a string, denoting all functions fbound to symbols whose home package is the package with the given name.
Options allow modification of the default behavior. Each option is a pair of an option keyword and a value form. Global options are specified before the first name, and affect all functions traced by a given use of
trace
. Options may also be interspersed with function names, in which case they act as local options, only affecting tracing of the immediately preceding function name. Local options override global options.By default,
trace
causes a printout on*trace-output*
each time that one of the named functions is entered or returns. (This is the basic,ansi
Common Lisp behavior oftrace
.) As ansbcl
extension, the:report
sb-ext:profile
option can be used to instead cause information to be silently recorded to be inspected later using thesb-ext:profile
function.The following options are defined:
:report
Report-Type- If Report-Type is
trace
(the default) then information is reported by printing immediately. If Report-Type issb-ext:profile
, information is recorded for later summary by calls tosb-ext:profile
. If Report-Type isnil
, then the only effect of the trace is to execute other options (e.g.:condition
Form:condition-after
Form:condition-all
Form- If
:condition
is specified, thentrace
does nothing unless Form evaluates to true at the time of the call.:condition-after
is similar, but suppresses the initial printout, and is tested when the function returns.:condition-all
tries both before and after. This option is not supported with:report
profile
.:break
Form:break-after
Form:break-all
Form- If specified, and Form evaluates to true, then the debugger is invoked at the start of the function, at the end of the function, or both, according to the respective option.
:print-after
Form:print-all
Form- In addition to the usual printout, the result of evaluating Form is printed at the start of the function, at the end of the function, or both, according to the respective option. Multiple print options cause multiple values to be printed.
:wherein
Names- If specified, Names is a function name or list of names.
trace
does nothing unless a call to one of those functions encloses the call to this function (i.e. it would appear in a backtrace.) Anonymous functions have string names like "DEFUN FOO". This option is not supported with:report
profile
.:encapsulate
{:DEFAULT |t
| NIL}- If
t
, the tracing is done via encapsulation (redefining the function name) rather than by modifying the function.:default
is the default, and means to use encapsulation for interpreted functions and funcallable instances, breakpoints otherwise. When encapsulation is used, forms are *not* evaluated in the function's lexical environment, butsb-debug:arg
can still be used.:methods
{T | NIL}- If
t
, any function argument naming a generic function will have its methods traced in addition to the generic function itself.:function
Function-Form- This is a not really an option, but rather another way of specifying what function to trace. The Function-Form is evaluated immediately, and the resulting function is instrumented, i.e. traced or profiled as specified in
report
.
:condition
,:break
andsb-debug:var
andsb-debug:arg
can be used. The-after
and-all
forms can usesb-debug:arg
.
Remove tracing from the specified functions. Untraces all functions when called with no arguments.
the increase in trace indentation at each call level
If the trace indentation exceeds this value, then indentation restarts at 0.
the default value for the
:encapsulate
option totrace
SBCL includes an instrumentation based single-stepper for compiled
code, that can be invoked via the step
macro, or from within
the debugger. See Debugger Policy Control, for details on enabling
stepping for compiled code.
The following debugger commands are used for controlling single stepping.
Selects the
continue
restart if one exists and starts single stepping. None of the other single stepping commands can be used before stepping has been started either by usingstart
or by using the standardstep
macro.
Steps into the current form. Stepping will be resumed when the next form that has been compiled with stepper instrumentation is evaluated.
Steps over the current form. Stepping will be disabled until evaluation of the form is complete.
Steps out of the current frame. Stepping will be disabled until the topmost stack frame that had been stepped into returns.
The form is evaluated with single stepping enabled. Function calls outside the lexical scope of the form can be stepped into only if the functions in question have been compiled with sufficient
debug
policy to be at least partially steppable.
In certain contexts (e.g., non-interactive applications), it may be desirable to turn off the SBCL debugger (and possibly re-enable it). The functions here control the debugger.
When invoked, this function will turn off both the
sbcl
debugger andldb
(the low-level debugger). See alsoenable-debugger
.
Restore the debugger if it has been turned off by
disable-debugger
.
Structure slot accessors are efficient only if the compiler is able to
open code them: compiling a call to a structure slot accessor before
the structure is defined, declaring one notinline
, or passing
it as a functional argument to another function causes severe
performance degradation.
The most efficient way to access a slot of a standard-object
is
by using slot-value
with a constant slot name argument inside a
defmethod
body, where the variable holding the instance is a
specializer parameter of the method and is never assigned to. The cost
is roughly 1.6 times that of an open coded structure slot accessor.
Second most efficient way is to use a CLOS slot accessor, or
slot-value
with a constant slot name argument, but in
circumstances other than specified above. This may be up to 3 times as
slow as the method described above.
Example:
(defclass foo () ((bar))) ;; Fast: specializer and never assigned to (defmethod quux ((foo foo) new) (let ((old (slot-value foo 'bar))) (setf (slot-value foo 'bar) new) old)) ;; Slow: not a specializer (defmethod quux ((foo foo) new) (let* ((temp foo) (old (slot-value temp 'bar))) (setf (slot-value temp 'bar) new) old)) ;; Slow: assignment to FOO (defmethod quux ((foo foo) new) (let ((old (slot-value foo 'bar))) (setf (slot-value foo 'bar) new) (setf foo new) old))
Note that when profiling code such as this, the first few calls to the generic function are not representative, as the dispatch mechanism is lazily set up during those calls.
SBCL has fairly extensive support for performing allocation on the
stack when a variable is declared dynamic-extent
. The
dynamic-extent
declarations are not verified, but are simply
trusted as long as sb-ext:*stack-allocate-dynamic-extent*
is
true.
If true (the default), the compiler respects
dynamic-extent
declarations and stack allocates otherwise inaccessible parts of the object whenever possible. Potentially long (over one page in size) vectors are, however, not stack allocated except in zerosafety
code, as such a vector could overflow the stack without triggering overflow protection.
If dynamic extent constraints specified in the Common Lisp standard are violated, the best that can happen is for the program to have garbage in variables and return values; more commonly, the system will crash.
In particular, it is important to realize that dynamic extend is contagious:
(let* ((a (list 1 2 3)) (b (cons a a))) (declare (dynamic-extent b)) ;; Unless A is accessed elsewhere as well, SBCL will consider ;; it to be otherwise inaccessible -- it can only be accessed ;; through B, after all -- and stack allocate it as well. ;; ;; Hence returning (CAR B) here is unsafe. ...)
This allows stack allocation of complex structures. As a notable
exception to this, SBCL does not as of 1.0.48.21 propagate
dynamic-extentness through &rest
arguments – but another
conforming implementation might, so portable code should not rely on
this.
(declaim (inline foo)) (defun foo (fun &rest arguments) (declare (dynamic-extent arguments)) (apply fun arguments)) (defun bar (a) ;; SBCL will heap allocate the result of (LIST A), and stack allocate ;; only the spine of the &rest list -- so this is safe, but unportable. ;; ;; Another implementation, including earlier versions of SBCL might consider ;; (LIST A) to be otherwise inaccessible and stack-allocate it as well! (foo #'car (list a)))
There are many cases when dynamic-extent
declarations could be
useful. At present, SBCL implements stack allocation for
&rest
lists, when these are declared dynamic-extent
.
cons
, list
, list*
, and vector
when the
result is bound to a variable declared dynamic-extent
.
make-array
, whose result is bound to a variable
declared dynamic-extent
: stack allocation is possible only if
the resulting array is known to be both simple and one-dimensional,
and has a constant :element-type
.
Note: stack space is limited, so allocation of a large vector
may cause stack overflow. For this reason potentially large vectors,
which might circumvent stack overflow detection, are stack allocated
only in zero safety
policies.
flet
or labels
, with a bound
dynamic-extent
declaration. Blocks and tags are also allocated
on the heap, unless all non-local control transfers to them are
compiled with zero safety
.
defstruct
has been declared inline
and the result of the
call to the constructor is bound to a variable declared
dynamic-extent
.
Note: structures with “raw” slots can currently be stack-allocated only on x86 and x86-64.
Examples:
;;; Declaiming a structure constructor inline before definition makes ;;; stack allocation possible. (declaim (inline make-thing)) (defstruct thing obj next) ;;; Stack allocation of various objects bound to DYNAMIC-EXTENT ;;; variables. (let* ((list (list 1 2 3)) (nested (cons (list 1 2) (list* 3 4 (list 5)))) (vector (make-array 3 :element-type 'single-float)) (thing (make-thing :obj list :next (make-thing :obj (make-array 3))))) (declare (dynamic-extent list nested vector thing)) ...) ;;; Stack allocation of arguments to a local function is equivalent ;;; to stack allocation of local variable values. (flet ((f (x) (declare (dynamic-extent x)) ...)) ... (f (list 1 2 3)) (f (cons (cons 1 2) (cons 3 4))) ...) ;;; Stack allocation of &REST lists (defun foo (&rest args) (declare (dynamic-extent args)) ...)
Future plans include
dynamic-extent
.
Some numeric functions have a property: N lower bits of the
result depend only on N lower bits of (all or some)
arguments. If the compiler sees an expression of form (logand
exp mask)
, where exp is a tree of such “good”
functions and mask is known to be of type (unsigned-byte
w)
, where w is a “good” width, all intermediate results
will be cut to w bits (but it is not done for variables and
constants!). This often results in an ability to use simple machine
instructions for the functions.
Consider an example.
(defun i (x y) (declare (type (unsigned-byte 32) x y)) (ldb (byte 32 0) (logxor x (lognot y))))
The result of (lognot y)
will be negative and of type
(signed-byte 33)
, so a naive implementation on a 32-bit
platform is unable to use 32-bit arithmetic here. But modular
arithmetic optimizer is able to do it: because the result is cut down
to 32 bits, the compiler will replace logxor
and lognot
with versions cutting results to 32 bits, and because terminals
(here—expressions x
and y
) are also of type
(unsigned-byte 32)
, 32-bit machine arithmetic can be used.
As of SBCL 0.8.5 “good” functions are +
, -
;
logand
, logior
, logxor
, lognot
and their
combinations; and ash
with the positive second
argument. “Good” widths are 32 on HPPA, MIPS, PPC, Sparc and x86 and
64 on Alpha. While it is possible to support smaller widths as well,
currently this is not implemented.
Defines
name
as a global variable that is always bound.value
is evaluated and assigned toname
both at compile- and load-time, but only ifname
is not already bound.Global variables share their values between all threads, and cannot be locally bound, declared special, defined as constants, and neither bound nor defined as symbol macros.
See also the declarations
sb-ext:global
andsb-ext:always-bound
.
Syntax:
(sb-ext:global symbol*)
Only valid as a global proclamation.
Specifies that the named symbols cannot be proclaimed or locally declared
special
. Proclaiming an already special or constant variable name asglobal
signal an error. Allows more efficient value lookup in threaded environments in addition to expressing programmer intention.
Syntax:
(sb-ext:always-bound symbol*)
Only valid as a global proclamation.
Specifies that the named symbols are always bound. Inhibits
makunbound
of the named symbols. Proclaiming an unbound symbol asalways-bound
signals an error. Allows the compiler to elide boundness checks from value lookups.
FIXME: The material in the CMUCL manual about getting good performance from the compiler should be reviewed, reformatted in Texinfo, lightly edited for SBCL, and substituted into this manual. In the meantime, the original CMUCL manual is still 95+% correct for the SBCL version of the Python compiler. See the sections
Besides this information from the CMUCL manual, there are a few other points to keep in mind.
let
, let*
, inline function call, and so
forth. However, it's much more passive and dumb about inferring the
types of values assigned with setq
, setf
, and
friends. It would be nice to fix this, but in the meantime don't
expect that just because it's very smart about types in most respects
it will be smart about types involved in assignments. (This doesn't
affect its ability to benefit from explicit type declarations
involving the assigned variables, only its ability to get by without
explicit type declarations.)
Finally, note that Common Lisp defines many constructs which, in the infamous phrase, “could be compiled efficiently by a sufficiently smart compiler”. The phrase is infamous because making a compiler which actually is sufficiently smart to find all these optimizations systematically is well beyond the state of the art of current compiler technology. Instead, they're optimized on a case-by-case basis by hand-written code, or not optimized at all if the appropriate case hasn't been hand-coded. Some cases where no such hand-coding has been done as of SBCL version 0.6.3 include
(reduce #'f x)
where the type of x
is known at compile
time
(position 0
some-bit-vector)
(remove item list :count 1)
(locally (declare (safety 1)) (assoc item
list))
(which currently performs safe endp
checking internal
to assoc).
If your system's performance is suffering because of some construct
which could in principle be compiled efficiently, but which the SBCL
compiler can't in practice compile efficiently, consider writing a
patch to the compiler and submitting it for inclusion in the main
sources. Such code is often reasonably straightforward to write;
search the sources for the string “deftransform
” to find many
examples (some straightforward, some less so).
SBCL is derived from CMUCL, which implements many extensions to the ANSI standard. SBCL doesn't support as many extensions as CMUCL, but it still has quite a few. See Contributed Modules.
SBCL supports extended package prefix syntax, which allows specifying
an alternate package instead of *package*
for the reader to use
as the default package for interning symbols:
package-name::form-with-interning-into-package
Example:
'foo::(bar quux zot) == '(foo::bar foo::quux foo::zot)
Doesn't alter *package*
: if foo::bar
would cause a
read-time package lock violation, so does foo::(bar)
.
SBCL also extends the reader to normalize all symbols to Normalization Form KC in builds with Unicode enabled. Whether symbols are normalized is controlled by
Returns
t
ifreadtable
normalizes strings tonfkc
, andnil
otherwise. Thereadtable-normalization
of the standard readtable ist
.
Symbols created by
intern
and similar functions are not affected by this setting. If
sb-ext:readtable-normalization
is t
, symbols that are not
normalized are escaped during printing.
SBCL allows giving packages local nicknames: they allow short and easy-to-use names to be used without fear of name conflict associated with normal nicknames.
A local nickname is valid only when inside the package for which it has been specified. Different packages can use same local nickname for different global names, or different local nickname for same global name.
Symbol :package-local-nicknames
in *features*
denotes the
support for this feature.
Options are extended to include
:local-nicknames (
local-nickname actual-package-name)*
The package has the specified local nicknames for the corresponding actual packages.
Example:
(defpackage :bar (:intern "X")) (defpackage :foo (:intern "X")) (defpackage :quux (:use :cl) (:local-nicknames (:bar :foo) (:foo :bar))) (find-symbol "X" :foo) ; => FOO::X (find-symbol "X" :bar) ; => BAR::X (let ((*package* (find-package :quux))) (find-symbol "X" :foo)) ; => BAR::X (let ((*package* (find-package :quux))) (find-symbol "X" :bar)) ; => FOO::X
Returns an alist of (local-nickname . actual-package) describing the nicknames local to the designated package.
When in the designated package, calls to
find-package
with the any of the local-nicknames will return the corresponding actual-package instead. This also affects all implied calls tofind-package
, including those performed by the reader.When printing a package prefix for a symbol with a package local nickname, the local nickname is used instead of the real name in order to preserve print-read consistency.
See also:
add-package-local-nickname
,package-locally-nicknamed-by-list
,remove-package-local-nickname
, and thedefpackage
option:local-nicknames
.Experimental: interface subject to change.
Returns a list of packages which have a local nickname for the designated package.
See also:
add-package-local-nickname
,package-local-nicknames
,remove-package-local-nickname
, and thedefpackage
option:local-nicknames
.Experimental: interface subject to change.
Adds
local-nickname
foractual-package
in the designated package, defaulting to current package.local-nickname
must be a string designator, andactual-package
must be a package designator.Returns the designated package.
Signals a continuable error if
local-nickname
is already a package local nickname for a different package, or iflocal-nickname
is one of "CL", "COMMON-LISP", or, "KEYWORD", or iflocal-nickname
is a global name or nickname for the package to which the nickname would be added.When in the designated package, calls to
find-package
with thelocal-nickname
will return the package the designatedactual-package
instead. This also affects all implied calls tofind-package
, including those performed by the reader.When printing a package prefix for a symbol with a package local nickname, local nickname is used instead of the real name in order to preserve print-read consistency.
See also:
package-local-nicknames
,package-locally-nicknamed-by-list
,remove-package-local-nickname
, and thedefpackage
option:local-nicknames
.Experimental: interface subject to change.
If the designated package had
old-nickname
as a local nickname for another package, it is removed. Returns true if the nickname existed and was removed, andnil
otherwise.See also:
add-package-local-nickname
,package-local-nicknames
,package-locally-nicknamed-by-list
, and thedefpackage
option:local-nicknames
.Experimental: interface subject to change.
Common Lisp standard specifies that “If the new definition is at variance with the current state of that package, the consequences are undefined;” SBCL by default signals a full warning and retains as much of the package state as possible.
This can be adjusted using sb-ext:*on-package-variance*
:
Specifies behavior when redefining a package using
defpackage
and the definition is in variance with the current state of the package.The value should be of the form:
(:WARN [T | packages-names] :ERROR [T | package-names])specifying which packages get which behaviour
--
witht
signifying the default unless otherwise specified. If default is not specified,:warn
is used.
:warn
keeps as much state as possible and causessbcl
to signal a full warning.
:error
causessbcl
to signal an error when the variantdefpackage
form is executed, with restarts provided for user to specify what action should be taken.Example:
(setf *on-package-variance* '(:warn (:swank :swank-backend) :error t))specifies to signal a warning if
swank
package is in variance, and an error otherwise.
SBCL provides additional garbage collection functionality not specified by ANSI.
Called after each garbage collection, except for garbage collections triggered during thread exits. In a multithreaded environment these hooks may run in any thread.
Initiate a garbage collection.
The default is to initiate a nursery collection, which may in turn trigger a collection of one or more older generations as well. If
full
is true, all generations are collected. Ifgen
is provided, it can be used to specify the oldest generation guaranteed to be collected.On CheneyGC platforms arguments
full
andgen
take no effect: a full collection is always performed.
Finalization allows code to be executed after an object has been garbage collected. This is useful for example for releasing foreign memory associated with a Lisp object.
Arrange for the designated
function
to be called when there are no more references toobject
, including references infunction
itself.If
dont-save
is true, the finalizer will be cancelled whensave-lisp-and-die
is called: this is useful for finalizers deallocating system memory, which might otherwise be called with addresses from the old image.In a multithreaded environment
function
may be called in any thread. In both single and multithreaded environmentsfunction
may be called in any dynamic scope: consequences are unspecified iffunction
is not fully re-entrant.Errors from
function
are handled and cause awarning
to be signalled in whichever thread thefunction
was called in.Examples:
;;; GOOD, assuming RELEASE-HANDLE is re-entrant. (let* ((handle (get-handle)) (object (make-object handle))) (finalize object (lambda () (release-handle handle))) object) ;;; BAD, finalizer refers to object being finalized, causing ;;; it to be retained indefinitely! (let* ((handle (get-handle)) (object (make-object handle))) (finalize object (lambda () (release-handle (object-handle object))))) ;;; BAD, not re-entrant! (defvar *rec* nil) (defun oops () (when *rec* (error "recursive OOPS")) (let ((*rec* t)) (gc))) ; or just cons enough to cause one (progn (finalize "oops" #'oops) (oops)) ; GC causes re-entry to #'oops due to the finalizer ; -> ERROR, caught, WARNING signalled
Weak pointers allow references to objects to be maintained without keeping them from being garbage collected: useful for building caches among other things.
Hash tables can also have weak keys and values: see Hash Table Extensions.
Allocate and return a weak pointer which points to
object
.
If
weak-pointer
is valid, return the value ofweak-pointer
andt
. If the referent ofweak-pointer
has been garbage collected, returns the valuesnil
andnil
.
Total
cpu
time spent doing garbage collection (as reported byget-internal-run-time
.) Initialized to zero on startup. It is safe to bind this to zero in order to measuregc
time inside a certain section of code, but doing so may interfere with results reported by eg.time
.
The amount of memory that will be allocated before the next garbage collection is initiated. This can be set with
setf
.On
gencgc
platforms this is the nursery size, and defaults to 5% of dynamic space size.Note: currently changes to this value are lost when saving core.
Return the number of bytes consed since the program began. Typically this result will be a consed bignum, so if you have an application (e.g. profiling) which can't tolerate the overhead of consing bignums, you'll probably want either to hack in at a lower level (as the code in the
sb-profile
package does), or to design a more microefficient interface and submit it as a patch.
Return the pathname used to log garbage collections. Can be
setf
. Default isnil
, meaning collections are not logged. If non-null, the designated file is opened before and after each collection, and generation statistics are appended to it.
Average age of memory allocated to
generation:
average number of times objects allocated to the generation have seen younger objects promoted to it. Available ongencgc
platforms only.Experimental: interface subject to change.
Number of bytes allocated to
generation
currently. Available ongencgc
platforms only.Experimental: interface subject to change.
Number of bytes that can be allocated to
generation
before that generation is considered for garbage collection. This value is meaningless for generation 0 (the nursery): seebytes-consed-between-gcs
instead. Default is 5% of the dynamic space size divided by the number of non-nursery generations. Can be assigned to usingsetf
. Available ongencgc
platforms only.Experimental: interface subject to change.
Minimum average age of objects allocated to
generation
before that generation is may be garbage collected. Default is 0.75. See alsogeneration-average-age
. Can be assigned to usingsetf
. Available ongencgc
platforms only.Experimental: interface subject to change.
Number of times garbage collection is done on
generation
before automatic promotion to the next generation is triggered. Default is 1. Can be assigned to usingsetf
. Available ongencgc
platforms only.Experimental: interface subject to change.
Number of times garbage collection has been done on
generation
without promotion. Available ongencgc
platforms only.Experimental: interface subject to change.
SBCL supports a metaobject protocol which is intended to be compatible with AMOP; present exceptions to this (as distinct from current bugs) are:
compute-effective-method
only returns one value, not two.
There is no record of what the second return value was meant to indicate, and apparently no clients for it.
funcallable-standard-object
are
(function standard-object)
, not (standard-object function)
.
This is to ensure that the standard-object
class is the last of
the standardized classes before t
appearing in the class
precedence list of generic-function
and
standard-generic-function
, as required by section 1.4.4.5 of the
ANSI specification.
:declare
and :declarations
to
ensure-generic-function
are both accepted, with the leftmost
argument defining the declarations to be stored and returned by
generic-function-declarations
.
Where AMOP specifies :declarations
as the keyword argument to
ensure-generic-function
, the Common Lisp standard specifies
:declare
. Portable code should use :declare
.
validate-superclass
should treat standard-class
and
funcallable-standard-class
as compatible metaclasses, we
impose an additional requirement at class finalization time: a class
of metaclass funcallable-standard-class
must have
function
in its superclasses, and a class of metaclass
standard-class
must not.
After a class has been finalized, it is associated with a class
prototype which is accessible by a standard mop function
class-prototype
. The user can then ask whether this object is a
function
or not in several different ways: whether it is a
function according to typep
; whether its class-of
is
subtypep
function
, or whether function
appears in
the superclasses of the class. The additional consistency requirement
comes from the desire to make all of these answers the same.
The following class definitions are bad, and will lead to errors either immediately or if an instance is created:
(defclass bad-object (funcallable-standard-object) () (:metaclass standard-class))
(defclass bad-funcallable-object (standard-object) () (:metaclass funcallable-standard-class))
The following definition is acceptable:
(defclass mixin () ((slot :initarg slot))) (defclass funcallable-object (funcallable-standard-object mixin) () (:metaclass funcallable-standard-class))
and leads to a class whose instances are funcallable and have one slot.
Note that this requirement also applies to the class
funcallable-standard-object
, which has metaclass
funcallable-standard-class
rather than
standard-class
as AMOP specifies.
common-lisp-user
package or exported by any package defined in
the ANSI Common Lisp standard.” is interpreted to mean that the
standardized classes themselves should not have slots named by external
symbols of public packages.
The rationale behind the restriction is likely to be similar to the ANSI Common Lisp restriction on defining functions, variables and types named by symbols in the Common Lisp package: preventing two independent pieces of software from colliding with each other.
new-value
argument to (setf
slot-value-using-class)
are not allowed: all user-defined methods must
have a specializer of the class t
.
This prohibition is motivated by a separation of layers: the
slot-value-using-class
family of functions is intended for use in
implementing different and new slot allocation strategies, rather than
in performing application-level dispatching. Additionally, with this
requirement, there is a one-to-one mapping between metaclass, class and
slot-definition-class tuples and effective methods of (setf
slot-value-using-class)
, which permits optimization of (setf
slot-value-using-class)
's discriminating function in the same manner as
for slot-value-using-class
and slot-boundp-using-class
.
Note that application code may specialize on the new-value
argument of slot accessors.
name
argument to ensure-class
, if
any, is only redefined if it is the proper name of that class;
otherwise, a new class is created.
This is consistent with the description of ensure-class
in AMOP
as the functional version of defclass
, which has this behaviour;
however, it is not consistent with the weaker requirement in AMOP, which
states that any class found by find-class
, no matter what its
class-name
, is redefined.
:name
initialization
argument for slot-definition
objects being a constant, when the
slot definition is of type structure-slot-definition
(i.e. it is
associated with a class of type structure-class
).
This allows code which uses constant names for structure slots to continue working as specified in ANSI, while enforcing the constraint for all other types of slot.
t
is not an instance of the built-in-class
metaclass.
AMOP specifies, in the “Inheritance Structure of Metaobject Classes”
section, that the class named t
should be an instance of
built-in-class
. However, it also specifies that
validate-superclass
should return true (indicating that a direct
superclass relationship is permissible) if the second argument is the
class named t
. Also, ANSI specifies that classes with metaclass
built-in-class
may not be subclassed using defclass
, and
also that the class named t
is the universal superclass,
inconsistent with it being a built-in-class
.
In addition, SBCL supports extensions to the Metaobject protocol from AMOP; at present, they are:
defmethod
forms is provided by the
make-method-specializers-form
function, which returns a form
which, when evaluated in the lexical environment of the
defmethod
, returns a list of specializer metaobjects. This
operator suffers from similar restrictions to those affecting
make-method-lambda
, namely that the generic function must be
defined when the defmethod
form is expanded, so that the
correct method of make-method-specializers-form
is invoked.
The system-provided method on make-method-specializers-form
generates a call to find-class
for each symbol specializer
name, and a call to intern-eql-specializer
for each (eql
x)
specializer name.
find-method
, is provided by
parse-specializer-using-class
and
unparse-specializer-using-class
, which dispatch on their first
argument, the generic function associated with a method with the given
specializer. The system-provided methods on those methods convert
between classes and proper names and between lists of the form
(eql
x)
and interned eql specializer objects.
standard-instance-access
and
funcallable-standard-instance-access
is possible by comparison
to the constant +slot-unbound+
.
ANSI Common Lisp has a class sequence
with subclasses list
and
vector
on which the “sequence functions” like find
,
subseq
, etc. operate. As an extension to the ANSI specification,
SBCL allows additional subclasses of sequence
to be defined
6.
Users of this extension just make instances of sequence
subclasses
and transparently operate on them using sequence functions:
(coerce (subseq (make-instance 'my-sequence) 5 10) 'list)
From this perspective, no distinction between builtin and user-defined
sequence
subclasses should be necessary.
Providers of the extension, that is of user-defined sequence
subclasses, have to adhere to a “sequence protocol” which consists of
a set of generic functions in the sequence
package.
A minimal sequence
subclass has to specify standard-object
and
sequence
as its superclasses and has to be the specializer of the
sequence
parameter of methods on at least the following generic
functions:
Returns the length of
sequence
or signals aprotocol-unimplemented
error if the sequence protocol is not implemented for the class ofsequence
.
Returns the element at position
index
ofsequence
or signals aprotocol-unimplemented
error if the sequence protocol is not implemented for the class ofsequence
.
Replaces the element at position
index
ofsequence
withnew-value
and returnsnew-value
or signals aprotocol-unimplemented
error if the sequence protocol is not implemented for the class ofsequence
.
Return destructively modified
sequence
or a freshly allocated sequence of the same class assequence
of lengthlength
. Elements of the returned sequence are initialized toinitial-element
, if supplied, initialized toinitial-contents
if supplied, or identical to the elements ofsequence
if neither is supplied. Signals aprotocol-unimplemented
error if the sequence protocol is not implemented for the class ofsequence
.
Returns a freshly allocated sequence of length
length
and of the same class assequence
. Elements of the new sequence are initialized toinitial-element
, if supplied, initialized toinitial-contents
if supplied, or identical to the elements ofsequence
if neither is supplied. Signals aprotocol-unimplemented
error if the sequence protocol is not implemented for the class ofsequence
.
make-sequence-like
is needed for functions returning
freshly-allocated sequences such as subseq
or
copy-seq
. adjust-sequence
is needed for functions which
destructively modify their arguments such as delete
. In fact, all
other sequence functions can be implemented in terms of the above
functions and actually are, if no additional methods are
defined. However, relying on these generic implementations, in
particular not implementing the iterator protocol can incur a high
performance penalty See Iterator Protocol.
When the sequence protocol is only partially implemented for a given
sequence
subclass, an attempt to apply one of the missing
operations to instances of that class signals the following condition:
Class precedence list:
protocol-unimplemented, type-error, error, serious-condition, condition, t
This error is signaled if a sequence operation is applied to an instance of a sequence class that does not support the operation.
In addition to the mandatory functions above, methods on the sequence functions listed below can be defined.
There are two noteworthy irregularities:
sb-sequence:emptyp
does not have a counterpart in
the cl
package. It is intended to be used instead of
length
when working with lazy or infinite sequences.
map
, concatenate
and merge
receive a
type designator specifying the type of the constructed sequence as their
first argument. However, the corresponding generic functions
sb-sequence:map
, sb-sequence:concatenate
and
sb-sequence:merge
receive a prototype instance of the requested
sequence
subclass instead.
Returns
t
ifsequence
is an empty sequence andnil
otherwise. Signals an error ifsequence
is not a sequence.
sb-sequence:count
, sb-sequence:count-if
, sb-sequence:count-if-not
sb-sequence:find
, sb-sequence:find-if
, sb-sequence:find-if-not
sb-sequence:position
, sb-sequence:position-if
, sb-sequence:position-if-not
sb-sequence:subseq
sb-sequence:copy-seq
sb-sequence:fill
Implements
cl:map
for extended sequences.
result-prototype
corresponds to theresult-type
ofcl:map
but receives a prototype instance of an extended sequence class instead of a type specifier. By dispatching onresult-prototype
, methods on this generic function specify how extended sequence classes act when they are specified as the result type in acl:map
call.result-prototype
may not be fully initialized and thus should only be used for dispatch and to determine its class.Another difference to
cl:map
is thatfunction
is a function, not a function designator.
sb-sequence:nsubstitute
, sb-sequence:nsubstitute-if
,
sb-sequence:nsubstitute-if-not
, sb-sequence:substitute
,
sb-sequence:substitute-if
, sb-sequence:substitute-if-not
sb-sequence:replace
sb-sequence:nreverse
, sb-sequence:reverse
Implements
cl:concatenate
for extended sequences.
result-prototype
corresponds to theresult-type
ofcl:concatenate
but receives a prototype instance of an extended sequence class instead of a type specifier. By dispatching onresult-prototype
, methods on this generic function specify how extended sequence classes act when they are specified as the result type in acl:concatenate
call.result-prototype
may not be fully initialized and thus should only be used for dispatch and to determine its class.
sb-sequence:reduce
sb-sequence:mismatch
sb-sequence:search
sb-sequence:delete
, sb-sequence:delete-if
, sb-sequence:delete-if-not
,
sb-sequence:remove
, sb-sequence:remove-if
, sb-sequence:remove-if-not
,
sb-sequence:delete-duplicates
, sb-sequence:remove-duplicates
sb-sequence:sort
, sb-sequence:stable-sort
Implements
cl:merge
for extended sequences.
result-prototype
corresponds to theresult-type
ofcl:merge
but receives a prototype instance of an extended sequence class instead of a type specifier. By dispatching onresult-prototype
, methods on this generic function specify how extended sequence classes act when they are specified as the result type in acl:merge
call.result-prototype
may not be fully initialized and thus should only be used for dispatch and to determine its class.Another difference to
cl:merge
is thatpredicate
is a function, not a function designator.
In the spirit of dolist
, generic sequences can be traversed using
the macro
Executes
body
withelement
subsequently bound to each element ofsequence
, then returnsreturn
.
The iterator protocol allows subsequently accessing some or all elements
of a sequence in forward or reverse direction. Users first call
make-sequence-iterator
to create an iteration state and
receive functions to query and mutate it. These functions allow, among
other things, moving to, retrieving or modifying elements of the
sequence. An iteration state consists of a state object, a limit object,
a from-end indicator and the following six functions to query or mutate
this state:
step function
sequence iterator from-endMoves the iterator one position forward or backward in the associated sequence depending on the iteration direction.
endp function
sequence iterator limit from-endReturns non-
nil
when the iterator has reached the end of the associated sequence with respect to the iteration direction.
element function
sequence iteratorReturns the sequence element associated to the current position of the iteration.
setf element function
new-value sequence iteratorDestructively modifies the associates sequence by replacing the sequence element associated to the current iteration position with a new value.
index function
sequence iteratorReturns the position of the iteration in the associated sequence.
copy function
sequence iteratorReturns a copy of the iteration state which can be mutated independently of the copied iteration state.
An iterator is created by calling:
Returns a sequence iterator for
sequence
or, ifstart
and/orend
are supplied, the subsequence bounded bystart
andend
as nine values:1. iterator state 2. limit 3. from-end 4. step function 5. endp function 6. element function 7. setf element function 8. index function 9. copy state function
If
from-end
isnil
, the constructed iterator visits the specified elements in the order in which they appear insequence
. Otherwise, the elements are visited in the opposite order.
Note that make-sequence-iterator
calls
make-simple-sequence-iterator
when there is no specialized
method for a particular sequence
subclass. See Simple Iterator Protocol.
The following convenience macros simplify traversing sequences using
iterators:
Executes
body
with the elements ofvars
bound to the iteration state returned bymake-sequence-iterator
forsequence
andargs
. Elements ofvars
may benil
in which case the corresponding value returned bymake-sequence-iterator
is ignored.
Executes
body
with the namesstep
,endp
,elt
,setf
,index
andcopy
bound to local functions which execute the iteration state query and mutation functions returned bymake-sequence-iterator
forsequence
andargs
.step
,endp
,elt
,setf
,index
andcopy
have dynamic extent.
For cases in which the full flexibility and performance of the general sequence iterator protocol is not required, there is a simplified sequence iterator protocol consisting of a few generic functions which can be specialized for iterator classes:
Moves
iterator
one position forward or backward insequence
depending on the iteration direction encoded infrom-end
.
Returns non-NIL when
iterator
has reachedlimit
(which may correspond to the end of SEQUENCE) with respect to the iteration direction encoded infrom-end
.
Returns the element of
sequence
associated to the position ofiterator
.
Destructively modifies
sequence
by replacing the sequence element associated to position ofiterator
withnew-value
.
Returns the position of
iterator
insequence
.
Returns a copy of
iterator
which also traversessequence
but can be mutated independently ofiterator
.
Iterator objects implementing the above simple iteration protocol are created by calling the following generic function:
Returns a sequence iterator for
sequence
,start
,end
andfrom-end
as three values:1. iterator state 2. limit 3. from-end
The returned iterator can be used with the generic iterator functions
iterator-step
,iterator-endp
,iterator-element
, (SETF ITERATOR-ELEMENT),iterator-index
anditerator-copy
.
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.
Return the "value" part of the environment string "name=value" which corresponds to
name
, ornil
if there is none.
External programs can be run with sb-ext:run-program
.
7
run-program
creates a new process specified by theprogram
argument.args
are the standard arguments that can be passed to a program. For no arguments, usenil
(which means that just the name of the program is passed as arg 0).The program arguments and the environment are encoded using the default external format for streams.
run-program
will return aprocess
structure. See thecmu
Common Lisp Users Manual for details about theprocess
structure.Notes about Unix environments (as in the
:environment
and:env
args):
- The
sbcl
implementation ofrun-program
, like Perl and many other programs, but unlike the originalcmu
cl
implementation, copies the Unix environment by default.- Running Unix programs from a setuid process, or in any other situation where the Unix environment is under the control of someone else, is a mother lode of security problems. If you are contemplating doing this, read about it first. (The Perl community has a lot of good documentation about this and other security issues in script-like programs.)
- The
&key
arguments have the following meanings::environment
- a list of STRINGs describing the new Unix environment (as in "man environ"). The default is to copy the environment of the current process.
:env
- an alternative lossy representation of the new Unix environment, for compatibility with
cmu
cl
:search
- Look for
program
in each of the directories in the child's $PATH environment variable. Otherwise an absolute pathname is required.:wait
- If non-NIL (default), wait until the created process finishes. If
nil
, continue running Lisp until the program finishes.:pty
- Either
t
,nil
, or a stream. Unlessnil
, the subprocess is established under apty
. If :pty is a stream, all output to this pty is sent to this stream, otherwise theprocess-pty
slot is filled in with a stream connected to pty that can read output and write input.:input
- Either
t
,nil
, a pathname, a stream, or:stream
. Ift
, the standard input for the current process is inherited. Ifnil
, /dev/null is used. If a pathname, the file so specified is used. If a stream, all the input is read from that stream and sent to the subprocess. If:stream
, theprocess-input
slot is filled in with a stream that sends its output to the process. Defaults tonil
.:if-input-does-not-exist
(when:input
is the name of a file)- can be one of:
:error
to generate an error:create
to create an empty filenil
(the default) to returnnil
fromrun-program
:output
- Either
t
,nil
, a pathname, a stream, or:stream
. Ift
, the standard output for the current process is inherited. Ifnil
, /dev/null is used. If a pathname, the file so specified is used. If a stream, all the output from the process is written to this stream. If:stream
, theprocess-output
slot is filled in with a stream that can be read to get the output. Defaults tonil
.:if-output-exists
(when:output
is the name of a file)- can be one of:
:error
(the default) to generate an error:supersede
to supersede the file with output from the program:append
to append output from the program to the filenil
to returnnil
fromrun-program
, without doing anything:error
and:if-error-exists
- Same as
:output
and:if-output-exists
, except that:error
can also be specified as:output
in which case all error output is routed to the same place as normal output.:status-hook
- This is a function the system calls whenever the status of the process changes. The function takes the process as an argument.
:external-format
- The external-format to use for
:input
,:output
, and:error
:STREAMs.:directory
- Specifies the directory in which the program should be run.
nil
(the default) means the directory is unchanged.
When sb-ext:run-program
is called with wait
equal to
NIL, an instance of class sb-ext:process is returned. The
following functions are available for use with processes:
Return the current status of
process
. The result is one of:running
,:stopped
,:exited
, or:signaled
.
Wait for
process
to quit running for some reason. Whencheck-for-stopped
ist
, also returns whenprocess
is stopped. Returnsprocess
.
Close all streams connected to
process
and stop maintaining the status slot.
Hand
signal
toprocess
. Ifwhom
is:pid
, use the kill Unix system call. Ifwhom
is:process-group
, use the killpg Unix system call. Ifwhom
is:pty-process-group
deliver the signal to whichever process group is currently in the foreground.
SBCL provides support for working with Unicode text and querying the
standard Unicode database for information about individual codepoints.
Unicode-related functions are located in the sb-unicode
package.
SBCL also extends ANSI character literal syntax to support Unicode codepoints. You can either specify a character by its Unicode name, with spaces replaced by underscores, if a unique name exists 8 or by giving its hexadecimal codepoint preceded by a “U”, an optional “+”, and an arbitrary number of leading zeros. You may also input the character directly into your source code if it can be encoded in your file. If a character had an assigned name in Unicode 1.0 that was distinct from its current name, you may also use that name (with spaces replaced by underscores) to specify the character, unless the name is already associated with a codepoint in the latest Unicode standard (such as “BELL”).
For example, you can specify the codepoint U+00E1 (“Latin Small Letter A With Acute”) as
#\LATIN_SMALL_LETTER_A_WITH_ACUTE
#\LATIN_SMALL_LETTER_A_ACUTE
#\á
assuming a Unicode source file
#\U00E1
#\UE1
#\U+00E1
The following functions can be used to find information about a Unicode codepoint.
Returns the general category of
character
as it appears in UnicodeData.txt
Returns the canonical combining class (CCC) of
character
Returns the decimal digit value associated with
character
ornil
if there is no such value.The only characters in Unicode with a decimal digit value are those that are part of a range of characters that encode the digits 0-9. Because of this, `(decimal-digit c) <=> (digit-char-p c 10)` in #+sb-unicode builds
Returns the Unicode digit value of
character
ornil
if it doesn't exist.Digit values are guaranteed to be integers between 0 and 9 inclusive. All characters with decimal digit values have the same digit value, but there are characters (such as digits of number systems without a 0 value) that have a digit value but no decimal digit value
Returns the numeric value of
character
ornil
if there is no such value. Numeric value is the most general of the Unicode numeric properties. The only constraint on the numeric value is that it be a rational number.
Returns
t
ifcharacter
needs to be mirrored in bidirectional text. Otherwise, returnsnil
.
Returns the mirror image of
character
if it exists. Otherwise, returnsnil
.
Returns the version of Unicode in which
character
was assigned as a pair of values, both integers, representing the major and minor version respectively. Ifcharacter
is not assigned in Unicode, returnsnil
for both values.
Returns the Hangul syllable type of
character
. The syllable type can be one of:l
,:v
,:t
,:lv
, or:lvt
. If the character is not a Hangul syllable or Jamo, returnsnil
Returns the East Asian Width property of
character
as one of the keywords:n
(Narrow),:a
(Ambiguous),:h
(Halfwidth),:w
(Wide),:f
(Fullwidth), or:na
(Not applicable)
Returns the Script property of
character
as a keyword. Ifcharacter
does not have a known script, returns:unknown
Returns the Unicode block in which
character
resides as a keyword. Ifcharacter
does not have a known block, returns:no-block
Returns the name assigned to
character
in Unicode 1.0 if it is distinct from the name currently assigned tocharacter
. Otherwise, returnsnil
. This property has been officially obsoleted by the Unicode standard, and is only included for backwards compatibility.
Returns
t
ifcharacter
has the specifiedproperty
.property
is a keyword representing one of the properties from PropList.txt, with underscores replaced by dashes.
Returns
t
ifcharacter
has the Unicode property Uppercase andnil
otherwise
Returns
t
ifcharacter
has the Unicode property Lowercase andnil
otherwise
Returns
t
ifcharacter
has a (Unicode) case, andnil
otherwise
Returns
t
ifcharacter
is Case Ignorable as defined in Unicode 6.3, Chapter 3
Returns
t
ifcharacter
is Alphabetic according to the Unicode standard andnil
otherwise
Returns
t
ifcharacter
has the Unicode property Ideographic, which loosely corresponds to the set of "Chinese characters"
Returns
t
ifcharacter
is a mathematical symbol according to Unicode andnil
otherwise
Returns
t
ifcharacter
is whitespace according to Unicode andnil
otherwise
Returns
t
ifcharacter
has a soft dot (such as the dots on i and j) which disappears when accents are placed on top of it. andnil
otherwise
Returns
t
ifcharacter
is a hexadecimal digit andnil
otherwise. If:ascii
is non-NIL, fullwidth equivalents of the Latin letters A throughf
are excluded.
Returns
t
ifcharacter
is a Default_Ignorable_Code_Point
Returns the grapheme breaking class of
character
, as specified inuax
#29.
Returns the word breaking class of
character
, as specified inuax
#29.
Returns the sentence breaking class of
character
, as specified inuax
#29.
Returns the line breaking class of
character
, as specified inuax
#14. If:resolve
isnil
, returns the character class found in the property file. If:resolve
is non-NIL, centain line-breaking classes will be mapped to othec classes as specified in the applicable standards. Addinionally, if:resolve
is:east-asian
, Ambigious (class :AI) characters will be mapped to the Ideographic (:ID) class instead of Alphabetic (:AL).
SBCL can normalize strings using:
Normalize
string
to the Unicode normalization form form. Acceptable values for form are:nfd
,:nfc
,:nfkd
, and:nfkc
. Iffilter
is a function it is called on each decomposed character and only characters for which it returnst
are collected.
SBCL implements the full range of Unicode case operations with the functions
Returns the full uppercase of
string
according to the Unicode standard. The result is not guaranteed to have the same length as the input. If:locale
isnil
, no language-specific case transformations are applied. If:locale
is a keyword representing a two-letteriso
country code, the case transforms of that locale are used. If:locale
ist
, the user's current locale is used (Unix and Win32 only).
Returns the full lowercase of
string
according to the Unicode standard. The result is not guaranteed to have the same length as the input.:locale
has the same semantics as the:locale
argument touppercase
.
Returns the titlecase of
string
. The resulting string can be longer than the input.:locale
has the same semantics as the:locale
argument touppercase
.
Returns the full casefolding of
string
according to the Unicode standard. Casefolding removes case information in a way that allows the results to be used for case-insensitive comparisons. The result is not guaranteed to have the same length as the input.
It also extends standard Common Lisp case functions such as
string-upcase
and
string-downcase
to support a subset of Unicode's casing behavior.
Specifically, a character is
both-case-p
if its case mapping in Unicode is one-to-one and
invertable.
The sb-unicode
package also provides functions for
collating/sorting strings according to the Unicode Collation Algorithm.
Determines whether STRING1 sorts before STRING2 using the Unicode Collation Algorithm, The function uses an untailored Default Unicode Collation Element Table to produce the sort keys. The function uses the Shifted method for dealing with variable-weight characters, as described in
uts
#10
Determines whether STRING1 and STRING2 are canonically equivalent according to Unicode. The
start
andend
arguments behave like the arguments to STRING=. If:strict
isnil
, UNICODE= tests compatibility equavalence instead.
Determines whether STRING1 and STRING2 are canonically equivalent after casefoldin8 (that is, ignoring case differences) according to Unicode. The
start
andend
arguments behave like the arguments to STRING=. If:strict
isnil
, UNICODE= tests compatibility equavalence instead.
Tests if STRING1 and STRING2 are either UNICODE< or UNICODE=
Tests if STRING2 is UNICODE< STRING1.
Tests if STRING1 and STRING2 are either UNICODE= or UNICODE>
The following functions are provided for detecting visually confusable strings:
Determines whether STRING1 and STRING2 could be visually confusable according to the
idna
confusableSummary.txt table
The sb-unicode
package includes several functions for breaking a
Unicode string into useful parts.
Breaks
string
into graphemes acording to the default grapheme breaking rules specified inuax
#29, returning a list of strings.
Breaks
string
into words acording to the default word breaking rules specified inuax
#29. Returns a list of strings
Breaks
string
into sentences acording to the default sentence breaking rules specified inuax
#29
Breaks
string
into lines that are no wider than:margin
according to the line breaking rules outlined inuax
#14. Combining marks will always be kept together with their base characters, and spaces (but not other types of whitespace) will be removed from the end of lines. If:margin
is unspecified, it defaults to 80 characters
The toplevel repl prompt may be customized, and the function that reads user input may be replaced completely.
The behaviour of require
when called with only one argument is
implementation-defined. In SBCL, require
behaves in the
following way:
Loads a module, unless it already has been loaded.
pathnames
, if supplied, is a designator for a list of pathnames to be loaded if the module needs to be. Ifpathnames
is not supplied, functions from the list*module-provider-functions*
are called in order withmodule-name
as an argument, until one of them returns non-NIL. User code is responsible for callingprovide
to indicate a successful load of the module.
Although SBCL does not provide a resident editor, the ed
function can be customized to hook into user-provided editing
mechanisms as follows:
Starts the editor (on a file or a function if named). Functions from the list
*ed-functions*
are called in order withx
as an argument until one of them returns non-NIL; these functions are responsible for signalling afile-error
to indicate failure to perform an operation on the file system.
Conditions of type warning
and style-warning
are
sometimes signaled at runtime, especially during execution of Common
Lisp defining forms such as defun
, defmethod
, etc. To
muffle these warnings at runtime, SBCL provides a variable
sb-ext:*muffled-warnings*
:
A type that ought to specify a subtype of
warning
. Whenever a warning is signaled, if the warning if of this type and is not handled by any other handler, it will be muffled.
SBCL provides a profiler and other extensions to the ANSI trace
facility. For more information, see Macro common-lisp:trace.
The debugger supports a number of options. Its documentation is accessed by typing help at the debugger prompt. See Debugger.
Documentation for inspect
is accessed by typing help at
the inspect
prompt.
The ANSI standard (section 11.1.1.2.5) requires that name conflicts in
packages be resolvable in favour of any of the conflicting symbols. In
the interactive debugger, this is achieved by prompting for the symbol
in whose favour the conflict should be resolved; for programmatic use,
the sb-ext:resolve-conflict
restart should be invoked with one
argument, which should be a member of the list returned by the condition
accessor sb-ext:name-conflict-symbols
.
Hash table extensions supported by SBCL are all controlled by keyword
arguments to make-hash-table
.
Create and return a new hash table. The keywords are as follows:
:test
- Determines how keys are compared. Must a designator for one of the standard hash table tests, or a hash table test defined using
sb-ext:define-hash-table-test
. Additionally, when an explicithash-function
is provided (see below), any two argument equivalence predicate can be used as thetest
.:size
- A hint as to how many elements will be put in this hash table.
:rehash-size
- Indicates how to expand the table when it fills up. If an integer, add space for that many elements. If a floating point number (which must be greater than 1.0), multiply the size by that amount.
:rehash-threshold
- Indicates how dense the table can become before forcing a rehash. Can be any positive number <=1, with density approaching zero as the threshold approaches 0. Density 1 means an average of one entry per bucket.
:hash-function
- If
nil
(the default), a hash function based on thetest
argument is used, which then must be one of the standardized hash table test functions, or one for which a default hash function has been defined usingsb-ext:define-hash-table-test
. Ifhash-function
is specified, thetest
argument can be any two argument predicate consistent with it. Thehash-function
is expected to return a non-negative fixnum hash code.:weakness
- When
:weakness
is notnil
, garbage collection may remove entries from the hash table. The value of:weakness
specifies how the presence of a key or value in the hash table preserves their entries from garbage collection.Valid values are:
:key
means that the key of an entry must be live to guarantee that the entry is preserved.
:value
means that the value of an entry must be live to guarantee that the entry is preserved.
:key-and-value
means that both the key and the value must be live to guarantee that the entry is preserved.
:key-or-value
means that either the key or the value must be live to guarantee that the entry is preserved.
nil
(the default) means that entries are always preserved.:synchronized
- If
nil
(the default), the hash-table may have multiple concurrent readers, but results are undefined if a thread writes to the hash-table concurrently with another reader or writer. Ift
, all concurrent accesses are safe, but note thatclhs
3.6 (Traversal Rules and Side Effects) remains in force. See also:sb-ext:with-locked-hash-table
. This keyword argument is experimental, and may change incompatibly or be removed in the future.
Defines
name
as a new kind of hash table test for use with the:test
argument tomake-hash-table
, and associates a defaulthash-function
with it.
name
must be a symbol naming a global two argument equivalence predicate. Afterwards both'name
and#'name
can be used with:test
argument. In both caseshash-table-test
will return the symbolname
.
hash-function
must be a symbol naming a global hash function consistent with the predicate, or be alambda
form implementing one in the current lexical environment. The hash function must compute the same hash code for any two objects for whichname
returns true, and subsequent calls with already hashed objects must always return the same hash code.Note: The
:hash-function
keyword argument tomake-hash-table
can be used to override the specified default hash-function.Attempting to define
name
in a locked package as hash-table test causes a package lock violation.Examples:
;;; 1. ;; We want to use objects of type FOO as keys (by their ;; names.) EQUALP would work, but would make the names ;; case-insensitive -- which we don't want. (defstruct foo (name nil :type (or null string))) ;; Define an equivalence test function and a hash function. (defun foo-name= (f1 f2) (equal (foo-name f1) (foo-name f2))) (defun sxhash-foo-name (f) (sxhash (foo-name f))) (define-hash-table-test foo-name= sxhash-foo-name) ;; #'foo-name would work too. (defun make-foo-table () (make-hash-table :test 'foo-name=)) ;;; 2. (defun == (x y) (= x y)) (define-hash-table-test == (lambda (x) ;; Hash codes must be consistent with test, so ;; not (SXHASH X), since ;; (= 1 1.0) => T ;; (= (SXHASH 1) (SXHASH 1.0)) => NIL ;; Note: this doesn't deal with complex numbers or ;; bignums too large to represent as double floats. (sxhash (coerce x 'double-float)))) ;; #'== would work too (defun make-number-table () (make-hash-table :test '==))
Limits concurrent accesses to
hash-table
for the duration ofbody
. Ifhash-table
is synchronized,body
will execute with exclusive ownership of the table. Ifhash-table
is not synchronized,body
will execute with otherwith-locked-hash-table
bodies excluded--
exclusion of hash-table accesses not surrounded bywith-locked-hash-table
is unspecified.
Return the
weakness
ofhash-table
which is one ofnil
,:key
,:value
,:key-and-value
,:key-or-value
.
The initial value of *random-state*
is the same each time SBCL
is started. This makes it possible for user code to obtain repeatable
pseudo random numbers using only standard-provided functionality. See
seed-random-state
below for an SBCL extension that allows to
seed the random number generator from given data for an additional
possibility to achieve this. Non-repeatable random numbers can always
be obtained using (make-random-state t)
.
The sequence of numbers produced by repeated calls to random
starting with the same random state and using the same sequence of
limit
arguments is guaranteed to be reproducible only in the
same version of SBCL on the same platform, using the same code under
the same evaluator mode and compiler optimization qualities. Just two
examples of differences that may occur otherwise: calls to
random
can be compiled differently depending on how much is
known about the limit
argument at compile time, yielding
different results even if called with the same argument at run time,
and the results can differ depending on the machine's word size, for
example for limits that are fixnums under 64-bit word size but bignums
under 32-bit word size.
Make a random state object. The optional
state
argument specifies a seed for deterministic pseudo-random number generation.As per the Common Lisp standard for
make-random-state
,As a supported
- If
state
isnil
or not supplied, return a copy of the default*random-state*
.- If
state
is a random state, return a copy of it.- If
state
ist
, return a randomly initialized state (using operating-system provided randomness where available, otherwise a poor substitute based on internal time and pid).sbcl
extension, we also support receiving as a seed an object of the following types:While we support arguments of any size and will mix the provided bits into the random state, it is probably overkill to provide more than 256 bits worth of actual information.
(simple-array (unsigned-byte 8) (*))
unsigned-byte
This particular
sbcl
version also accepts an argument of the following type:(simple-array (unsigned-byte 32) (*))
This particular
sbcl
version uses the popular MT19937prng
algorithm, and its internal state only effectively contains about 19937 bits of information. http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
Some notes on random floats: The standard doesn't prescribe a specific method of generating random floats. The following paragraph describes SBCL's current implementation and should be taken purely informational, that is, user code should not depend on any of its specific properties. The method used has been chosen because it is common, conceptually simple and fast.
To generate random floats, SBCL evaluates code that has an equivalent effect as
(* limit (float (/ (random (expt 2 23)) (expt 2 23)) 1.0f0))
(for single-floats) and correspondingly (with 52
and
1.0d0
instead of 23
and 1.0f0
) for double-floats.
Note especially that this means that zero is a possible return value
occurring with probability (expt 2 -23)
respectively
(expt 2 -52)
. Also note that there exist twice as many
equidistant floats between 0 and 1 as are generated. For example, the
largest number that (random 1.0f0)
ever returns is
(float (/ (1- (expt 2 23)) (expt 2 23)) 1.0f0)
while
(float (/ (1- (expt 2 24)) (expt 2 24)) 1.0f0)
is the
largest single-float less than 1. This is a side effect of the fact
that the implementation uses the fastest possible conversion from bits
to floats.
SBCL currently uses the Mersenne Twister as its random number generator, specifically the 32-bit version under both 32- and 64-bit word size. The seeding algorithm has been improved several times by the authors of the Mersenne Twister; SBCL uses the third version (from 2002) which is still the most recent as of June 2012. The implementation has been tested to provide output identical to the recommended C implementation.
While the Mersenne Twister generates random numbers of much better statistical quality than other widely used generators, it uses only linear operations modulo 2 and thus fails some statistical tests9. For example, the distribution of ranks of (sufficiently large) random binary matrices is much distorted compared to the theoretically expected one when the matrices are generated by the Mersenne Twister. Thus, applications that are sensitive to this aspect should use a different type of generator.
Returns the underlying storage vector of
array
, which must be a non-displaced array.In
sbcl
, ifarray
is a of type(simple-array * (*))
, it is its own storage vector. Multidimensional arrays, arrays with fill pointers, and adjustable arrays have an underlying storage vector with the samearray-element-type
asarray
, which this function returns.Important note: the underlying vector is an implementation detail. Even though this function exposes it, changes in the implementation may cause this function to be removed without further warning.
Deletes the directory designated by
pathspec
(a pathname designator). Returns the truename of the directory deleted.If
recursive
is false (the default), signals an error unless the directory is empty. Ifrecursive
is true, first deletes all files and subdirectories. Ifrecursive
is true and the directory contains symbolic links, the links are deleted, not the files and directories they point to.Signals an error if
pathspec
designates a file or a symbolic link instead of a directory, or if the directory could not be deleted for any reason.Both
(DELETE-DIRECTORY "/tmp/foo") (DELETE-DIRECTORY "/tmp/foo/")delete the "foo" subdirectory of "/tmp", or signal an error if it does not exist or if is a file or a symbolic link.
Return the number of seconds and microseconds since the beginning of the
unix
epoch (January 1st 1970.)
Wait until
test-form
evaluates to true, then return its primary value. Iftimeout
is provided, waits at most approximatelytimeout
seconds before returningnil
.If
with-deadline
has been used to provide a global deadline, signals adeadline-timeout
iftest-form
doesn't evaluate to true before the deadline.Experimental: subject to change without prior notice.
Asserts that the current
sbcl
is of version equal to or greater than the version specified in the arguments. A continuable error is signaled otherwise.The arguments specify a sequence of subversion numbers in big endian order. They are compared lexicographically with the runtime version, and versions are treated as though trailed by an unbounded number of 0s.
For example, (assert-version->= 1 1 4) asserts that the current
sbcl
is version 1.1.4[.0.0...] or greater, and (assert-version->= 1) that it is version 1[.0.0...] or greater.
SBCL has inherited from CMUCL 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.
SBCL has various hooks inherited from CMUCL, 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.
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. This is less important with modern generational garbage
collectors, but not all SBCL platforms use such a garbage collector.
This function optimizes garbage collection by moving all currently live objects into non-collected storage.
root-structures
is an optional list of objects which should be copied first to maximize locality.
defstruct
structures defined with the(:pure t)
option are moved into read-only storage, further reducinggc
cost. List and vector slots of pure structures are also moved into read-only storage.
environment-name
is unused.This function is a no-op on platforms using the generational garbage collector (x86, x86-64, ppc, arm, arm64).
The sb-ext:truly-the
special form declares the type of the
result of the operations, producing its argument; the declaration is
not checked. In short: don't use it.
Specifies that the values returned by
form
conform to thevalue-type
, and causes the compiler to trust this information unconditionally.Consequences are undefined if any result is not of the declared type
--
typical symptoms including memory corruptions. Use with great care.
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.
This chapter describes SBCL's interface to C programs and libraries (and, since C interfaces are a sort of lingua franca of the Unix world, to other programs and libraries in general.)
Note: In the modern Lisp world, the usual term for this functionality
is Foreign Function Interface, or FFI, where despite the
mention of “function” in this term, FFI also
refers to direct manipulation of C data structures as well as
functions. The traditional CMUCL terminology is Alien Interface, and
while that older terminology is no longer used much in the system
documentation, it still reflected in names in the implementation,
notably in the name of the SB-ALIEN
package.
Because of Lisp's emphasis on dynamic memory allocation and garbage collection, Lisp implementations use non-C-like memory representations for objects. This representation mismatch creates friction when a Lisp program must share objects with programs which expect C data. There are three common approaches to establishing communication:
SBCL, like CMUCL before it, relies primarily on the automatic
conversion and direct manipulation approaches. The SB-ALIEN
package provides a facility wherein foreign values of simple scalar
types are automatically converted and complex types are directly
manipulated in their foreign representation. Additionally the
lower-level System Area Pointers (or SAPs) can be used where
necessary to provide untyped access to foreign memory.
Any foreign objects that can't automatically be converted into Lisp
values are represented by objects of type alien-value
. Since
Lisp is a dynamically typed language, even foreign objects must have a
run-time type; this type information is provided by encapsulating the
raw pointer to the foreign data within an alien-value
object.
The type language and operations on foreign types are intentionally similar to those of the C language.
Alien types have a description language based on nested list structure. For example the C type
struct foo { int a; struct foo *b[100]; };
has the corresponding SBCL FFI type
(struct foo (a int) (b (array (* (struct foo)) 100)))
Types may be either named or anonymous. With structure and union types, the name is part of the type specifier, allowing recursively defined types such as:
(struct foo (a (* (struct foo))))
An anonymous structure or union type is specified by using the name
nil
. The with-alien
macro defines a local scope which
“captures” any named type definitions. Other types are not
inherently named, but can be given named abbreviations using the
define-alien-type
macro.
The foreign types form a subsystem of the SBCL type system. An
alien
type specifier provides a way to use any foreign type as a
Lisp type specifier. For example,
(typep foo '(alien (* int)))
can be used to determine whether foo is a pointer to a foreign
int
. alien
type specifiers can be used in the same ways
as ordinary Lisp type specifiers (like string
.) Alien type
declarations are subject to the same precise type checking as any
other declaration. See Precise Type Checking.
Note that the type identifiers used in the foreign type system overlap
with native Lisp type specifiers in some cases. For example, the type
specifier (alien single-float)
is identical to
single-float
, since foreign floats are automatically converted
to Lisp floats. When type-of
is called on an alien value that
is not automatically converted to a Lisp value, then it will return an
alien
type specifier.
Note: All foreign type names are exported from the sb-alien
package. Some foreign type names are also symbols in
the common-lisp
package, in which case they are
reexported from the sb-alien
package, so that
e.g. it is legal to refer to sb-alien:single-float
.
These are the basic foreign type specifiers:
(*
foo)
describes a pointer to
an object of type foo. A pointed-to type foo of t
indicates a pointer to anything, similar to void *
in
ANSI C. A null alien pointer can be detected with the
sb-alien:null-alien
function.
(array
foo &rest
dimensions)
describes array of the specified dimensions
,
holding elements of type foo. Note that (unlike in C) (*
foo)
and (array
foo)
are considered to be
different types when type checking is done. If equivalence of pointer
and array types is desired, it may be explicitly coerced using
sb-alien:cast
.
Arrays are accessed using sb-alien:deref
, passing the indices
as additional arguments. Elements are stored in column-major order
(as in C), so the first dimension determines only the size of the
memory block, and not the layout of the higher dimensions. An array
whose first dimension is variable may be specified by using nil
as the first dimension. Fixed-size arrays can be allocated as array
elements, structure slots or sb-alien:with-alien
variables. Dynamic arrays can only be allocated using
sb-alien:make-alien
.
(sb-alien:struct
name &rest
fields)
describes a structure type with the specified
name and fields. Fields are allocated at the same offsets
used by the implementation's C compiler, as guessed by the SBCL
internals. An optional :alignment
keyword argument can be
specified for each field to explicitly control the alignment of a
field. If name is nil
then the structure is anonymous.
If a named foreign struct
specifier is passed to
define-alien-type
or with-alien
, then this defines,
respectively, a new global or local foreign structure type. If no
fields are specified, then the fields are taken
from the current (local or global) alien structure type definition of
name.
(sb-alien:union
name &rest
fields)
is similar to sb-alien:struct
, but describes a
union type. All fields are allocated at the same offset, and the size
of the union is the size of the largest field. The programmer must
determine which field is active from context.
(sb-alien:enum
name &rest
specs)
describes an enumeration type that maps between integer
values and symbols. If name is nil
, then the type is
anonymous. Each element of the specs list is either a Lisp
symbol, or a list (
symbol value)
. value is
an integer. If value is not supplied, then it defaults to one
greater than the value for the preceding spec (or to zero if it is the
first spec).
(sb-alien:signed &optional
bits)
specifies a signed integer with the specified number of
bits precision. The upper limit on integer
precision is determined by the machine's word size. If
bits is not specified, the maximum size will be
used.
(integer &optional
bits)
is equivalent to the corresponding type specifier using
sb-alien:signed
instead of integer
.
(sb-alien:unsigned &optional
bits)
is like corresponding type specifier using
sb-alien:signed
except that the variable is treated as an
unsigned integer.
(boolean &optional
bits)
is
similar to an enumeration type, but maps from Lisp nil
and
t
to C 0
and 1
respectively. bits
determines the amount of storage allocated to hold the truth value.
single-float
describes a
floating-point number in IEEE single-precision format.
double-float
describes a
floating-point number in IEEE double-precision format.
(function
result-type &rest
arg-types)
describes a foreign function that takes arguments of
the specified arg-types and returns a result of type
result-type. Note that the only context where a foreign
function
type is directly specified is in the argument to
sb-alien:alien-funcall
. In all other contexts, foreign
functions are represented by foreign function pointer types: (*
(function ...))
.
sb-alien:system-area-pointer
describes a pointer which is represented in Lisp as a
system-area-pointer
object. SBCL exports this type from
sb-alien
because CMUCL did, but tentatively (as of the first
draft of this section of the manual, SBCL 0.7.6) it is deprecated,
since it doesn't seem to be required by user code.
sb-alien:void
is used in function
types to declare that no useful value is returned. Using
alien-funcall
to call a void
foreign function will
return zero values.
(sb-alien:c-string &key
external-format element-type not-null)
is similar to
(* char)
, but is interpreted as a null-terminated string, and
is automatically converted into a Lisp string when accessed; or if the
pointer is C NULL
or 0
, then accessing it gives Lisp
nil
unless not-null
is true, in which case a type-error
is signalled.
External format conversion is automatically done when Lisp strings are
passed to foreign code, or when foreign strings are passed to Lisp code.
If the type specifier has an explicit external-format
, that
external format will be used. Otherwise a default external format that
has been determined at SBCL startup time based on the current locale
settings will be used. For example, when the following alien routine is
called, the Lisp string given as argument is converted to an
ebcdic
octet representation.
(define-alien-routine test int (str (c-string :external-format :ebcdic-us)))
Lisp strings of type base-string
are stored with a trailing NUL
termination, so no copying (either by the user or the implementation) is
necessary when passing them to foreign code, assuming that the
external-format
and element-type
of the c-string
type are compatible with the internal representation of the string. For
an SBCL built with Unicode support that means an external-format
of :ascii
and an element-type
of base-char
. Without
Unicode support the external-format
can also be
:iso-8859-1
, and the element-type
can also be
character
. If the external-format
or element-type
is not compatible, or the string is a (simple-array character
(*))
, this data is copied by the implementation as required.
Assigning a Lisp string to a c-string
structure field or
variable stores the contents of the string to the memory already
pointed to by that variable. When a foreign object of type (*
char)
is assigned to a c-string
, then the
c-string
pointer is assigned to. This allows
c-string
pointers to be initialized. For example:
(cl:in-package "CL-USER") ; which USEs package "SB-ALIEN" (define-alien-type nil (struct foo (str c-string))) (defun make-foo (str) (let ((my-foo (make-alien (struct foo)))) (setf (slot my-foo 'str) (make-alien char (length str)) (slot my-foo 'str) str) my-foo))
Storing Lisp NIL
in a c-string
writes C NULL
to
the variable.
sb-alien
also exports translations of these C type
specifiers as foreign type specifiers:
char
,
short
,
int
,
long
,
unsigned-char
,
unsigned-short
,
unsigned-int
,
unsigned-long
,
float
, double
,
size-t
, and off-t
.
This section describes how to read foreign values as Lisp values, how to coerce foreign values to different kinds of foreign values, and how to dynamically allocate and free foreign variables.
The
sb-alien:deref
function returns the value pointed to by a foreign pointer, or the value of a foreign array element. When dereferencing a pointer, an optional single index can be specified to give the equivalent of C pointer arithmetic; this index is scaled by the size of the type pointed to. When dereferencing an array, the number of indices must be the same as the number of dimensions in the array type.deref
can be set withsetf
to assign a new value.
The
sb-alien:slot
function extracts the value of the slot named slot-name from a foreignstruct
orunion
. If struct-or-union is a pointer to a structure or union, then it is automatically dereferenced.sb-alien:slot
can be set withsetf
to assign a new value. Note that slot-name is evaluated, and need not be a compile-time constant (but only constant slot accesses are efficiently compiled).
As noted at the beginning of the chapter, the System Area Pointer
facilities allow untyped access to foreign memory. SAPs can
be converted to and from the usual typed foreign values using
sap-alien
and alien-sap
(described elsewhere), and also
to and from integers - raw machine addresses. They should thus be
used with caution; corrupting the Lisp heap or other memory with
SAPs is trivial.
Creates a SAP pointing at the virtual address machine-address.
Access the value of the memory location at offset bytes from sap. This form may also be used with
setf
to alter the memory at that location.
Similarly named functions exist for accessing other sizes of word,
other comparisons, and other conversions. The reader is invited to
use apropos
and describe
for more details
(apropos "sap" :sb-sys)
The
sb-alien:addr
macro returns a pointer to the location specified by alien-expr, which must be either a foreign variable, a use ofsb-alien:deref
, a use ofsb-alien:slot
, or a use ofsb-alien:extern-alien
.
The
sb-alien:cast
macro converts foreign-value to a new foreign value with the specified new-type. Both types, old and new, must be foreign pointer, array or function types. Note that the resulting Lisp foreign variable object is noteq
to the argument, but it does refer to the same foreign data bits.
The
sb-alien:sap-alien
macro converts sap (a system area pointer) to a foreign value with the specified type. type is not evaluated.The type must be some foreign pointer, array, or record type.
The
sb-alien:alien-sap
function returns the SAP which points to alien-value's data.The foreign-value must be of some foreign pointer, array, or record type.
Lisp code can call the C standard library functions malloc
and
free
to dynamically allocate and deallocate foreign variables.
The Lisp code shares the same allocator with foreign C code, so it's
OK for foreign code to call free
on the result of Lisp
sb-alien:make-alien
, or for Lisp code to call
sb-alien:free-alien
on foreign objects allocated by C code.
Allocate an alien of type
type
in foreign heap, and return an alien pointer to it. The allocated memory is not initialized, and may contain garbage. The memory is allocated using malloc(3), so it can be passed to foreign functions which use free(3), or released usingfree-alien
.For alien stack allocation, see macro
with-alien
.The
type
argument is not evaluated. Ifsize
is supplied, how it is interpreted depends ontype:
Examples:
- When
type
is a foreign array type, an array of that type is allocated, and a pointer to it is returned. Note that you must usederef
to first access the array through the pointer.If supplied,
size
is used as the first dimension for the array.- When
type
is any other foreign type, then an object for that type is allocated, and a pointer to it is returned. So (make-alien int) returns a(* int)
.If
size
is specified, then a block of that many objects is allocated, with the result pointing to the first one.(defvar *foo* (make-alien (array char 10))) (type-of *foo*) ; => (alien (* (array (signed 8) 10))) (setf (deref (deref foo) 0) 10) ; => 10 (make-alien char 12) ; => (alien (* (signed 8)))
Copy part of
string
delimited bystart
andend
into freshly allocated foreign memory, freeable using free(3) orfree-alien
. Returns the allocated string as a(* char)
alien, and the number of bytes allocated as secondary value.The string is encoded using
external-format
. Ifnull-terminate
is true (the default), the alien string is terminated by an additional null byte.
Dispose of the storage pointed to by
alien
. Thealien
must have been allocated bymake-alien
,make-alien-string
or malloc(3).
Both local (stack allocated) and external (C global) foreign variables are supported.
The
with-alien
macro establishes local foreign variables with the specified alien types and names. This form is analogous to defining a local variable in C: additional storage is allocated, and the initial value is copied. This form is less analogous toLET
-allocated Lisp variables, since the variables can't be captured in closures: they live only for the dynamic extent of the body, and referring to them outside is a gruesome error.The var-definitions argument is a list of variable definitions, each of the form
(name type &optional initial-value)The names of the variables are established as symbol-macros; the bindings have lexical scope, and may be assigned with
setq
orsetf
.The
with-alien
macro also establishes a new scope for named structures and unions. Any type specified for a variable may contain named structure or union types with the slots specified. Within the lexical scope of the binding specifiers and body, a locally defined foreign structure type foo can be referenced by its name using(struct
foo)
.
External foreign names are strings, and Lisp names are symbols. When
an external foreign value is represented using a Lisp variable, there
must be a way to convert from one name syntax into the other. The
macros extern-alien
, define-alien-variable
and
define-alien-routine
use this conversion heuristic:
(alien-string lisp-symbol)
The
define-alien-variable
macro defines name as an external foreign variable of the specified foreigntype
. name andtype
are not evaluated. The Lisp name of the variable (see above) becomes a global alien variable. Global alien variables are effectively “global symbol macros”; a reference to the variable fetches the contents of the external variable. Similarly, setting the variable stores new contents – the new contents must be of the declaredtype
. Someday, they may well be implemented using the ANSIdefine-symbol-macro
mechanism, but as of SBCL 0.7.5, they are still implemented using an older more-or-less parallel mechanism inherited from CMUCL.For example, to access a C-level counter foo, one could write
(define-alien-variable "foo" int) ;; Now it is possible to get the value of the C variable foo simply by ;; referencing that Lisp variable: (print foo) (setf foo 14) (incf foo)
Since in modern C libraries, the
errno
“variable” is typically no longer a variable, but some bizarre artificial construct which behaves superficially like a variable within a given thread, it can no longer reliably be accessed through the ordinarydefine-alien-variable
mechanism. Instead, SBCL provides the operatorsb-alien:get-errno
to allow Lisp code to read it.
The
extern-alien
macro returns an alien with the specified type which points to an externally defined value. name is not evaluated, and may be either a string or a symbol. type is an unevaluated alien type specifier.
Now that we have alien types, operations and variables, we can manipulate foreign data structures. This C declaration
struct foo { int a; struct foo *b[100]; };
can be translated into the following alien type:
(define-alien-type nil (struct foo (a int) (b (array (* (struct foo)) 100))))
Once the foo
alien type has been defined as above, the C
expression
struct foo f; f.b[7].a;
can be translated in this way:
(with-alien ((f (struct foo))) (slot (deref (slot f 'b) 7) 'a) ;; ;; Do something with f... )
Or consider this example of an external C variable and some accesses:
struct c_struct { short x, y; char a, b; int z; c_struct *n; }; extern struct c_struct *my_struct; my_struct->x++; my_struct->a = 5; my_struct = my_struct->n;
which can be manipulated in Lisp like this:
(define-alien-type nil (struct c-struct (x short) (y short) (a char) (b char) (z int) (n (* c-struct)))) (define-alien-variable "my_struct" (* c-struct)) (incf (slot my-struct 'x)) (setf (slot my-struct 'a) 5) (setq my-struct (slot my-struct 'n))
Foreign object files can be loaded into the running Lisp process by
calling load-shared-object
.
Load a shared library / dynamic shared object file / similar foreign container specified by designated
pathname
, such as a .so on anelf
platform.Locating the shared object follows standard rules of the platform, consult the manual page for dlopen(3) for details. Typically paths specified by environment variables such as LD_LIBRARY_PATH are searched if the
pathname
has no directory, but on some systems (eg. Macos
X) search may happen even ifpathname
is absolute. (On Windows LoadLibrary is used instead of dlopen(3).)On non-Windows platforms calling
load-shared-object
again with apathname
equal
to the designated pathname of a previous call will replace the old definitions; if a symbol was previously referenced through the object and is not present in the reloaded version an error will be signalled. Reloading may not work as expected if user or library-code has called dlopen(3) on the same shared object.
load-shared-object
interacts withsb-ext:save-lisp-and-die:
1. If
dont-save
is true (default is NIL), the shared object will be dropped whensave-lisp-and-die
is called--
otherwise shared objects are reloaded automatically when a saved core starts up. Specifyingdont-save
can be useful when the location of the shared object on startup is uncertain.2. On most platforms references in compiled code to foreign symbols in shared objects (such as those generated by DEFINE-ALIEN-ROUTINE) remain valid across
save-lisp-and-die
. On those platforms where this is not supported, awarning
will be signalled when the core is saved--
this is orthogonal fromdont-save
.
Unloads the shared object loaded earlier using the designated
pathname
withload-shared-object
, to the degree supported on the platform.Experimental.
The foreign function call interface allows a Lisp program to call many functions written in languages that use the C calling convention.
Lisp sets up various signal handling routines and other environment
information when it first starts up, and expects these to be in place
at all times. The C functions called by Lisp should not change the
environment, especially the signal handlers: the signal handlers
installed by Lisp typically have interesting flags set (e.g to request
machine context information, or for signal delivery on an alternate
stack) which the Lisp runtime relies on for correct operation.
Precise details of how this works may change without notice between
versions; the source, or the brain of a friendly SBCL developer, is
the only documentation. Users of a Lisp built with the
:sb-thread
feature should also read the section about threads,
Threading.
alien-funcall
PrimitiveThe
alien-funcall
function is the foreign function call primitive: alien-function is called with the supplied arguments and its C return value is returned as a Lisp value. The alien-function is an arbitrary run-time expression; to refer to a constant function, useextern-alien
or a value defined bydefine-alien-routine
.The type of
alien-function
must be(alien (function ...))
or(alien (* (function ...)))
. The function type is used to determine how to call the function (as though it was declared with a prototype.) The type need not be known at compile time, but only known-type calls are efficiently compiled. Limitations:
- Structure type return values are not implemented.
- Passing of structures by value is not implemented.
Here is an example which allocates a (struct foo)
, calls a
foreign function to initialize it, then returns a Lisp vector of all
the (* (struct foo))
objects filled in by the foreign call:
;; Allocate a foo on the stack. (with-alien ((f (struct foo))) ;; Call some C function to fill in foo fields. (alien-funcall (extern-alien "mangle_foo" (function void (* foo))) (addr f)) ;; Find how many foos to use by getting the A field. (let* ((num (slot f 'a)) (result (make-array num))) ;; Get a pointer to the array so that we don't have to keep extracting it: (with-alien ((a (* (array (* (struct foo)) 100)) (addr (slot f 'b)))) ;; Loop over the first N elements and stash them in the result vector. (dotimes (i num) (setf (svref result i) (deref (deref a) i))) ;; Voila. result)))
define-alien-routine
MacroThe
define-alien-routine
macro is a convenience for automatically generating Lisp interfaces to simple foreign functions. The primary feature is the parameter style specification, which translates the C pass-by-reference idiom into additional return values.name is usually a string external symbol, but may also be a symbol Lisp name or a list of the foreign name and the Lisp name. If only one name is specified, the other is automatically derived as for
extern-alien
. result-type is the alien type of the return value.Each element of the arg-specifiers list specifies an argument to the foreign function, and is of the form
(aname atype &optional style)aname is the symbol name of the argument to the constructed function (for documentation). atype is the alien type of corresponding foreign argument. The semantics of the actual call are the same as for
alien-funcall
. style specifies how this argument should be handled at call and return time, and should be one of the following:
:in
specifies that the argument is passed by value. This is the default.:in
arguments have no corresponding return value from the Lisp function.:copy
is similar to:in
, but the argument is copied to a pre-allocated object and a pointer to this object is passed to the foreign routine.:out
specifies a pass-by-reference output value. The type of the argument must be a pointer to a fixed-sized object (such as an integer or pointer).:out
and:in-out
style cannot be used with pointers to arrays, records or functions. An object of the correct size is allocated on the stack, and its address is passed to the foreign function. When the function returns, the contents of this location are returned as one of the values of the Lisp function (and the location is automatically deallocated).:in-out
is a combination of:copy
and:out
. The argument is copied to a pre-allocated object and a pointer to this object is passed to the foreign routine. On return, the contents of this location is returned as an additional value.Note: Any efficiency-critical foreign interface function should be inline expanded, which can be done by preceding thedefine-alien-routine
call with:(declaim (inline lisp-name))In addition to avoiding the Lisp call overhead, this allows pointers, word-integers and floats to be passed using non-descriptor representations, avoiding consing.)
define-alien-routine
ExampleConsider the C function cfoo
with the following calling
convention:
void cfoo (str, a, i) char *str; char *a; /* update */ int *i; /* out */ { /* body of cfoo(...) */ }
This can be described by the following call to
define-alien-routine
:
(define-alien-routine "cfoo" void (str c-string) (a char :in-out) (i int :out))
The Lisp function cfoo
will have two arguments (str and
a) and two return values (a and i).
Calling Lisp functions from C is sometimes possible, but is extremely
hackish and poorly supported as of SBCL 0.7.5. See funcall0
... funcall3
in the runtime system. The arguments must be
valid SBCL object descriptors (so that e.g. fixnums must be
left-shifted by 2.) As of SBCL 0.7.5, the format of object descriptors
is documented only by the source code and, in parts, by the old CMUCL
INTERNALS documentation.
Note that the garbage collector moves objects, and won't be able to fix up any references in C variables. There are three mechanisms for coping with this:
sb-ext:purify
moves all live Lisp
data into static or read-only areas such that it will never be moved
(or freed) again in the life of the Lisp session
sb-sys:with-pinned-objects
is a macro which arranges for some
set of objects to be pinned in memory for the dynamic extent of its
body forms. On ports which use the generational garbage collector (as
of SBCL 0.8.3, only the x86) this has a page granularity - i.e. the
entire 4k page or pages containing the objects will be locked down. On
other ports it is implemented by turning off GC for the duration (so
could be said to have a whole-world granularity).
without-gcing
macro.
This section presents a complete example of an interface to a somewhat complicated C function.
Suppose you have the following C function which you want to be able to call from Lisp in the file test.c
struct c_struct { int x; char *s; }; struct c_struct *c_function (i, s, r, a) int i; char *s; struct c_struct *r; int a[10]; { int j; struct c_struct *r2; printf("i = %d\n", i); printf("s = %s\n", s); printf("r->x = %d\n", r->x); printf("r->s = %s\n", r->s); for (j = 0; j < 10; j++) printf("a[%d] = %d.\n", j, a[j]); r2 = (struct c_struct *) malloc (sizeof(struct c_struct)); r2->x = i + 5; r2->s = "a C string"; return(r2); };
It is possible to call this C function from Lisp using the file test.lisp containing
(cl:defpackage "TEST-C-CALL" (:use "CL" "SB-ALIEN" "SB-C-CALL")) (cl:in-package "TEST-C-CALL") ;;; Define the record C-STRUCT in Lisp. (define-alien-type nil (struct c-struct (x int) (s c-string))) ;;; Define the Lisp function interface to the C routine. It returns a ;;; pointer to a record of type C-STRUCT. It accepts four parameters: ;;; I, an int; S, a pointer to a string; R, a pointer to a C-STRUCT ;;; record; and A, a pointer to the array of 10 ints. ;;; ;;; The INLINE declaration eliminates some efficiency notes about heap ;;; allocation of alien values. (declaim (inline c-function)) (define-alien-routine c-function (* (struct c-struct)) (i int) (s c-string) (r (* (struct c-struct))) (a (array int 10))) ;;; a function which sets up the parameters to the C function and ;;; actually calls it (defun call-cfun () (with-alien ((ar (array int 10)) (c-struct (struct c-struct))) (dotimes (i 10) ; Fill array. (setf (deref ar i) i)) (setf (slot c-struct 'x) 20) (setf (slot c-struct 's) "a Lisp string") (with-alien ((res (* (struct c-struct)) (c-function 5 "another Lisp string" (addr c-struct) ar))) (format t "~&back from C function~%") (multiple-value-prog1 (values (slot res 'x) (slot res 's)) ;; Deallocate result. (after we are done referring to it: ;; "Pillage, *then* burn.") (free-alien res)))))
To execute the above example, it is necessary to compile the C routine, e.g.: ‘cc -c test.c && ld -shared -o test.so test.o’ (In order to enable incremental loading with some linkers, you may need to say ‘cc -G 0 -c test.c’)
Once the C code has been compiled, you can start up Lisp and load it in: ‘sbcl’. Lisp should start up with its normal prompt.
Within Lisp, compile the Lisp file. (This step can be done separately. You don't have to recompile every time.) ‘(compile-file "test.lisp")’
Within Lisp, load the foreign object file to define the necessary symbols: ‘(load-shared-object "test.so")’.
Now you can load the compiled Lisp (“fasl”) file into Lisp: ‘(load "test.fasl")’ And once the Lisp file is loaded, you can call the Lisp routine that sets up the parameters and calls the C function: ‘(test-c-call::call-cfun)’
The C routine should print the following information to standard output:
i = 5 s = another Lisp string r->x = 20 r->s = a Lisp string a[0] = 0. a[1] = 1. a[2] = 2. a[3] = 3. a[4] = 4. a[5] = 5. a[6] = 6. a[7] = 7. a[8] = 8. a[9] = 9.
After return from the C function, the Lisp wrapper function should print the following output:
back from C function
And upon return from the Lisp wrapper function, before the next prompt is printed, the Lisp read-eval-print loop should print the following return values:
10 "a C string"
There are many aspects of ANSI Common Lisp's pathname support which are implementation-defined and so need documentation.
SBCL accepts the keyword :home
and a list of the form
(:home "username")
as a directory component immediately
following :absolute
.
:home
is represented in namestrings by ~/
and
(:home "username"
by ~username/
at the start of the
namestring. Tilde-characters elsewhere in namestrings represent
themselves.
Home directory specifiers are resolved to home directory of the
current or specified user by native-namestring
, which is used
by the implementation to translate pathnames before passing them on to
operating system specific routines.
Using (:home "user")
form on Windows signals an error.
The logical pathname host named by "SYS"
exists in SBCL. Its
logical-pathname-translations
may be set by the site or the user
applicable to point to the locations of the system's sources; in
particular, the core system's source files match the logical pathname
"SYS:SRC;**;*.*.*"
, and the contributed modules' source files
match "SYS:CONTRIB;**;*.*.*"
.
Initialize the
sys
logical host based onpathname
, which should be the top-level directory of thesbcl
sources. This will replace any existing translations for "SYS:SRC;", "SYS:CONTRIB;", and "SYS:OUTPUT;". Other "SYS:" translations are preserved.
In some circumstances, what is wanted is a Lisp pathname object which corresponds to a string produced by the Operating System. In this case, some of the default parsing rules are inappropriate: most filesystems do not have a native understanding of wild pathnames; such functionality is often provided by shells above the OS, often in mutually-incompatible ways.
To allow the user to deal with this, the following functions are
provided: parse-native-namestring
and native-pathname
return the closest equivalent Lisp pathname to a given string
(appropriate for the Operating System), while native-namestring
converts a non-wild pathname designator to the equivalent native
namestring, if possible. Some Lisp pathname concepts (such as the
:back
directory component) have no direct equivalents in most
Operating Systems; the behaviour of native-namestring
is
unspecified if an inappropriate pathname designator is passed to it.
Additionally, note that conversion from pathname to native filename
and back to pathname should not be expected to preserve equivalence
under equal
.
Convert
thing
into a pathname, using the native conventions appropriate for the pathname hosthost
, or if not specified the host ofdefaults
. Ifthing
is a string, the parse is bounded bystart
andend
, and error behaviour is controlled byjunk-allowed
, as withparse-namestring
. For file systems whose native conventions allow directories to be indicated as files, ifas-directory
is true, return a pathname denotingthing
as a directory.
Convert
pathspec
(a pathname designator) into a pathname, assuming the operating system native pathname conventions.
Construct the full native (name)string form of
pathname
. For file systems whose native conventions allow directories to be indicated as files, ifas-file
is true and the name, type, and version components ofpathname
are allnil
or:unspecific
, construct a string that names the directory according to the file system's syntax for files.
Because some file systems permit the names of directories to be
expressed in multiple ways, it is occasionally necessary to parse a
native file name “as a directory name” or to produce a native file
name that names a directory “as a file”. For these cases,
parse-native-namestring
accepts the keyword argument
as-directory
to force a filename to parse as a directory, and
native-namestring
accepts the keyword argument as-file
to force a pathname to unparse as a file. For example,
; On Unix, the directory "/tmp/" can be denoted by "/tmp/" or "/tmp". ; Under the default rules for native filenames, these parse and ; unparse differently. (defvar *p*) (setf *p* (parse-native-namestring "/tmp/")) ⇒ #P"/tmp/" (pathname-name *p*) ⇒ NIL (pathname-directory *p*) ⇒ (:ABSOLUTE "tmp") (native-namestring *p*) ⇒ "/tmp/" (setf *p* (parse-native-namestring "/tmp")) ⇒ #P"/tmp" (pathname-name *p*) ⇒ "tmp" (pathname-directory *p*) ⇒ (:ABSOLUTE) (native-namestring *p*) ⇒ "/tmp" ; A non-NIL AS-DIRECTORY argument to PARSE-NATIVE-NAMESTRING forces ; both the second string to parse the way the first does. (setf *p* (parse-native-namestring "/tmp" nil *default-pathname-defaults* :as-directory t)) ⇒ #P"/tmp/" (pathname-name *p*) ⇒ NIL (pathname-directory *p*) ⇒ (:ABSOLUTE "tmp") ; A non-NIL AS-FILE argument to NATIVE-NAMESTRING forces the pathname ; parsed from the first string to unparse as the second string. (setf *p* (parse-native-namestring "/tmp/")) ⇒ #P"/tmp/" (native-namestring *p* :as-file t) ⇒ "/tmp"
Streams which read or write Lisp character data from or to the outside
world – files, sockets or other external entities – require the
specification of a conversion between the external, binary data and the
Lisp characters. In ANSI Common Lisp, this is done by specifying the
:external-format
argument when the stream is created. The major
information required is an encoding, specified by a keyword
naming that encoding; however, it is also possible to specify
refinements to that encoding as additional options to the external
format designator.
In addition, SBCL supports various extensions of ANSI Common Lisp streams:
character
and
(unsigned-byte 8)
values.
format
).
The encodings supported by SBCL as external formats are named by
keyword. Each encoding has a canonical name, which will be encoding
returned by stream-external-format
, and a number of aliases for
convenience, as shown in the table below:
:ASCII
:US-ASCII
, :ANSI_X3.4-1968
, :ISO-646
, :ISO-646-US
, :|646|
:CP1250
:|cp1250|
, :WINDOWS-1250
, :|windows-1250|
:CP1251
:|cp1251|
, :WINDOWS-1251
, :|windows-1251|
:CP1252
:|cp1252|
, :WINDOWS-1252
, :|windows-1252|
:CP1253
:|cp1253|
, :WINDOWS-1253
, :|windows-1253|
:CP1254
:|cp1254|
:CP1255
:|cp1255|
, :WINDOWS-1255
, :|windows-1255|
:CP1256
:|cp1256|
, :WINDOWS-1256
, :|windows-1256|
:CP1257
:|cp1257|
, :WINDOWS-1257
, :|windows-1257|
:CP1258
:|cp1258|
, :WINDOWS-1258
, :|windows-1258|
:CP437
:|cp437|
:CP850
:|cp850|
:CP852
:|cp852|
:CP855
:|cp855|
:CP857
:|cp857|
:CP860
:|cp860|
:CP861
:|cp861|
:CP862
:|cp862|
:CP863
:|cp863|
:CP864
:|cp864|
:CP865
:|cp865|
:CP866
:|cp866|
:CP869
:|cp869|
:CP874
:|cp874|
:EBCDIC-US
:CP037
, :|cp037|
, :IBM-037
, :IBM037
:EUC-JP
:EUCJP
, :|eucJP|
:GBK
:CP936
:ISO-8859-10
:|iso-8859-10|
, :LATIN-6
, :|latin-6|
:ISO-8859-11
:|iso-8859-11|
:ISO-8859-13
:|iso-8859-13|
, :LATIN-7
, :|latin-7|
:ISO-8859-14
:|iso-8859-14|
, :LATIN-8
, :|latin-8|
:ISO-8859-2
:|iso-8859-2|
, :LATIN-2
, :|latin-2|
:ISO-8859-3
:|iso-8859-3|
, :LATIN-3
, :|latin-3|
:ISO-8859-4
:|iso-8859-4|
, :LATIN-4
, :|latin-4|
:ISO-8859-5
:|iso-8859-5|
:ISO-8859-6
:|iso-8859-6|
:ISO-8859-7
:|iso-8859-7|
:ISO-8859-8
:|iso-8859-8|
:ISO-8859-9
:|iso-8859-9|
, :LATIN-5
, :|latin-5|
:KOI8-R
:|koi8-r|
:KOI8-U
:|koi8-u|
:LATIN-1
:LATIN1
, :ISO-8859-1
, :ISO8859-1
:LATIN-9
:LATIN9
, :ISO-8859-15
, :ISO8859-15
:MAC-ROMAN
:|mac-roman|
, :|MacRoman|
, :MAC
, :|mac|
, :MACINTOSH
, :|macintosh|
:SHIFT_JIS
:SJIS
, :|Shift_JIS|
, :CP932
:UCS-2BE
:UCS2BE
:UCS-2LE
:UCS2LE
:UCS-4BE
:UCS4BE
:UCS-4LE
:UCS4LE
:UTF-16BE
:UTF16BE
:UTF-16LE
:UTF16LE
:UTF-32BE
:UTF32BE
:UTF-32LE
:UTF32LE
:UTF-8
:UTF8
:X-MAC-CYRILLIC
:|x-mac-cyrillic|
In situations where an external file format designator is required, such
as the :external-format
argument in calls to open
or
with-open-file
, users may supply the name of an encoding to
denote the external format which is applying that encoding to Lisp
characters.
In addition to the basic encoding for an external format, options
controlling various special cases may be passed, by using a list (whose
first element must be an encoding name and whose rest is a plist) as an
external file format designator. At present, the only supported key in
the plist is :replacement
, where the corresponding value is a
string designator which is used as a replacement when an encoding or
decoding error happens, handling those errors without user intervention;
for example:
(with-open-file (i pathname :external-format '(:utf-8 :replacement #\?)) (read-line i))
will read the first line of pathname, replacing any invalid utf-8 sequences with question marks.
A bivalent stream can be used to read and write both
character
and (unsigned-byte 8)
values. A bivalent
stream is created by calling open
with the argument :element-type
:default
. On such a stream, both binary and character data can be
read and written with the usual input and output functions.
Streams are not created bivalent by default for performance reasons. Bivalent streams are incompatible withfast-read-char
, an internal optimization in SBCL's stream machinery that bulk-converts octets to characters and implements a fast path throughread-char
.
The Gray Streams interface is a widely supported extension that provides for definition of CLOS-extensible stream classes. Gray stream classes are implemented by adding methods to generic functions analogous to Common Lisp's standard I/O functions. Instances of Gray stream classes may be used with any I/O operation where a non-Gray stream can, provided that all required methods have been implemented suitably.
The defined Gray Stream classes are these:
Class precedence list:
fundamental-stream, standard-object, stream, t
Base class for all Gray streams.
Class precedence list:
fundamental-input-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray input streams.
The function input-stream-p will return true of any generalized instance of fundamental-input-stream.
Class precedence list:
fundamental-output-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray output streams.
The function output-stream-p will return true of any generalized instance of fundamental-output-stream.
Class precedence list:
fundamental-binary-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray streams whose element-type is a subtype of unsigned-byte or signed-byte.
Note that instantiable subclasses of fundamental-binary-stream should provide (or inherit) an applicable method for the generic function stream-element-type.
Class precedence list:
fundamental-character-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray streams whose element-type is a subtype of character.
Class precedence list:
fundamental-binary-input-stream, fundamental-input-stream, fundamental-binary-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray input streams whose element-type is a subtype of unsigned-byte or signed-byte.
Class precedence list:
fundamental-binary-output-stream, fundamental-output-stream, fundamental-binary-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray output streams whose element-type is a subtype of unsigned-byte or signed-byte.
Class precedence list:
fundamental-character-input-stream, fundamental-input-stream, fundamental-character-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray input streams whose element-type is a subtype of character.
Class precedence list:
fundamental-character-output-stream, fundamental-output-stream, fundamental-character-stream, fundamental-stream, standard-object, stream, t
Superclass of all Gray output streams whose element-type is a subtype of character.
These generic functions can be specialized on any generalized instance of fundamental-stream.
Return a type specifier for the kind of object returned by the
stream
. The classfundamental-character-stream
provides a default method which returnscharacter
.
Close the given
stream
. No more I/O may be performed, but inquiries may still be made. If:abort
is true, an attempt is made to clean up the side effects of having created the stream.
Used by
file-position
. Returns or changes the current position withinstream
.
These generic functions may be specialized on any generalized instance of fundamental-input-stream.
This is like
cl:clear-input
, but for Gray streams, returningnil
. The default method does nothing.
This is like
cl:read-sequence
, but for Gray streams.
These generic functions are used to implement subclasses of fundamental-input-stream:
This is used to implement
peek-char
; this corresponds topeek-type
ofnil
. It returns either a character or:eof
. The default method callsstream-read-char
andstream-unread-char
.
This is used to implement
read-char-no-hang
. It returns either a character, ornil
if no input is currently available, or:eof
if end-of-file is reached. The default method provided byfundamental-character-input-stream
simply callsstream-read-char
; this is sufficient for file streams, but interactive streams should define their own method.
Read one character from the stream. Return either a character object, or the symbol
:eof
if the stream is at end-of-file. Every subclass offundamental-character-input-stream
must define a method for this function.
This is used by
read-line
. A string is returned as the first value. The second value is true if the string was terminated by end-of-file instead of the end of a line. The default method uses repeated calls tostream-read-char
.
This is used by
listen
. It returns true or false. The default method usesstream-read-char-no-hang
andstream-unread-char
. Most streams should define their own method since it will usually be trivial and will always be more efficient than the default method.
Undo the last call to
stream-read-char
, as inunread-char
. Returnnil
. Every subclass offundamental-character-input-stream
must define a method for this function.
These generic functions are used to implement subclasses of fundamental-output-stream:
This is like
cl:clear-output
, but for Gray streams: clear the given outputstream
. The default method does nothing.
Attempts to ensure that all output sent to the Stream has reached its destination, and only then returns false. Implements
finish-output
. The default method does nothing.
Attempts to force any buffered output to be sent. Implements
force-output
. The default method does nothing.
This is like
cl:write-sequence
, but for Gray streams.
These generic functions are used to implement subclasses of fundamental-character-output-stream:
Write enough blank space so that the next character will be written at the specified column. Returns true if the operation is successful, or
nil
if it is not supported for this stream. This is intended for use by bypprint
andformat
~T. The default method usesstream-line-column
and repeated calls tostream-write-char
with a#space
character; it returnsnil
ifstream-line-column
returnsnil
.
Outputs a new line to the Stream if it is not positioned at the beginning of a line. Returns
t
if it output a new line, nil otherwise. Used byfresh-line
. The default method usesstream-start-line-p
andstream-terpri
.
Return the column number where the next character will be written, or
nil
if that is not meaningful for this stream. The first column on a line is numbered 0. This function is used in the implementation ofpprint
and theformat
~T directive. For every character output stream class that is defined, a method must be defined for this function, although it is permissible for it to always returnnil
.
Is
stream
known to be positioned at the beginning of a line? It is permissible for an implementation to always returnnil
. This is used in the implementation offresh-line
. Note that while a value of 0 fromstream-line-column
also indicates the beginning of a line, there are cases wherestream-start-line-p
can be meaningfully implemented althoughstream-line-column
can't be. For example, for a window using variable-width characters, the column number isn't very meaningful, but the beginning of the line does have a clear meaning. The default method forstream-start-line-p
on classfundamental-character-output-stream
usesstream-line-column
, so if that is defined to returnnil
, then a method should be provided for eitherstream-start-line-p
orstream-fresh-line
.
Writes an end of line, as for
terpri
. Returnsnil
. The default method does (stream-write-char
stream #NEWLINE).
Write
character
tostream
and returncharacter
. Every subclass offundamental-character-output-stream
must have a method defined for this function.
This is used by
write-string
. It writes the string to the stream, optionally delimited by start and end, which default to 0 andnil
. The string argument is returned. The default method provided byfundamental-character-output-stream
uses repeated calls tostream-write-char
.
The following generic functions are available for subclasses of fundamental-binary-stream:
Used by
read-byte
; returns either an integer, or the symbol:eof
if the stream is at end-of-file.
Implements
write-byte
; writes the integer to the stream and returns the integer as the result.
Below are two classes of stream that can be conveniently defined as
wrappers for Common Lisp streams. These are meant to serve as
examples of minimal implementations of the protocols that must be
followed when defining Gray streams. Realistic uses of the Gray
Streams API would implement the various methods that can do I/O in
batches, such as stream-read-line
, stream-write-string
,
stream-read-sequence
, and stream-write-sequence
.
It is occasionally handy for programs that process input files to
count the number of characters and lines seen so far, and the number
of characters seen on the current line, so that useful messages may be
reported in case of parsing errors, etc. Here is a character input
stream class that keeps track of these counts. Note that all
character input streams must implement stream-read-char
and
stream-unread-char
.
(defclass wrapped-stream (fundamental-stream) ((stream :initarg :stream :reader stream-of))) (defmethod stream-element-type ((stream wrapped-stream)) (stream-element-type (stream-of stream))) (defmethod close ((stream wrapped-stream) &key abort) (close (stream-of stream) :abort abort)) (defclass wrapped-character-input-stream (wrapped-stream fundamental-character-input-stream) ()) (defmethod stream-read-char ((stream wrapped-character-input-stream)) (read-char (stream-of stream) nil :eof)) (defmethod stream-unread-char ((stream wrapped-character-input-stream) char) (unread-char char (stream-of stream))) (defclass counting-character-input-stream (wrapped-character-input-stream) ((char-count :initform 1 :accessor char-count-of) (line-count :initform 1 :accessor line-count-of) (col-count :initform 1 :accessor col-count-of) (prev-col-count :initform 1 :accessor prev-col-count-of))) (defmethod stream-read-char ((stream counting-character-input-stream)) (with-accessors ((inner-stream stream-of) (chars char-count-of) (lines line-count-of) (cols col-count-of) (prev prev-col-count-of)) stream (let ((char (call-next-method))) (cond ((eql char :eof) :eof) ((char= char #\Newline) (incf lines) (incf chars) (setf prev cols) (setf cols 1) char) (t (incf chars) (incf cols) char))))) (defmethod stream-unread-char ((stream counting-character-input-stream) char) (with-accessors ((inner-stream stream-of) (chars char-count-of) (lines line-count-of) (cols col-count-of) (prev prev-col-count-of)) stream (cond ((char= char #\Newline) (decf lines) (decf chars) (setf cols prev)) (t (decf chars) (decf cols) char)) (call-next-method)))
The default methods for stream-read-char-no-hang
,
stream-peek-char
, stream-listen
,
stream-clear-input
, stream-read-line
, and
stream-read-sequence
should be sufficient (though the last two
will probably be slower than methods that forwarded directly).
Here's a sample use of this class:
(with-input-from-string (input "1 2 3 :foo ") (let ((counted-stream (make-instance 'counting-character-input-stream :stream input))) (loop for thing = (read counted-stream) while thing unless (numberp thing) do (error "Non-number ~S (line ~D, column ~D)" thing (line-count-of counted-stream) (- (col-count-of counted-stream) (length (format nil "~S" thing)))) end do (print thing))))1 2 3 Non-number :FOO (line 2, column 5) [Condition of type SIMPLE-ERROR]
One use for a wrapped output stream might be to prefix each line of
text with a timestamp, e.g., for a logging stream. Here's a simple
stream that does this, though without any fancy line-wrapping. Note
that all character output stream classes must implement
stream-write-char
and stream-line-column
.
(defclass wrapped-stream (fundamental-stream) ((stream :initarg :stream :reader stream-of))) (defmethod stream-element-type ((stream wrapped-stream)) (stream-element-type (stream-of stream))) (defmethod close ((stream wrapped-stream) &key abort) (close (stream-of stream) :abort abort)) (defclass wrapped-character-output-stream (wrapped-stream fundamental-character-output-stream) ((col-index :initform 0 :accessor col-index-of))) (defmethod stream-line-column ((stream wrapped-character-output-stream)) (col-index-of stream)) (defmethod stream-write-char ((stream wrapped-character-output-stream) char) (with-accessors ((inner-stream stream-of) (cols col-index-of)) stream (write-char char inner-stream) (if (char= char #\Newline) (setf cols 0) (incf cols)))) (defclass prefixed-character-output-stream (wrapped-character-output-stream) ((prefix :initarg :prefix :reader prefix-of))) (defgeneric write-prefix (prefix stream) (:method ((prefix string) stream) (write-string prefix stream)) (:method ((prefix function) stream) (funcall prefix stream))) (defmethod stream-write-char ((stream prefixed-character-output-stream) char) (with-accessors ((inner-stream stream-of) (cols col-index-of) (prefix prefix-of)) stream (when (zerop cols) (write-prefix prefix inner-stream)) (call-next-method)))
As with the example input stream, this implements only the minimal
protocol. A production implementation should also provide methods for
at least stream-write-line
, stream-write-sequence
.
And here's a sample use of this class:
(flet ((format-timestamp (stream) (apply #'format stream "[~2@*~2,' D:~1@*~2,'0D:~0@*~2,'0D] " (multiple-value-list (get-decoded-time))))) (let ((output (make-instance 'prefixed-character-output-stream :stream *standard-output* :prefix #'format-timestamp))) (loop for string in '("abc" "def" "ghi") do (write-line string output) (sleep 1))))[ 0:30:05] abc [ 0:30:06] def [ 0:30:07] ghi NIL
Simple streams are an extensible streams protocol that avoids some problems with Gray streams.
Documentation about simple streams is available at:
http://www.franz.com/support/documentation/6.2/doc/streams.htm
The implementation should be considered Alpha-quality; the basic framework is there, but many classes are just stubs at the moment.
See SYS:CONTRIB;SB-SIMPLE-STREAMS;SIMPLE-STREAM-TEST.LISP for things that should work.
Known differences to the ACL behaviour:
open
not return a simple-stream by default. This can be
adjusted; see default-open-class in the file cl.lisp
write-vector
is unimplemented.
None of the following sections apply to SBCL built without package locking support.
warning: The interface described here is experimental: incompatible changes in future SBCL releases are possible, even expected: the concept of “implementation packages” and the associated operators may be renamed; more operations (such as naming restarts or catch tags) may be added to the list of operations violating package locks.
Package locks protect against unintentional modifications of a package:
they provide similar protection to user packages as is mandated to
common-lisp
package by the ANSI specification. They are not, and
should not be used as, a security measure.
Newly created packages are by default unlocked (see the :lock
option to defpackage
).
The package common-lisp
and SBCL internal implementation
packages are locked by default, including sb-ext
.
It may be beneficial to lock common-lisp-user
as well, to
ensure that various libraries don't pollute it without asking,
but this is not currently done by default.
Each package has a list of associated implementation packages. A
locked package, and the symbols whose home package it is, can be
modified without violating package locks only when *package*
is
bound to one of the implementation packages of the locked package.
Unless explicitly altered by defpackage
,
sb-ext:add-implementation-package
, or
sb-ext:remove-implementation-package
each package is its own
(only) implementation package.
Lexical bindings or declarations that violate package locks cause a
compile-time warning, and a runtime program-error
when the form
that violates package locks would be executed.
A complete listing of operators affect by this is: let
,
let*
, flet
, labels
, macrolet
, and
symbol-macrolet
, declare
.
Package locks affecting both lexical bindings and declarations can be
disabled locally with sb-ext:disable-package-locks
declaration,
and re-enabled with sb-ext:enable-package-locks
declaration.
Example:
(in-package :locked) (defun foo () ...) (defmacro with-foo (&body body) `(locally (declare (disable-package-locks locked:foo)) (flet ((foo () ...)) (declare (enable-package-locks locked:foo)) ; re-enable for body ,@body)))
If an non-lexical operation violates a package lock, a continuable
error that is of a subtype of sb-ext:package-lock-violation
(subtype of package-error
) is signalled when the operation is
attempted.
Additional restarts may be established for continuable package lock violations for interactive use.
The actual type of the error depends on circumstances that caused the
violation: operations on packages signal errors of type
sb-ext:package-locked-error
, and operations on symbols signal
errors of type sb-ext:symbol-package-locked-error
.
If file-compiled code contains interned symbols, then loading that code into an image without the said symbols will not cause a package lock violation, even if the packages in question are locked.
With the exception of interned symbols, behaviour is unspecified if package locks affecting compiled code are not the same during loading of the code or execution.
Specifically, code compiled with packages unlocked may or may not fail to signal package-lock-violations even if the packages are locked at runtime, and code compiled with packages locked may or may not signal spurious package-lock-violations at runtime even if the packages are unlocked.
In practice all this means that package-locks have a negligible performance penalty in compiled code as long as they are not violated.
The following actions cause a package lock violation if the package
operated on is locked, and *package*
is not an implementation
package of that package, and the action would cause a change in the
state of the package (so e.g. exporting already external symbols is
never a violation). Package lock violations caused by these operations
signal errors of type sb-ext:package-locked-error
.
Following actions cause a package lock violation if the home package
of the symbol operated on is locked, and *package*
is not an
implementation package of that package. Package lock violations caused
by these action signal errors of type
sb-ext:symbol-package-locked-error
.
These actions cause only one package lock violation per lexically apparent violated package.
Example:
;;; Packages FOO and BAR are locked. ;;; ;;; Two lexically apparent violated packages: exactly two ;;; package-locked-errors will be signalled. (defclass foo:point () ((x :accessor bar:x) (y :accessor bar:y)))
Exceptions:
Exceptions:
Exceptions:
Exceptions:
sb-ext:define-hash-table-test
.
Syntax:
(sb-ext:disable-package-locks symbol*)
Disables package locks affecting the named symbols during compilation in the lexical scope of the declaration. Disabling locks on symbols whose home package is unlocked, or disabling an already disabled lock, has no effect.
Syntax:
(sb-ext:enable-package-locks symbol*)
Re-enables package locks affecting the named symbols during compilation in the lexical scope of the declaration. Enabling locks that were not first disabled with
sb-ext:disable-package-locks
declaration, or enabling locks that are already enabled has no effect.
Class precedence list:
package-lock-violation, package-error, error, serious-condition, condition, t
Subtype of
cl:package-error
. A subtype of this error is signalled when a package-lock is violated.
Class precedence list:
package-locked-error, package-lock-violation, package-error, error, serious-condition, condition, t
Subtype of
sb-ext:package-lock-violation
. An error of this type is signalled when an operation on a package violates a package lock.
Class precedence list:
symbol-package-locked-error, package-lock-violation, package-error, error, serious-condition, condition, t
Subtype of
sb-ext:package-lock-violation
. An error of this type is signalled when an operation on a symbol violates a package lock. The symbol that caused the violation is accessed by the functionsb-ext:package-locked-error-symbol
.
Returns the symbol that caused the
symbol-package-locked-error
condition.
Returns
t
whenpackage
is locked,nil
otherwise. Signals an error ifpackage
doesn't designate a valid package.
Locks
package
and returnst
. Has no effect ifpackage
was already locked. Signals an error ifpackage
is not a valid package designator
Unlocks
package
and returnst
. Has no effect ifpackage
was already unlocked. Signals an error ifpackage
is not a valid package designator.
Returns a list containing the implementation packages of
package
. Signals an error ifpackage
is not a valid package designator.
Returns the packages that
package
is an implementation package of. Signals an error ifpackage
is not a valid package designator.
Adds
packages-to-add
as implementation packages ofpackage
. Signals an error ifpackage
or any of thepackages-to-add
is not a valid package designator.
Removes
packages-to-remove
from the implementation packages ofpackage
. Signals an error ifpackage
or any of thepackages-to-remove
is not a valid package designator.
Ignores all runtime package lock violations during the execution of body. Body can begin with declarations.
Unlocks
packages
for the dynamic scope of the body. Signals an error if any ofpackages
is not a valid package designator.
Options are extended to include the following:
:lock
booleanIf the argument to
:lock
ist
, the package is initially locked. If:lock
is not provided it defaults tonil
.:implement
package-designator*The package is added as an implementation package to the packages named. If
:implement
is not provided, it defaults to the package itself.Example:
(defpackage "FOO" (:export "BAR") (:lock t) (:implement)) (defpackage "FOO-INT" (:use "FOO") (:implement "FOO" "FOO-INT")) ;;; is equivalent to (defpackage "FOO") (:export "BAR")) (lock-package "FOO") (remove-implementation-package "FOO" "FOO") (defpackage "FOO-INT" (:use "BAR")) (add-implementation-package "FOO-INT" "FOO")
SBCL supports a fairly low-level threading interface that maps onto the host operating system's concept of threads or lightweight processes. This means that threads may take advantage of hardware multiprocessing on machines that have more than one CPU, but it does not allow Lisp control of the scheduler. This is found in the SB-THREAD package.
Threads are part of the default build on x86[-64]/ARM64 Linux and Windows.
They are also supported on: x86[-64] Darwin (Mac OS X), x86[-64] FreeBSD, x86 SunOS (Solaris), PPC Linux, ARM64 Linux. On these platforms threads must be explicitly enabled at build-time, see INSTALL for directions.
(make-thread (lambda () (write-line "Hello, world")))
Class precedence list:
thread, structure-object, t
Thread type. Do not rely on threads being structs as it may change in future versions.
Return a list of the live threads. Note that the return value is potentially stale even before the function returns, as new threads may be created and old ones may exit at any time.
Return
t
ifthread
is still alive. Note that the return value is potentially stale even before the function returns, as the thread may exit at any time.
Name of the thread. Can be assigned to using
setf
. Thread names can be arbitrary printable objects, and need not be unique.
True if
thread
, defaulting to current thread, is the main thread of the process.
Create a new thread of
name
that runsfunction
with the argument list designator provided (defaults to no argument). Thread exits when the function returns. The return values offunction
are kept around and can be retrieved byjoin-thread
.Invoking the initial
abort
restart established bymake-thread
terminates the thread.See also:
return-from-thread
,abort-thread
.
Unwinds from and terminates the current thread, with values from
values-form
as the results visible tojoin-thread
.If current thread is the main thread of the process (see MAIN-THREAD-P), signals an error unless
allow-exit
is true, as terminating the main thread would terminate the entire process. Ifallow-exit
is true, returning from the main thread is equivalent to callingsb-ext:exit
with:code
0 and:abort
nil
.See also:
abort-thread
andsb-ext:exit
.
Unwinds from and terminates the current thread abnormally, causing
join-thread
on current thread to signal an error unless a default-value is provided.If current thread is the main thread of the process (see MAIN-THREAD-P), signals an error unless
allow-exit
is true, as terminating the main thread would terminate the entire process. Ifallow-exit
is true, aborting the main thread is equivalent to callingsb-ext:exit
code 1 and:abort
nil
.Invoking the initial
abort
restart established bymake-thread
is equivalent to callingabort-thread
in other than main threads. However, whereasabort
restart may be rebound,abort-thread
always unwinds the entire thread. (Behaviour of the initialabort
restart for main thread depends on the:toplevel
argument tosb-ext:save-lisp-and-die
.)See also:
return-from-thread
andsb-ext:exit
.
Suspend current thread until
thread
exits. Return the result values of the thread function.If
thread
does not exit withintimeout
seconds anddefault
is supplied, return two values: 1)default
2):timeout
. Ifdefault
is not supplied, signal ajoin-thread-error
withjoin-thread-problem
equal to:timeout
.If
thread
does not exit normally (i.e. aborted) anddefault
is supplied, return two values: 1)default
2):abort
. Ifdefault
is not supplied, signal ajoin-thread-error
withjoin-thread-problem
equal to:abort
.If
thread
is the current thread, signal ajoin-thread-error
withjoin-thread-problem
equal to:self-join
.Trying to join the main thread causes
join-thread
to block untiltimeout
occurs or the process exits: when the main thread exits, the entire process exits.
note:
Return convention in case of a timeout is experimental and subject to change.
Interrupt
thread
and make it runfunction
.The interrupt is asynchronous, and can occur anywhere with the exception of sections protected using
sb-sys:without-interrupts
.
function
is called with interrupts disabled, undersb-sys:allow-with-interrupts
. Since functions such asgrab-mutex
may try to enable interrupts internally, in most casesfunction
should either entersb-sys:with-interrupts
to allow nested interrupts, orsb-sys:without-interrupts
to prevent them completely.When a thread receives multiple interrupts, they are executed in the order they were sent
--
first in, first out.This means that a great degree of care is required to use
interrupt-thread
safely and sanely in a production environment. The general recommendation is to limit uses ofinterrupt-thread
for interactive debugging, banning it entirely from production environments--
it is simply exceedingly hard to use correctly.With those caveats in mind, what you need to know when using it:
Take together, these two restrict the "safe" things to do using
- If calling
function
causes a non-local transfer of control (ie. an unwind), all normal cleanup forms will be executed.However, if the interrupt occurs during cleanup forms of an
unwind-protect
, it is just as if that had happened due to a regulargo
,throw
, orreturn-from:
the interrupted cleanup form and those following it in the sameunwind-protect
do not get executed.
sbcl
tries to keep its own internals asynch-unwind-safe, but this is frankly an unreasonable expectation for third party libraries, especially given that asynch-unwind-safety does not compose: a function calling only asynch-unwind-safe function isn't automatically asynch-unwind-safe.This means that in order for an asynch unwind to be safe, the entire callstack at the point of interruption needs to be asynch-unwind-safe.
- In addition to asynch-unwind-safety you must consider the issue of reentrancy.
interrupt-thread
can cause function that are never normally called recursively to be re-entered during their dynamic contour, which may cause them to misbehave. (Consider binding of special variables, values of global variables, etc.)interrupt-thread
to a fairly minimal set. One useful one--
exclusively for interactive development use is using it to force entry to debugger to inspect the state of a thread:(interrupt-thread thread #'break)Short version: be careful out there.
Terminate the thread identified by
thread
, by interrupting it and causing it to callsb-ext:abort-thread
with:allow-exit
t
.The unwind caused by
terminate-thread
is asynchronous, meaning that eg. thread executing(let (foo) (unwind-protect (progn (setf foo (get-foo)) (work-on-foo foo)) (when foo ;; An interrupt occurring inside the cleanup clause ;; will cause cleanups from the current UNWIND-PROTECT ;; to be dropped. (release-foo foo))))might miss calling
release-foo
despiteget-foo
having returned true if the interrupt occurs inside the cleanup clause, eg. during execution ofrelease-foo
.Thus, in order to write an asynch unwind safe
unwind-protect
you need to usewithout-interrupts:
(let (foo) (sb-sys:without-interrupts (unwind-protect (progn (setf foo (sb-sys:allow-with-interrupts (get-foo))) (sb-sys:with-local-interrupts (work-on-foo foo))) (when foo (release-foo foo)))))Since most libraries using
unwind-protect
do not do this, you should never assume that unknown code can safely be terminated usingterminate-thread
.
Return the local value of
symbol
inthread
, and a secondary value oft
on success.If the value cannot be retrieved (because the thread has exited or because it has no local binding for NAME) and
errorp
is true signals an error of typesymbol-value-in-thread-error
; iferrorp
is false returns a primary value ofnil
, and a secondary value ofnil
.Can also be used with
setf
to change the thread-local value ofsymbol
.
symbol-value-in-thread
is primarily intended as a debugging tool, and not as a mechanism for inter-thread communication.
Class precedence list:
thread-error, error, serious-condition, condition, t
Conditions of type
thread-error
are signalled when thread operations fail. The offending thread is initialized by the:thread
initialization argument and read by the functionthread-error-thread
.
Return the offending thread that the
thread-error
pertains to.
Class precedence list:
interrupt-thread-error, thread-error, error, serious-condition, condition, t
Signalled when interrupting a thread fails because the thread has already exited. The offending thread can be accessed using
thread-error-thread
.
Class precedence list:
join-thread-error, thread-error, error, serious-condition, condition, t
Signalled when joining a thread fails due to abnormal exit of the thread to be joined. The offending thread can be accessed using
thread-error-thread
.
The interaction of special variables with multiple threads is mostly as one would expect, with behaviour very similar to other implementations.
The last point means that
(defparameter *x* 0) (let ((*x* 1)) (sb-thread:make-thread (lambda () (print *x*))))
prints 0
and not 1
as of 0.9.6.
Following atomic operations are particularly useful for implementing lockless algorithms.
Atomically decrements
place
bydiff
, and returns the value ofplace
before the decrement.
place
must access one of the following:Macroexpansion is performed on
- a
defstruct
slot with declared type(unsigned-byte 64)
oraref
of a(simple-array (unsigned-byte 64) (*))
The typesb-ext:word
can be used for these purposes.car
orcdr
(respectivelyfirst
or REST) of acons
.- a variable defined using
defglobal
with a proclaimed type offixnum
.place
before expandingatomic-decf
.Decrementing is done using modular arithmetic, which is well-defined over two different domains:
- For structures and arrays, the operation accepts and produces an
(unsigned-byte 64)
, anddiff
must be of type(signed-byte 64)
.atomic-decf
of #x0 by one results in #xFFFFFFFFFFFFFFFF being stored inplace
.- For other places, the domain is
fixnum
, anddiff
must be afixnum
.atomic-decf
of #x-4000000000000000 by one results in #x3FFFFFFFFFFFFFFF being stored inplace
.diff
defaults to 1.
experimental:
Interface subject to change.
Atomically increments
place
bydiff
, and returns the value ofplace
before the increment.
place
must access one of the following:Macroexpansion is performed on
- a
defstruct
slot with declared type(unsigned-byte 64)
oraref
of a(simple-array (unsigned-byte 64) (*))
The typesb-ext:word
can be used for these purposes.car
orcdr
(respectivelyfirst
or REST) of acons
.- a variable defined using
defglobal
with a proclaimed type offixnum
.place
before expandingatomic-incf
.Incrementing is done using modular arithmetic, which is well-defined over two different domains:
- For structures and arrays, the operation accepts and produces an
(unsigned-byte 64)
, anddiff
must be of type(signed-byte 64)
.atomic-incf
of #xFFFFFFFFFFFFFFFF by one results in #x0 being stored inplace
.- For other places, the domain is
fixnum
, anddiff
must be afixnum
.atomic-incf
of #x3FFFFFFFFFFFFFFF by one results in #x-4000000000000000 being stored inplace
.diff
defaults to 1.
experimental:
Interface subject to change.
Like
pop
, but atomic.place
may be read multiple times before the operation completes--
the write does not occur until such time that no other thread modifiedplace
between the read and the write.Works on all CASable places.
Like
push
, but atomic.place
may be read multiple times before the operation completes--
the write does not occur until such time that no other thread modifiedplace
between the read and the write.Works on all CASable places.
Updates
place
atomically to the value returned by calling function designated byupdate-fn
witharguments
and the previous value ofplace
.
place
may be read andupdate-fn
evaluated and called multiple times before the update succeeds: atomicity in this context means that the value ofplace
did not change between the time it was read, and the time it was replaced with the computed value.
place
can be any place supported bysb-ext:compare-and-swap
.Examples:
;;; Conses T to the head of FOO-LIST. (defstruct foo list) (defvar *foo* (make-foo)) (atomic-update (foo-list *foo*) #'cons t) (let ((x (cons :count 0))) (mapc #'sb-thread:join-thread (loop repeat 1000 collect (sb-thread:make-thread (lambda () (loop repeat 1000 do (atomic-update (cdr x) #'1+) (sleep 0.00001)))))) ;; Guaranteed to be (:COUNT . 1000000) -- if you replace ;; atomic update with (INCF (CDR X)) above, the result becomes ;; unpredictable. x)
Atomically stores
new
inplace
ifold
matches the current value ofplace
. Two values are considered to match if they areeq
. Returns the previous value ofplace:
if the returned value iseq
toold
, the swap was carried out.
place
must be an CAS-able place. Built-in CAS-able places are accessor forms whosecar
is one of the following:
car
,cdr
,first
,rest
,svref
,symbol-plist
,symbol-value
,svref
,slot-value
sb-mop:standard-instance-access
,sb-mop:funcallable-standard-instance-access
,or the name of a
defstruct
created accessor for a slot whose declared type is eitherfixnum
ort
. Results are unspecified if the slot has a declared type other thanfixnum
ort
.In case of
slot-value
, if the slot is unbound,slot-unbound
is called unlessold
iseq
tosb-pcl:+slot-unbound+
in which casesb-pcl:+slot-unbound+
is returned andnew
is assigned to the slot. Additionally, the results are unspecified if there is an applicable method on eithersb-mop:slot-value-using-class
,(setf sb-mop:slot-value-using-class)
, orsb-mop:slot-boundp-using-class
.Additionally, the
place
can be a anything for which a CAS-expansion has been specified usingdefcas
,define-cas-expander
, or for which a CAS-function has been defined. (Seesb-ext:cas
for more information.)
Our compare-and-swap
is user-extensible using a protocol
similar to setf
, allowing users to add CAS support to new
places via e.g. defcas
.
At the same time, new atomic operations can be built on top of CAS
using get-cas-expansion
. See atomic-update
,
atomic-push
, and atomic-pop
for examples of how to do
this.
Synonym for
compare-and-swap
.Additionally
defun
,defgeneric
,defmethod
,flet
, andlabels
can be also used to define CAS-functions analogously to SETF-functions:(defvar *foo* nil) (defun (cas foo) (old new) (cas (symbol-value '*foo*) old new))First argument of a
cas
function is the expected old value, and the second argument of is the new value. Note that the system provides no automatic atomicity forcas
functions, nor can it verify that they are atomic: it is up to the implementor of acas
function to ensure its atomicity.
experimental:
Interface subject to change.
Analogous to
define-setf-expander
. Defines a CAS-expansion foraccessor
.body
must return six values as specified inget-cas-expansion
.Note that the system provides no automatic atomicity for
cas
expansion, nor can it verify that they are atomic: it is up to the implementor of acas
expansion to ensure its atomicity.
experimental:
Interface subject to change.
Analogous to short-form
defsetf
. Definesfunction
as responsible for compare-and-swap on places accessed usingaccessor
.lambda-list
must correspond to the lambda-list of the accessor.Note that the system provides no automatic atomicity for
cas
expansions resulting fromdefcas
, nor can it verify that they are atomic: it is up to the user ofdefcas
to ensure that the function specified is atomic.
experimental:
Interface subject to change.
Analogous to
get-setf-expansion
. Returns the following six values:Example:
- list of temporary variables
- list of value-forms whose results those variable must be bound
- temporary variable for the old value of
place
- temporary variable for the new value of
place
- form using the aforementioned temporaries which performs the compare-and-swap operation on
place
- form using the aforementioned temporaries with which to perform a volatile read of
place
(get-cas-expansion '(car x)) ; => (#:CONS871), (X), #:OLD872, #:NEW873, ; (SB-KERNEL:%COMPARE-AND-SWAP-CAR #:CONS871 #:OLD872 :NEW873). ; (CAR #:CONS871) (defmacro my-atomic-incf (place &optional (delta 1) &environment env) (multiple-value-bind (vars vals old new cas-form read-form) (get-cas-expansion place env) (let ((delta-value (gensym "DELTA"))) `(let* (,@(mapcar 'list vars vals) (,old ,read-form) (,delta-value ,delta) (,new (+ ,old ,delta-value))) (loop until (eq ,old (setf ,old ,cas-form)) do (setf ,new (+ ,old ,delta-value))) ,new))))
experimental:
Interface subject to change.
Mutexes are used for controlling access to a shared resource. One thread is allowed to hold the mutex, others which attempt to take it will be made to wait until it's free. Threads are woken in the order that they go to sleep.
(defpackage :demo (:use "CL" "SB-THREAD" "SB-EXT")) (in-package :demo) (defvar *a-mutex* (make-mutex :name "my lock")) (defun thread-fn () (format t "Thread ~A running ~%" *current-thread*) (with-mutex (*a-mutex*) (format t "Thread ~A got the lock~%" *current-thread*) (sleep (random 5))) (format t "Thread ~A dropped lock, dying now~%" *current-thread*)) (make-thread #'thread-fn) (make-thread #'thread-fn)
Acquire
mutex
for the dynamic scope ofbody
. Ifwait-p
is true (the default), and themutex
is not immediately available, sleep until it is available.If
timeout
is given, it specifies a relative timeout, in seconds, on how long the system should try to acquire the lock in the contested case.If the mutex isn't acquired successfully due to either
wait-p
ortimeout
, the body is not executed, andwith-mutex
returnsnil
.Otherwise body is executed with the mutex held by current thread, and
with-mutex
returns the values ofbody
.Historically
with-mutex
also accepted avalue
argument, which when provided was used as the new owner of the mutex instead of the current thread. This is no longer supported: ifvalue
is provided, it must be eithernil
or the current thread.
Acquire
mutex
for the dynamic scope ofbody
.If
wait-p
is true (the default), and themutex
is not immediately available or held by the current thread, sleep until it is available.If
timeout
is given, it specifies a relative timeout, in seconds, on how long the system should try to acquire the lock in the contested case.If the mutex isn't acquired successfully due to either
wait-p
ortimeout
, the body is not executed, andwith-recursive-lock
returnsnil
.Otherwise body is executed with the mutex held by current thread, and
with-recursive-lock
returns the values ofbody
.Unlike
with-mutex
, which signals an error on attempt to re-acquire an already held mutex,with-recursive-lock
allows recursive lock attempts to succeed.
Current owner of the mutex,
nil
if the mutex is free. Naturally, this is racy by design (another thread may acquire the mutex after this function returns), it is intended for informative purposes. For testing whether the current thread is holding a mutex seeholding-mutex-p
.
Current owner of the mutex,
nil
if the mutex is free. May return a stale value, usemutex-owner
instead.
Acquire
mutex
for the current thread. Ifwaitp
is true (the default) and the mutex is not immediately available, sleep until it is available.If
timeout
is given, it specifies a relative timeout, in seconds, on how longgrab-mutex
should try to acquire the lock in the contested case.If
grab-mutex
returnst
, the lock acquisition was successful. In case ofwaitp
beingnil
, or an expiredtimeout
,grab-mutex
may also returnnil
which denotes thatgrab-mutex
did -not- acquire the lock.Notes:
grab-mutex
is not interrupt safe. The correct way to call it is:(WITHOUT-INTERRUPTS ... (
allow-with-interrupts
(grab-mutex
...)) ...)
without-interrupts
is necessary to avoid an interrupt unwinding the call while the mutex is in an inconsistent state whileallow-with-interrupts
allows the call to be interrupted from sleep.(grab-mutex <mutex> :timeout 0.0)
differs from(grab-mutex <mutex> :waitp nil)
in that the former may signal adeadline-timeout
if the global deadline was due already on enteringgrab-mutex
.The exact interplay of
grab-mutex
and deadlines are reserved to change in future versions.- It is recommended that you use
with-mutex
instead of callinggrab-mutex
directly.
Release
mutex
by setting it tonil
. Wake up threads waiting for this mutex.
release-mutex
is not interrupt safe: interrupts should be disabled around calls to it.If the current thread is not the owner of the mutex then it silently returns without doing anything (if
if-not-owner
is :PUNT), signals awarning
(ifif-not-owner
is :WARN), or releases the mutex anyway (ifif-not-owner
is :FORCE).
Semaphores are among other things useful for keeping track of a countable resource, e.g. messages in a queue, and sleep when the resource is exhausted.
Class precedence list:
semaphore, structure-object, t
Semaphore type. The fact that a
semaphore
is astructure-object
should be considered an implementation detail, and may change in the future.
Create a semaphore with the supplied
count
andname
.
Increment the count of
semaphore
byn
. If there are threads waiting on this semaphore, thenn
of them is woken up.
Decrement the count of
semaphore
byn
if the count would not be negative.Else blocks until the semaphore can be decremented. Returns the new count of
semaphore
on success.If
timeout
is given, it is the maximum number of seconds to wait. If the count cannot be decremented in that time, returnsnil
without decrementing the count.If
notification
is given, it must be asemaphore-notification
object whosesemaphore-notification-status
isnil
. Ifwait-on-semaphore
succeeds and decrements the count, the status is set tot
.
Try to decrement the count of
semaphore
byn
. If the count were to become negative, punt and returnnil
, otherwise return the new count ofsemaphore
.If
notification
is given it must be a semaphore notification object withsemaphore-notification-status
ofnil
. If the count is decremented, the status is set tot
.
Returns the current count of the semaphore
instance
.
Class precedence list:
semaphore-notification, structure-object, t
Semaphore notification object. Can be passed to
wait-on-semaphore
andtry-semaphore
as the:notification
argument. Consequences are undefined if multiple threads are using the same notification object in parallel.
Constructor for
semaphore-notification
objects.semaphore-notification-status
is initiallynil
.
Returns
t
if await-on-semaphore
ortry-semaphore
usingsemaphore-notification
has succeeded since the notification object was created or cleared.
Resets the
semaphore-notification
object for use with another call towait-on-semaphore
ortry-semaphore
.
These are based on the POSIX condition variable design, hence the annoyingly CL-conflicting name. For use when you want to check a condition and sleep until it's true. For example: you have a shared queue, a writer process checking “queue is empty” and one or more readers that need to know when “queue is not empty”. It sounds simple, but is astonishingly easy to deadlock if another process runs when you weren't expecting it to.
There are three components:
Important stuff to be aware of:
(defvar *buffer-queue* (make-waitqueue)) (defvar *buffer-lock* (make-mutex :name "buffer lock")) (defvar *buffer* (list nil)) (defun reader () (with-mutex (*buffer-lock*) (loop (condition-wait *buffer-queue* *buffer-lock*) (loop (unless *buffer* (return)) (let ((head (car *buffer*))) (setf *buffer* (cdr *buffer*)) (format t "reader ~A woke, read ~A~%" *current-thread* head)))))) (defun writer () (loop (sleep (random 5)) (with-mutex (*buffer-lock*) (let ((el (intern (string (code-char (+ (char-code #\A) (random 26))))))) (setf *buffer* (cons el *buffer*))) (condition-notify *buffer-queue*)))) (make-thread #'writer) (make-thread #'reader) (make-thread #'reader)
Class precedence list:
waitqueue, structure-object, t
Waitqueue type.
Atomically release
mutex
and start waiting onqueue
for till another thread wakes us up using eithercondition-notify
orcondition-broadcast
on that queue, at which point we re-acquiremutex
and returnt
.Spurious wakeups are possible.
If
timeout
is given, it is the maximum number of seconds to wait, including both waiting for the wakeup and the time to re-acquiremutex
. Unless both wakeup and re-acquisition do not occur within the given time, returnsnil
without re-acquiring the mutex.If
condition-wait
unwinds, it may do so with or without the mutex being held.Important: Since
condition-wait
may return withoutcondition-notify
having occurred the correct way to write code that usescondition-wait
is to loop around the call, checking the the associated data:(defvar *data* nil) (defvar *queue* (make-waitqueue)) (defvar *lock* (make-mutex)) ;; Consumer (defun pop-data (&optional timeout) (with-mutex (*lock*) (loop until *data* do (or (condition-wait *queue* *lock* :timeout timeout) ;; Lock not held, must unwind without touching *data*. (return-from pop-data nil))) (pop *data*))) ;; Producer (defun push-data (data) (with-mutex (*lock*) (push data *data*) (condition-notify *queue*)))
Notify
n
threads waiting onqueue
.
important:
The same mutex that is used in the correspondingcondition-wait
must be held by this thread during this call.
Notify all threads waiting on
queue
.
important:
The same mutex that is used in the correspondingcondition-wait
must be held by this thread during this call.
These are based on the Linux kernel barrier design, which is in turn based on the Alpha CPU memory model. They are presently implemented for x86, x86-64, PPC, and ARM64 systems, and behave as compiler barriers on all other CPUs.
In addition to explicit use of the sb-thread:barrier
macro, the
following functions and macros also serve as :memory
barriers:
sb-ext:atomic-decf
, sb-ext:atomic-incf
, sb-ext:atomic-push
,
and sb-ext:atomic-pop
.
sb-ext:compare-and-swap
.
sb-thread:grab-mutex
, sb-thread:release-mutex
,
sb-thread:with-mutex
and sb-thread:with-recursive-lock
.
sb-thread:signal-semaphore
, sb-thread:try-semaphore
and
sb-thread:wait-on-semaphore
.
sb-thread:condition-wait
, sb-thread:condition-notify
and
sb-thread:condition-broadcast
.
Insert a barrier in the code stream, preventing some sort of reordering.
kind
should be one of:
:compiler
- Prevent the compiler from reordering memory access across the barrier.
:memory
- Prevent the cpu from reordering any memory access across the barrier.
:read
- Prevent the cpu from reordering any read access across the barrier.
:write
- Prevent the cpu from reordering any write access across the barrier.
:data-dependency
- Prevent the cpu from reordering dependent memory reads across the barrier (requiring reads before the barrier to complete before any reads after the barrier that depend on them). This is a weaker form of the
:read
barrier.
forms
is an implicitprogn
, evaluated before the barrier.barrier
returns the values of the last form informs
.The file "memory-barriers.txt" in the Linux kernel documentation is highly recommended reading for anyone programming at this level.
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
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
.
Direct calls to pthread_create
(instead of MAKE-THREAD
)
create threads that SBCL is not aware of, these are called foreign
threads. Currently, it is not possible to run Lisp code in such
threads. This means that the Lisp side signal handlers cannot work.
The best solution is to start foreign threads with signals blocked,
but since third party libraries may create threads, it is not always
feasible to do so. As a workaround, upon receiving a signal in a
foreign thread, SBCL changes the thread's sigmask to block all signals
that it wants to handle and resends the signal to the current process
which should land in a thread that does not block it, that is, a Lisp
thread.
The resignalling trick cannot work for synchronously triggered signals
(SIGSEGV and co), take care not to trigger any. Resignalling for
synchronously triggered signals in foreign threads is subject to
--lose-on-corruption
, see Runtime Options.
Threading is implemented using pthreads and some Linux specific bits like futexes.
On x86 the 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. On x86-64 the r12 register has a similar role.
Queues require the sys_futex()
system call to be available:
this is the reason for the NPTL requirement. We test at runtime that
this system call exists.
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.
SBCL supports a system-wide event scheduler implemented on top of
setitimer
that also works with threads but does not require a
separate scheduler thread.
The following example schedules a timer that writes “Hello, word” after two seconds.
(schedule-timer (make-timer (lambda () (write-line "Hello, world") (force-output))) 2)
It should be noted that writing timer functions requires special care, as the dynamic environment in which they run is unpredictable: dynamic variable bindings, locks held, etc, all depend on whatever code was running when the timer fired. The following example should serve as a cautionary tale:
(defvar *foo* nil) (defun show-foo () (format t "~&foo=~S~%" *foo*) (force-output t)) (defun demo () (schedule-timer (make-timer #'show-foo) 0.5) (schedule-timer (make-timer #'show-foo) 1.5) (let ((*foo* t)) (sleep 1.0)) (let ((*foo* :surprise!)) (sleep 2.0)))
Class precedence list:
timer, structure-object, t
Timer type. Do not rely on timers being structs as it may change in future versions.
Create a timer that runs
function
when triggered.If a
thread
is supplied,function
is run in that thread. Ifthread
ist
, a new thread is created forfunction
each time the timer is triggered. Ifthread
isnil
,function
is run in an unspecified thread.When
thread
is nott
,interrupt-thread
is used to runfunction
and the ordering guarantees ofinterrupt-thread
apply. In that case,function
runs with interrupts disabled butwith-interrupts
is allowed.
See if
timer
will still need to be triggered afterdelta
seconds from now. For timers with a repeat interval it returns true.
Schedule
timer
to be triggered attime
. Ifabsolute-p
thentime
is universal time, but non-integral values are also allowed, elsetime
is measured as the number of seconds from the current time.If
repeat-interval
is given,timer
is automatically rescheduled upon expiry.If
repeat-interval
is non-NIL, the Booleancatch-up
controls whethertimer
will "catch up" by repeatedly calling its function without delay in case calls are missed because of a clock discontinuity such as a suspend and resume cycle of the computer. The default isnil
, i.e. do not catch up.
Cancel
timer
. Once this function returns it is guaranteed thattimer
shall not be triggered again and there are no unfinished triggers.
The sb-bsd-sockets
module provides a thinly disguised BSD
socket API for SBCL. Ideas have been stolen from the BSD socket API
for C and Graham Barr's IO::Socket classes for Perl.
Sockets are represented as CLOS objects, and the API naming conventions attempt to balance between the BSD names and good lisp style.
Most of the functions are modelled on the BSD socket API. BSD sockets are widely supported, portably (“portable” by Unix standards, at least) available on a variety of systems, and documented. There are some differences in approach where we have taken advantage of some of the more useful features of Common Lisp - briefly:
errno
,
sb-bsd-sockets
signals an error. All the errors are subclasses
of sb-bsd-sockets:socket-condition
and generally correspond one
for one with possible errno
values.
Class precedence list:
socket, standard-object, t
Slots:
protocol
— initarg::protocol
; reader:sb-bsd-sockets:socket-protocol
Protocol used by the socket. If a keyword, the symbol-name of the keyword will be passed to
get-protocol-by-name
downcased, and the returned value used as protocol. Other values are used as-is.type
— initarg::type
; reader:sb-bsd-sockets:socket-type
Type of the socket:
:stream
or:datagram
.Common superclass of all sockets, not meant to be directly instantiated.
Bind
socket
toaddress
, which may vary according to socket family. For theinet
family, passaddress
andport
as two arguments; forfile
address family sockets, pass the filename string. See also bind(2)
Perform the accept(2) call, returning a newly-created connected socket and the peer address as multiple values
Perform the connect(2) call to connect
socket
to a remotepeer
. No useful return value.
Return SOCKET's peer; depending on the address family this may return multiple values
Return the address (as vector of bytes) and port that
socket
is bound to, as multiple values.
Read
length
octets fromsocket
intobuffer
(or a freshly-consed buffer if NIL), using recvfrom(2). Iflength
isnil
, the length ofbuffer
is used, so at least one of these two arguments must be non-NIL. Ifbuffer
is supplied, it had better be of an element type one octet wide. Returns the buffer, its length, and the address of the peer that sent it, as multiple values. On datagram sockets, sets MSG_TRUNC so that the actual packet length is returned even if the buffer was too small.
Send
length
octets frombuffer
intosocket
, using sendto(2). Ifbuffer
is a string, it will converted to octets according toexternal-format
. Iflength
isnil
, the length of the octet buffer is used. The format ofaddress
depends on the socket type (for example forinet
domain sockets it would be a list of anip
address and a port). If no socket address is provided, send(2) will be called instead. Returns the number of octets written.
Mark
socket
as willing to accept incoming connections. The integerbacklog
defines the maximum length that the queue of pending connections may grow to before new connection attempts are refused. See also listen(2)
Return true if
socket
is open; otherwise, return false.
Close
socket
, unless it was already closed.If
socket-make-stream
has been called, callsclose
usingabort
on that stream. Otherwise closes the socket file descriptor using close(2).
Indicate that no communication in
direction
will be performed onsocket
.
direction
has to be one of:input
,:output
or:io
.After a shutdown, no input and/or output of the indicated
direction
can be performed onsocket
.
Find or create a
stream
that can be used forio
onsocket
(which must be connected). Specify whether the stream is forinput
,output
, or both (it is an error to specify neither).
element-type
andexternal-format
are as peropen
.
timeout
specifies a read timeout for the stream.
Default method for
socket
objects.
element-type
defaults tocharacter
, to construct a bivalent stream, capable of both binary and characterio
use:default
.Acceptable values for
buffering
are:full
,:line
and:none
, default is:full
, ie. output is buffered till it is explicitly flushed usingclose
orfinish-output
. (force-output
forces some output to be flushed: to ensure all buffered output is flused usefinish-output
.)Streams have no
timeout
by default. If one is provided, it is the number of seconds the system will at most wait for input to appear on the socket stream when trying to read from it.If
auto-close
is true, the underlyingos
socket is automatically closed after the stream and the socket have been garbage collected. Default is false.If
serve-events
is true, blockingio
on the socket will dispatch to the recursive event loop. Default is false.The stream for
socket
will be cached, and a second invocation of this method will return the same stream. This may lead to oddities if this function is invoked with inconsistent arguments (e.g., one might request an input stream and get an output stream in response).
A subset of socket options are supported, using a fairly general
framework which should make it simple to add more as required - see
SYS:CONTRIB;SB-BSD-SOCKETS:SOCKOPT.LISP for details. The name
mapping from C is fairly straightforward: SO_RCVLOWAT
becomes
sockopt-receive-low-water
and (setf
sockopt-receive-low-water)
.
Return the value of the
so-reuseaddr
socket option forsocket
. This can also be updated withsetf
.
Return the value of the
so-keepalive
socket option forsocket
. This can also be updated withsetf
.
Return the value of the
so-oobinline
socket option forsocket
. This can also be updated withsetf
.
Return the value of the
so-bsdcompat
socket option forsocket
. This can also be updated withsetf
. Available only on Linux.
Return the value of the
so-passcred
socket option forsocket
. This can also be updated withsetf
. Available only on Linux.
Return the value of the
so-debug
socket option forsocket
. This can also be updated withsetf
.
Return the value of the
so-dontroute
socket option forsocket
. This can also be updated withsetf
.
Return the value of the
so-broadcast
socket option forsocket
. This can also be updated withsetf
.
Return the value of the
tcp-nodelay
socket option forsocket
. This can also be updated withsetf
.
The TCP and UDP sockets that you know and love. Some representation issues:
(unsigned-byte 8)
- viz. #(127 0 0 1)
. Ports are just
integers: 6010. No conversion between network- and host-order data is
needed from the user of this package.
(unsigned-byte 8)
- viz. #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1)
. Ports are just integers. As for IPv4 addresses, no conversion
between network- and host-order data is needed from the user of this
package.
(socket-connect socket #(192 168 1 1) 80)
for
IPv4 and (socket-connect socket #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1)
80)
for IPv6.
Class precedence list:
inet-socket, socket, standard-object, t
Class representing
tcp
andudp
over IPv4 sockets.Examples:
(make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp) (make-instance 'sb-bsd-sockets:inet-socket :type :datagram :protocol :udp)
Class precedence list:
inet6-socket, socket, standard-object, t
Class representing
tcp
andudp
over IPv6 sockets.Examples:
(make-instance 'sb-bsd-sockets:inet6-socket :type :stream :protocol :tcp) (make-instance 'sb-bsd-sockets:inet6-socket :type :datagram :protocol :udp)
Return a vector of octets given a string
dotted-quads
in the format "127.0.0.1". Signals an error if the string is malformed.
Return a vector of octets given a string representation of an IPv6 address
colon-separated-integers
. Signal an error if the string is malformed.
Given a protocol name, return the protocol number, the protocol name, and a list of protocol aliases
Local domain (AF_LOCAL
) sockets are also known as Unix-domain
sockets, but were renamed by POSIX presumably on the basis that they
may be available on other systems too.
A local socket address is a string, which is used to create a node in the local filesystem. This means of course that they cannot be used across a network.
Class precedence list:
local-socket, socket, standard-object, t
Class representing local domain (AF_LOCAL) sockets, also known as unix-domain sockets.
Presently name service is implemented by calling out to the
getaddrinfo(3)
and gethostinfo(3)
, or to
gethostbyname(3)
gethostbyaddr(3)
on platforms where
the preferred functions are not available. The exact details of
the name resolving process (for example the choice of whether
DNS or a hosts file is used for lookup) are platform dependent.
Class precedence list:
host-ent, standard-object, t
Slots:
name
— initarg::name
; reader:sb-bsd-sockets:host-ent-name
The name of the host
addresses
— initarg::addresses
; reader:sb-bsd-sockets:host-ent-addresses
A list of addresses for this host.
This class represents the results of an address lookup.
Returns a
host-ent
instance fornode
or signals aname-service-error
.Another
host-ent
instance containing zero, one or more IPv6 addresses may be returned as a second return value.
node
may also be anip
address in dotted quad notation or some other weird stuff-
see getaddrinfo(3) for the details.
Returns a
host-ent
instance foraddress
, which should be a vector of (integer 0 255) with 4 elements in case of an IPv4 address and 16 elements in case of an IPv6 address, or signals aname-service-error
. See gethostbyaddr(3) for details.
Return some valid address for
host-ent
.
SBCL includes both a deterministic profiler, that can collect statistics on individual functions, and a more “modern” statistical profiler.
Inlined functions do not appear in the results reported by either.
The package sb-profile
provides a classic, per-function-call
profiler.
note: When profiling code executed by multiple threads in parallel, the consing attributed to each function is inaccurate.
profile
Name*If no names are supplied, return the list of profiled functions.
If names are supplied, wrap profiling code around the named functions. As in
trace
, the names are not evaluated. A symbol names a function. A string names all the functions named by symbols in the named package. If a function is already profiled, then unprofile and reprofile (useful to notice function redefinition.) If a name is undefined, then we give a warning and ignore it. See alsounprofile
,report
andreset
.
Unwrap any profiling code around the named functions, or if no names are given, unprofile all profiled functions. A symbol names a function. A string names all the functions named by symbols in the named package.
names
defaults to the list of names of all currently profiled functions.
Report results from profiling. The results are approximately adjusted for profiling overhead. The compensation may be rather inaccurate when bignums are involved in runtime calculation, as in a very-long-running Lisp process.
If
limit
is set to an integer, only the toplimit
results are reported. Ifprint-no-call-list
ist
(the default) then a list of uncalled profiled functions are listed.
The sb-sprof
module, loadable by
(require :sb-sprof)
provides an alternate profiler which works by taking samples of the
program execution at regular intervals, instead of instrumenting
functions like sb-profile:profile
does. You might find
sb-sprof
more useful than the deterministic profiler when profiling
functions in the common-lisp
-package, SBCL internals, or code
where the instrumenting overhead is excessive.
Additionally sb-sprof
includes a limited deterministic profiler
which can be used for reporting the amounts of calls to some functions
during
(in-package :cl-user) (require :sb-sprof) (declaim (optimize speed)) (defun cpu-test-inner (a i) (logxor a (* i 5) (+ a i))) (defun cpu-test (n) (let ((a 0)) (dotimes (i (expt 2 n) a) (setf a (cpu-test-inner a i))))) ;;;; CPU profiling ;;; Take up to 1000 samples of running (CPU-TEST 26), and give a flat ;;; table report at the end. Profiling will end one the body has been ;;; evaluated once, whether or not 1000 samples have been taken. (sb-sprof:with-profiling (:max-samples 1000 :report :flat :loop nil) (cpu-test 26)) ;;; Record call counts for functions defined on symbols in the CL-USER ;;; package. (sb-sprof:profile-call-counts "CL-USER") ;;; Take 1000 samples of running (CPU-TEST 24), and give a flat ;;; table report at the end. The body will be re-evaluated in a loop ;;; until 1000 samples have been taken. A sample count will be printed ;;; after each iteration. (sb-sprof:with-profiling (:max-samples 1000 :report :flat :loop t :show-progress t) (cpu-test 24)) ;;;; Allocation profiling (defun foo (&rest args) (mapcar (lambda (x) (float x 1d0)) args)) (defun bar (n) (declare (fixnum n)) (apply #'foo (loop repeat n collect n))) (sb-sprof:with-profiling (:max-samples 10000 :mode :alloc :report :flat) (bar 1000))
The flat report format will show a table of all functions that the profiler encountered on the call stack during sampling, ordered by the number of samples taken while executing that function.
Self Total Cumul Nr Count % Count % Count % Calls Function ------------------------------------------------------------------------ 1 69 24.4 97 34.3 69 24.4 67108864 CPU-TEST-INNER 2 64 22.6 64 22.6 133 47.0 - SB-VM::GENERIC-+ 3 39 13.8 256 90.5 172 60.8 1 CPU-TEST 4 31 11.0 31 11.0 203 71.7 - SB-KERNEL:TWO-ARG-XOR
For each function, the table will show three absolute and relative sample counts. The Self column shows samples taken while directly executing that function. The Total column shows samples taken while executing that function or functions called from it (sampled to a platform-specific depth). The Cumul column shows the sum of all Self columns up to and including that line in the table.
Additionally the Calls column will record the amount of calls that were
made to the function during the profiling run. This value will only
be reported for functions that have been explicitly marked for call counting
with profile-call-counts
.
The profiler also hooks into the disassembler such that instructions which have been sampled are annotated with their relative frequency of sampling. This information is not stored across different sampling runs.
; 6CF: 702E JO L4 ; 6/242 samples ; 6D1: D1E3 SHL EBX, 1 ; 6D3: 702A JO L4 ; 6D5: L2: F6C303 TEST BL, 3 ; 2/242 samples ; 6D8: 756D JNE L8 ; 6DA: 8BC3 MOV EAX, EBX ; 5/242 samples ; 6DC: L3: 83F900 CMP ECX, 0 ; 4/242 samples
This module is known not to work consistently on the Alpha platform, for technical reasons related to the implementation of a machine language idiom for marking sections of code to be treated as atomic by the garbage collector; However, it should work on other platforms, and the deficiency on the Alpha will eventually be rectified.
Allocation profiling is only supported on SBCL builds that use the generational garbage collector. Tracking of call stacks at a depth of more than two levels is only supported on x86 and x86-64.
Evaluate
body
with statistical profiling turned on. Ifloop
is true, loop around thebody
until a sufficient number of samples has been collected. Returns the values from the last evaluation ofbody
.In multithreaded operation, only the thread in which
with-profiling
was evaluated will be profiled by default. If you want to profile multiple threads, invoke the profiler withstart-profiling
.The following keyword args are recognized:
:sample-interval
<n>- Take a sample every <n> seconds. Default is
*sample-interval*
.:alloc-interval
<n>- Take a sample every time <n> allocation regions (approximately 8kB) have been allocated since the last sample. Default is
*alloc-interval*
.:mode
<mode>- If
:cpu
, run the profiler incpu
profiling mode. If:alloc
, run the profiler in allocation profiling mode. If:time
, run the profiler in wallclock profiling mode.:max-samples
<max>- Repeat evaluating body until <max> samples are taken. Default is
*max-samples*
.:max-depth
<max>- Maximum call stack depth that the profiler should consider. Only has an effect on x86 and x86-64.
:report
<type>- If specified, call
report
with:type
<type> at the end.:reset
<bool>- It true, call
reset
at the beginning.:threads
<list-form>- Form that evaluates to the list threads to profile, or
:all
to indicate that all threads should be profiled. Defaults to the current thread. (Note:start-profiling
defaults to all threads.)
:threads
has no effect on call-counting at the moment.On some platforms (eg. Darwin) the signals used by the profiler are not properly delivered to threads in proportion to their
cpu
usage when doing:cpu
profiling. If you see empty call graphs, or are obviously missing several samples from certain threads, you may be falling afoul of this. In this case using:mode
:time
is likely to work better.:loop
<bool>- If false (the default), evaluate
body
only once. If true repeatedly evaluatebody
.
Evaluate body with statistical sampling turned on or off.
Report statistical profiling results. The following keyword args are recognized:
:type
<type>- Specifies the type of report to generate. If
:flat
, show flat report, if:graph
show a call graph and a flat report. If nil, don't print out a report.:stream
<stream>- Specify a stream to print the report on. Default is
*standard-output*
.:max
<max>- Don't show more than <max> entries in the flat report.
:min-percent
<min-percent>- Don't show functions taking less than <min-percent> of the total time in the flat report.
:sort-by
<column>- If
:samples
, sort flat report by number of samples taken. If:cumulative-samples
, sort flat report by cumulative number of samples taken (shows how much time each function spent on stack.) Default is*report-sort-by*
.:sort-order
<order>- If
:descending
, sort flat report in descending order. If:ascending
, sort flat report in ascending order. Default is*report-sort-order*
.:show-progress
<bool>- If true, print progress messages while generating the call graph.
:call-graph
<graph>- Print a report from <graph> instead of the latest profiling results.
Value of this function is a
call-graph
object representing the resulting call-graph, ornil
if there are no samples (eg. right after callingreset
.)Profiling is stopped before the call graph is generated.
Start profiling statistically in the current thread if not already profiling. The following keyword args are recognized:
:sample-interval
<n>- Take a sample every <n> seconds. Default is
*sample-interval*
.:alloc-interval
<n>- Take a sample every time <n> allocation regions (approximately 8kB) have been allocated since the last sample. Default is
*alloc-interval*
.:mode
<mode>- If
:cpu
, run the profiler incpu
profiling mode. If:alloc
, run the profiler in allocation profiling mode. If:time
, run the profiler in wallclock profiling mode.:max-samples
<max>- Maximum number of samples. Default is
*max-samples*
.:max-depth
<max>- Maximum call stack depth that the profiler should consider. Only has an effect on x86 and x86-64.
:threads
<list>- List threads to profile, or
:all
to indicate that all threads should be profiled. Defaults to:all
. (Note:with-profiling
defaults to the current thread.)
:threads
has no effect on call-counting at the moment.On some platforms (eg. Darwin) the signals used by the profiler are not properly delivered to threads in proportion to their
cpu
usage when doing:cpu
profiling. If you see empty call graphs, or are obviously missing several samples from certain threads, you may be falling afoul of this.:sampling
<bool>- If true, the default, start sampling right away. If false,
start-sampling
can be used to turn sampling on.
Mark the functions named by
names
as being subject to call counting during statistical profiling. If a string is used as a name, it will be interpreted as a package name. In this case call counting will be done for all functions with names likex
or(setf x)
, wherex
is a symbol with the package as its home package.
Clear all call counting information. Call counting will be done for no functions during statistical profiling.
Default number of traces taken. This variable is somewhat misnamed: each trace may actually consist of an arbitrary number of samples, depending on the depth of the call stack.
sb-sprof
is an SBCL port, with enhancements, of Gerd
Moellmann's statistical profiler for CMUCL.
SBCL comes with a number of modules that are not part of the core
system. These are loaded via (require :
modulename)
(see Customization Hooks for Users). This section contains
documentation (or pointers to documentation) for some of the
contributed modules.
The sb-aclrepl
module offers an Allegro CL-style
Read-Eval-Print Loop for SBCL, with integrated inspector. Adding a
debugger interface is planned.
To start sb-aclrepl
as your read-eval-print loop, put the form
(require 'sb-aclrepl)
in your ~/.sbclrc initialization file.
Here's a longer example of a ~/.sbclrc file that shows off
some of the features of sb-aclrepl
:
(ignore-errors (require 'sb-aclrepl)) (when (find-package 'sb-aclrepl) (push :aclrepl cl:*features*)) #+aclrepl (progn (setq sb-aclrepl:*max-history* 100) (setf (sb-aclrepl:alias "asdc") #'(lambda (sys) (asdf:operate 'asdf:compile-op sys))) (sb-aclrepl:alias "l" (sys) (asdf:operate 'asdf:load-op sys)) (sb-aclrepl:alias "t" (sys) (asdf:operate 'asdf:test-op sys)) ;; The 1 below means that two characaters ("up") are required (sb-aclrepl:alias ("up" 1 "Use package") (package) (use-package package)) ;; The 0 below means only the first letter ("r") is required, ;; such as ":r base64" (sb-aclrepl:alias ("require" 0 "Require module") (sys) (require sys)) (setq cl:*features* (delete :aclrepl cl:*features*)))
Questions, comments, or bug reports should be sent to Kevin Rosenberg (kevin@rosenberg.net).
Allegro CL is a registered trademark of Franz Inc.
Additional data structures, synchronization primitives and tools for
concurrent programming. Similiar to Java's java.util.concurrent
package.
sb-concurrency:queue
is a lock-free, thread-safe FIFO queue
datatype.
The implementation is based on An Optimistic Approach to
Lock-Free FIFO Queues by Edya Ladan-Mozes and Nir Shavit.
Before SBCL 1.0.38, this implementation resided in its own contrib
(see sb-queue) which is still provided for backwards-compatibility
but which has since been deprecated.
Class precedence list:
queue, structure-object, t
Lock-free thread safe
fifo
queue.Use
enqueue
to add objects to the queue, anddequeue
to remove them.
Retrieves the oldest value in
queue
and returns it as the primary value, andt
as secondary value. If the queue is empty, returnsnil
as both primary and secondary value.
Returns the contents of
queue
as a list without removing them from thequeue
. Mainly useful for manual examination of queue state, as the list may be out of date by the time it is returned, and concurrent dequeue operations may in the worse case force the queue-traversal to be restarted several times.
Returns a new
queue
withname
and contents of theinitial-contents
sequence enqueued.
Returns the number of objects in
queue
. Mainly useful for manual examination of queue state, and inprint-object
methods: inefficient as it must walk the entire queue.
Name of a
queue
. Can be assigned to usingsetf
. Queue names can be arbitrary printable objects, and need not be unique.
sb-concurrency:mailbox
is a lock-free message queue where one
or multiple ends can send messages to one or multiple receivers. The
difference to queues is that the receiving
end may block until a message arrives.
Built on top of the queue implementation.
Class precedence list:
mailbox, structure-object, t
Mailbox aka message queue.
send-message
adds a message to the mailbox,receive-message
waits till a message becomes available, whereasreceive-message-no-hang
is a non-blocking variant, andreceive-pending-messages
empties the entire mailbox in one go.Messages can be arbitrary objects
Returns a fresh list containing all the messages in the mailbox. Does not remove messages from the mailbox.
Returns the number of messages currently in the mailbox.
Returns true if
mailbox
is currently empty,nil
otherwise.
Returns a new
mailbox
with messages ininitial-contents
enqueued.
Removes the oldest message from
mailbox
and returns it as the primary value, and a secondary value oft
. Ifmailbox
is empty waits until a message arrives.If
timeout
is provided, and no message arrives within the specified interval, returns primary and secondary value ofnil
.
The non-blocking variant of
receive-message
. Returns two values, the message removed frommailbox
, and a flag specifying whether a message could be received.
Removes and returns all (or at most N) currently pending messages from
mailbox
, or returnsnil
if no messages are pending.Note: Concurrent threads may be snarfing messages during the run of this function, so even though
x
,y
appear right next to each other in the result, does not necessarily mean thaty
was the message sent right afterx
.
Adds a
message
tomailbox
. Message can be any object.
sb-concurrency:gate
is a synchronization object suitable for when
multiple threads must wait for a single event before proceeding.
Class precedence list:
gate, structure-object, t
gate
type. Gates are synchronization constructs suitable for making multiple threads wait for single event before proceeding.Use
wait-on-gate
to wait for a gate to open,open-gate
to open one, andclose-gate
to close an open gate.gate-open-p
can be used to test the state of a gate without blocking.
Closes
gate
. Returnst
if the gate was previously open, andnil
if the gate was already closed.
Makes a new gate. Gate will be initially open if
open
is true, and closed ifopen
isnil
(the default.)name
, if provided, is the name of the gate, used when printing the gate.
Opens
gate
. Returnst
if the gate was previously closed, andnil
if the gate was already open.
Waits for
gate
to open, ortimeout
seconds to pass. Returnst
if the gate was opened in time, andnil
otherwise.
Class precedence list:
frlock, structure-object, t
FRlock, aka Fast Read Lock.
Fast Read Locks allow multiple readers and one potential writer to operate in parallel while providing for consistency for readers and mutual exclusion for writers.
Readers gain entry to protected regions without waiting, but need to retry if a writer operated inside the region while they were reading. This makes frlocks very efficient when readers are much more common than writers.
FRlocks are
not
suitable when it is not safe at all for readers and writers to operate on the same data in parallel: they provide consistency, not exclusion between readers and writers. Hence using an frlock to eg. protect ansbcl
hash-table is unsafe. If multiple readers operating in parallel with a writer would be safe but inconsistent without a lock, frlocks are suitable.The recommended interface to use is
frlock-read
andfrlock-write
, but those needing it can also use a lower-level interface.Example:
;; Values returned by FOO are always consistent so that ;; the third value is the sum of the two first ones. (let ((a 0) (b 0) (c 0) (lk (make-frlock))) (defun foo () (frlock-read (lk) a b c)) (defun bar (x y) (frlock-write (lk) (setf a x b y c (+ x y)))))
Evaluates
value-forms
underfrlock
till it obtains a consistent set, and returns that as multiple values.
Executes
body
while holdingfrlock
for writing.
Start a read sequence on
frlock
. Returns a read-token and an epoch to be validated later.Using
frlock-read
instead is recommended.
Ends a read sequence on
frlock
. Returns a token and an epoch. If the token and epoch areeql
to the read-token and epoch returned byfrlock-read-begin
, the values read under thefrlock
are consistent and can be used: if the values differ, the values are inconsistent and the read must be restated.Using
frlock-read
instead is recommended.Example:
(multiple-value-bind (t0 e0) (frlock-read-begin *fr*) (let ((a (get-a)) (b (get-b))) (multiple-value-bind (t1 e1) (frlock-read-end *fr*) (if (and (eql t0 t1) (eql e0 e1)) (list :a a :b b) :aborted))))
Acquires
frlock
for writing, invalidating existing and future read-tokens for the duration. Returnst
on success, andnil
if the lock wasn't acquired due to eg. a timeout. Usingfrlock-write
instead is recommended.
Releases
frlock
after writing, allowing valid read-tokens to be acquired again. Signals an error if the current thread doesn't holdfrlock
for writing. Usingfrlock-write
instead is recommended.
The sb-cover
module provides a code coverage tool for SBCL. The
tool has support for expression coverage, and for some branch coverage.
Coverage reports are only generated for code compiled using
compile-file
with the value of the
sb-cover:store-coverage-data
optimization quality set to 3.
As of SBCL 1.0.6 sb-cover
is still experimental, and the
interfaces documented here might change in later versions.
;;; Load SB-COVER (require :sb-cover) ;;; Turn on generation of code coverage instrumentation in the compiler (declaim (optimize sb-cover:store-coverage-data)) ;;; Load some code, ensuring that it's recompiled with the new optimization ;;; policy. (asdf:oos 'asdf:load-op :cl-ppcre-test :force t) ;;; Run the test suite. (cl-ppcre-test:test) ;;; Produce a coverage report (sb-cover:report "/tmp/report/") ;;; Turn off instrumentation (declaim (optimize (sb-cover:store-coverage-data 0)))
Print a code coverage report of all instrumented files into
directory
. Ifdirectory
does not exist, it will be created. The main report will be printed to the file cover-index.html. The external format of the source files can be specified with theexternal-format
parameter.If the keyword argument
form-mode
has the value:car
, the annotations in the coverage report will be placed on the CARs of any cons-forms, while if it has the value:whole
the whole form will be annotated (the default). The former mode shows explicitly which forms were instrumented, while the latter mode is generally easier to read.
Clear all files from the coverage database. The files will be re-entered into the database when the
fasl
files (produced by compilingstore-coverage-data
optimization policy set to 3) are loaded again into the image.
Returns an opaque representation of the current code coverage state. The only operation that may be done on the state is passing it to
restore-coverage
. The representation is guaranteed to be readably printable. A representation that has been printed and read back will work identically inrestore-coverage
.
Call
save-coverage
and write the results of that operation into the file designated bypathname
.
Restore the code coverage data back to an earlier state produced by
save-coverage
.
read
the contents of the file designated bypathname
and pass the result torestore-coverage
.
The sb-grovel
module helps in generation of foreign function
interfaces. It aids in extracting constants' values from the C
compiler and in generating SB-ALIEN structure and union types,
see Defining Foreign Types.
The ASDF(http://www.cliki.net/ASDF) component type GROVEL-CONSTANTS-FILE has its PERFORM operation defined to write out a C source file, compile it, and run it. The output from this program is Lisp, which is then itself compiled and loaded.
sb-grovel is used in a few contributed modules, and it is currently compatible only to SBCL. However, if you want to use it, here are a few directions.
(eval-when (:compile-toplevel :load-toplevel :execute) (require :sb-grovel)) (defpackage :example-package.system (:use :cl :asdf :sb-grovel :sb-alien)) (in-package :example-package.system) (defsystem example-system :depends-on (sb-grovel) :components ((:module "sbcl" :components ((:file "defpackage") (grovel-constants-file "example-constants" :package :example-package)))))
Make sure to specify the package you chose in step 1
The grovel-constants-file, typically named constants.lisp
,
comprises lisp expressions describing the foreign things that you want
to grovel for. A constants.lisp
file contains two sections:
("sys/types.h" "sys/socket.h" "sys/stat.h" "unistd.h" "sys/un.h" "netinet/in.h" "netinet/in_systm.h" "netinet/ip.h" "net/if.h" "netdb.h" "errno.h" "netinet/tcp.h" "fcntl.h" "signal.h" )
((:integer af-local #+(or sunos solaris) "AF_UNIX" #-(or sunos solaris) "AF_LOCAL" "Local to host (pipes and file-domain).") (:structure stat ("struct stat" (integer dev "dev_t" "st_dev") (integer atime "time_t" "st_atime"))) (:function getpid ("getpid" int )))
There are two types of things that sb-grovel can sensibly extract from
the C compiler: constant integers and structure layouts. It is also
possible to define foreign functions in the constants.lisp file, but
these definitions don't use any information from the C program; they
expand directly to sb-alien:define-alien-routine
(see The define-alien-routine Macro) forms.
Here's how to use the grovel clauses:
:integer
- constant expressions in C. Used in this form:
(:integer lisp-variable-name "C expression" &optional doc export)
"C expression"
will be typically be the name of a constant. But
other forms are possible.
:enum
(:enum lisp-type-name ((lisp-enumerated-name c-enumerated-name) ...)))
An sb-alien:enum
type with name lisp-type-name
will be defined.
The symbols are the lisp-enumerated-name
s, and the values
are grovelled from the c-enumerated-name
s.
:structure
- alien structure definitions look like this:
(:structure lisp-struct-name ("struct c_structure" (type-designator lisp-element-name "c_element_type" "c_element_name" :distrust-length nil) ; ... ))
type-designator
is a reference to a type whose size (and type
constraints) will be groveled for. sb-grovel accepts a form of type
designator that doesn't quite conform to either lisp nor sb-alien's
type specifiers. Here's a list of type designators that sb-grovel
currently accepts:
integer
- a C integral type; sb-grovel will infer the exact
type from size information extracted from the C program. All common C
integer types can be grovelled for with this type designator, but it
is not possible to grovel for bit fields yet.
(unsigned n)
- an unsigned integer variable that is n
bytes long. No size information from the C program will be used.
(signed n)
- an signed integer variable that is n
bytes
long. No size information from the C program will be used.
c-string
- an array of char
in the structure. sb-grovel
will use the array's length from the C program, unless you pass it the
:distrust-length
keyword argument with non-nil
value
(this might be required for structures such as solaris's struct
dirent
).
c-string-pointer
- a pointer to a C string, corresponding to
the sb-alien:c-string
type (see Foreign Type Specifiers).
(array alien-type)
- An array of the previously-declared alien
type. The array's size will be determined from the output of the C
program and the alien type's size.
(array alien-type n)
- An array of the previously-declared alien
type. The array's size will be assumed as being n
.
Note that c-string
and c-string-pointer
do not have the
same meaning. If you declare that an element is of type
c-string
, it will be treated as if the string is a part of the
structure, whereas if you declare that the element is of type
c-string-pointer
, a pointer to a string will be the
structure member.
:function
- alien function definitions are similar to
define-alien-routine
definitions, because they expand to such
forms when the lisp program is loaded. See Foreign Function Calls.
(:function lisp-function-name ("alien_function_name" alien-return-type (argument alien-type) (argument2 alien-type)))
Let us assume that you have a grovelled structure definition:
(:structure mystruct ("struct my_structure" (integer myint "int" "st_int") (c-string mystring "char[]" "st_str")))
What can you do with it? Here's a short interface document:
(allocate-mystruct)
- allocates an object of type mystruct
and
returns a system area pointer to it.
(free-mystruct var)
- frees the alien object pointed to by
var.
(with-mystruct var ((member init) [...]) &body body)
-
allocates an object of type mystruct
that is valid in
body. If body terminates or control unwinds out of
body, the object pointed to by var will be deallocated.
(mystruct-myint var)
and (mystruct-mystring var)
return
the value of the respective fields in mystruct
.
(setf (mystruct-myint var) new-val)
and
(setf (mystruct-mystring var) new-val)
sets the value of the respective
structure member to the value of new-val. Notice that in
(setf (mystruct-mystring var) new-val)
's case, new-val is a lisp
string.
Basically, you can treat functions and data structure definitions that sb-grovel spits out as if they were alien routines and types. This has a few implications that might not be immediately obvious (especially if you have programmed in a previous version of sb-grovel that didn't use alien types):
with-mystruct
macro, be sure that no references
to the variable thus allocated leaks out. It will be deallocated when
the block exits.
The sb-md5
module implements the RFC1321 MD5 Message Digest
Algorithm. [FIXME cite]
Calculate the MD5 message-digest of the file designated by pathname.
Calculate the MD5 message-digest of data bounded by
start
andend
insequence
, which must be a vector with element-type (UNSIGNED-BYTE 8).
Calculate an MD5 message-digest of the contents of
stream
, whose element-type has to be(unsigned-byte 8)
.
Calculate the MD5 message-digest of the binary representation of
string
(as octets) inexternal-format
. The boundariesstart
andend
refer to character positions in the string, not to octets in the resulting binary representation.
The implementation for CMUCL was largely done by Pierre Mai, with help
from members of the cmucl-help
mailing list. Since CMUCL and
SBCL are similar in many respects, it was not too difficult to extend
the low-level implementation optimizations for CMUCL to SBCL.
Following this, SBCL's compiler was extended to implement efficient
compilation of modular arithmetic (see Modular arithmetic), which
enabled the implementation to be expressed in portable arithmetical
terms, apart from the use of rotate-byte
for bitwise rotation.
Sb-posix is the supported interface for calling out to the operating system.10
The scope of this interface is “operating system calls on a typical
Unixlike platform”. This is section 2 of the Unix manual, plus section
3 calls that are (a) typically found in libc, but (b) not part of the C
standard. For example, we intend to provide support for
opendir()
and readdir()
, but not for printf()
.
That said, if your favourite system call is not included yet, you are
encouraged to submit a patch to the SBCL mailing list.
Some facilities are omitted where they offer absolutely no additional use over some portable function, or would be actively dangerous to the consistency of Lisp. Not all functions are available on all platforms.
All symbols are in the SB-POSIX
package. This package contains a
Lisp function for each supported Unix system call or function, a
variable or constant for each supported Unix constant, an object type
for each supported Unix structure type, and a slot name for each
supported Unix structure member. A symbol name is derived from the C
binding's name, by (a) uppercasing, then (b) removing leading
underscores (#\_
) then replacing remaining underscore characters
with the hyphen (#\-
). The requirement to uppercase is so that in
a standard upcasing reader the user may write sb-posix:creat
instead of sb-posix:|creat|
as would otherise be required.
No other changes to “Lispify” symbol names are made, so creat()
becomes CREAT
, not CREATE
.
The user is encouraged not to (USE-PACKAGE :SB-POSIX)
but instead
to use the SB-POSIX:
prefix on all references, as some of the
symbols symbols contained in the SB-POSIX package have the same name as
CL symbols (OPEN
, CLOSE
, SIGNAL
etc).
Generally, marshalling between Lisp and C data types is done using SBCL's FFI. See Foreign Function Interface.
Some functions accept objects such as filenames or file descriptors. In
the C binding to POSIX these are represented as strings and small
integers respectively. For the Lisp programmer's convenience we
introduce designators such that CL pathnames or open streams can be
passed to these functions. For example, rename
accepts both
pathnames and strings as its arguments.
A
fixnum
designating a native file descriptor.
sb-sys:make-fd-stream
can be used to construct afile-stream
associated with a native file descriptor.Note that mixing I/O operations on a
file-stream
with operations directly on its descriptor may produce unexpected results if the stream is buffered.
Designator for a
file-descriptor:
either a fixnum designating itself, or afile-stream
designating the underlying file-descriptor.
Converts
file-descriptor-designator
into afile-descriptor
.
A
string
designating a filename in native namestring syntax.Note that native namestring syntax is distinct from Lisp namestring syntax:
(pathname "/foo*/bar")is a wild pathname with a pattern-matching directory component.
sb-ext:parse-native-namestring
may be used to construct Lisp pathnames that denoteposix
filenames as understood by system calls, andsb-ext:native-namestring
can be used to coerce them into strings in the native namestring syntax.Note also that
posix
filename syntax does not distinguish the names of files from the names of directories: in order to parse the name of a directory inposix
filename syntax into a pathnamemy-defaults
for which(merge-pathnames (make-pathname :name "FOO" :case :common) my-defaults)returns a pathname that denotes a file in the directory, supply a true
:as-directory
argument tosb-ext:parse-native-namestring
. Likewise, to supply the name of a directory to aposix
function in non-directory syntax, supply a true:as-file
argument tosb-ext:native-namestring
.
Designator for a
filename:
astring
designating itself, or a designator for apathname
designating the corresponding native namestring.
The calling convention is modelled after that of CMUCL's UNIX
package: in particular, it's like the C interface except that:
read
would be defined this way:
(read fd buffer &optional (length (length buffer))) => bytes-read
pipe()
or socketpair()
) these may be optional or omitted
in the Lisp interface: if not provided, appropriate objects will be
allocated and returned (using multiple return values if necessary).
The return value is usually the same as for the C binding, except in
error cases: where the C function is defined as returning some sentinel
value and setting errno
on error, we instead signal an error of
type SYSCALL-ERROR
. The actual error value (errno
) is
stored in this condition and can be accessed with SYSCALL-ERRNO
.
We do not automatically translate the returned value into “Lispy”
objects – for example, SB-POSIX:OPEN
returns a small integer,
not a stream. Exception: boolean-returning functions (or, more
commonly, macros) do not return a C integer, but instead a Lisp
boolean.
Sb-posix provides various Lisp object types to stand in for C structures in the POSIX library. Lisp bindings to C functions that accept, manipulate, or return C structures accept, manipulate, or return instances of these Lisp types instead of instances of alien types.
The names of the Lisp types are chosen according to the general rules
described above. For example Lisp objects of type STAT
stand
in for C structures of type struct stat
.
Accessors are provided for each standard field in the structure. These
are named structure-name-
field-name where the two
components are chosen according to the general name conversion rules,
with the exception that in cases where all fields in a given structure
have a common prefix, that prefix is omitted. For example,
stat.st_dev
in C becomes STAT-DEV
in Lisp.
Because sb-posix might not support all semi-standard or implementation-dependent members of all structure types on your system (patches welcome), here is an enumeration of all supported Lisp objects corresponding to supported POSIX structures, and the supported slots for those structures.
Class precedence list:
flock, standard-object, t
Slots:
type
— initarg::type
; reader:sb-posix:flock-type
; writer:(setf sb-posix:flock-type)
Type of lock; F_RDLCK, F_WRLCK, F_UNLCK.
whence
— initarg::whence
; reader:sb-posix:flock-whence
; writer:(setf sb-posix:flock-whence)
Flag for starting offset.
start
— initarg::start
; reader:sb-posix:flock-start
; writer:(setf sb-posix:flock-start)
Relative offset in bytes.
len
— initarg::len
; reader:sb-posix:flock-len
; writer:(setf sb-posix:flock-len)
Size; if 0 then until
eof
.pid
— reader:sb-posix:flock-pid
Process
id
of the process holding the lock; returned with F_GETLK.Class representing locks used in fcntl(2).
Class precedence list:
passwd, standard-object, t
Slots:
name
— initarg::name
; reader:sb-posix:passwd-name
; writer:(setf sb-posix:passwd-name)
User's login name.
passwd
— initarg::passwd
; reader:sb-posix:passwd-passwd
; writer:(setf sb-posix:passwd-passwd)
The account's encrypted password.
uid
— initarg::uid
; reader:sb-posix:passwd-uid
; writer:(setf sb-posix:passwd-uid)
Numerical user
id
.gid
— initarg::gid
; reader:sb-posix:passwd-gid
; writer:(setf sb-posix:passwd-gid)
Numerical group
id
.gecos
— initarg::gecos
; reader:sb-posix:passwd-gecos
; writer:(setf sb-posix:passwd-gecos)
User's name or comment field.
dir
— initarg::dir
; reader:sb-posix:passwd-dir
; writer:(setf sb-posix:passwd-dir)
Initial working directory.
shell
— initarg::shell
; reader:sb-posix:passwd-shell
; writer:(setf sb-posix:passwd-shell)
Program to use as shell.
Instances of this class represent entries in the system's user database.
Class precedence list:
stat, standard-object, t
Slots:
mode
— initarg::mode
; reader:sb-posix:stat-mode
Mode of file.
ino
— initarg::ino
; reader:sb-posix:stat-ino
File serial number.
dev
— initarg::dev
; reader:sb-posix:stat-dev
Device
id
of device containing file.nlink
— initarg::nlink
; reader:sb-posix:stat-nlink
Number of hard links to the file.
uid
— initarg::uid
; reader:sb-posix:stat-uid
User
id
of file.gid
— initarg::gid
; reader:sb-posix:stat-gid
Group
id
of file.size
— initarg::size
; reader:sb-posix:stat-size
For regular files, the file size in bytes. For symbolic links, the length in bytes of the filename contained in the symbolic link.
rdev
— initarg::rdev
; reader:sb-posix:stat-rdev
For devices the device number.
atime
— initarg::atime
; reader:sb-posix:stat-atime
Time of last access.
mtime
— initarg::mtime
; reader:sb-posix:stat-mtime
Time of last data modification.
ctime
— initarg::ctime
; reader:sb-posix:stat-ctime
Time of last status change.
Instances of this class represent
posix
file metadata.
Class precedence list:
termios, standard-object, t
Slots:
iflag
— initarg::iflag
; reader:sb-posix:termios-iflag
; writer:(setf sb-posix:termios-iflag)
Input modes.
oflag
— initarg::oflag
; reader:sb-posix:termios-oflag
; writer:(setf sb-posix:termios-oflag)
Output modes.
cflag
— initarg::cflag
; reader:sb-posix:termios-cflag
; writer:(setf sb-posix:termios-cflag)
Control modes.
lflag
— initarg::lflag
; reader:sb-posix:termios-lflag
; writer:(setf sb-posix:termios-lflag)
Local modes.
cc
— initarg::cc
; reader:sb-posix:termios-cc
; writer:(setf sb-posix:termios-cc)
Control characters.
Instances of this class represent I/O characteristics of the terminal.
Class precedence list:
timeval, standard-object, t
Slots:
sec
— initarg::tv-sec
; reader:sb-posix:timeval-sec
; writer:(setf sb-posix:timeval-sec)
Seconds.
usec
— initarg::tv-usec
; reader:sb-posix:timeval-usec
; writer:(setf sb-posix:timeval-usec)
Microseconds.
Instances of this class represent time values.
A few functions in sb-posix don't correspond directly to their C counterparts.
Since SBCL 1.0.38, the sb-queue
module has been merged into the
sb-concurrency
module (see sb-concurrency.)
The sb-rotate-byte
module offers an interface to bitwise
rotation, with an efficient implementation for operations which can be
performed directly using the platform's arithmetic routines. It
implements the specification at
http://www.cliki.net/ROTATE-BYTE.
Bitwise rotation is a component of various cryptographic or hashing algorithms: MD5, SHA-1, etc.; often these algorithms are specified on 32-bit rings. [FIXME cite cite cite].
Rotates a field of bits within
integer
; specifically, returns an integer that contains the bits ofinteger
rotatedcount
times leftwards within the byte specified bybytespec
, and elsewhere contains the bits ofinteger
.
In order to support evolution of interfaces in SBCL as well as in user code, SBCL allows declaring functions, variables and types as deprecated. Users of deprecated things are notified by means of warnings while the deprecated thing in question is still available.
This chapter documents the interfaces for being notified when using deprecated thing and declaring things as deprecated, the deprecation process used for SBCL interfaces, and lists legacy interfaces in various stages of deprecation.
Deprecation in this context should not be confused with those things the ANSI Common Lisp standard calls deprecated: the entirety of ANSI CL is supported by SBCL, and none of those interfaces are subject to censure.
While generally speaking we try to keep SBCL changes as backwards compatible as feasible, there are situations when existing interfaces are deprecated:
Sometimes it turns out that an interface is sufficiently misdesigned that fixing it would be worse than deprecating it and replacing it with another.
This is typically the case when fixing the interface would change its semantics in ways that could break user code subtly: in such cases we may end up considering the obvious breakage caused by deprecation to be preferable.
Another example are functions or macros whose current signature makes them hard or impossible to extend in the future: backwards compatible extensions would either make the interface intolerably hairy, or are sometimes outright impossible.
SBCL has several internal interfaces that were never meant to be used in user code – or at least never meant to be used in user code unwilling to track changes to SBCL internals.
Ideally we'd like to be free to refactor our own internals as we please, without even going through the hassle of deprecating things. Sometimes, however, it turns out that our internal interfaces have several external users who aren't using them advisedly, but due to misunderstandings regarding their status or stability.
Consider a deprecated internal interface a reminder for SBCL maintainers not to delete the thing just yet, even though it is seems unused – because it has external users.
When internal interfaces are deprecated we try our best to provide supported alternatives.
Sometimes an interface isn't broken or internal, but just inconsistent somehow.
This mostly happens only with historical interfaces inherited from CMUCL which often haven't been officially supported in SBCL before, or with new extensions to SBCL that haven't been around for very long in the first place.
The alternative would be to keep the suboptimal version around forever, possibly alongside an improved version. Sometimes we may do just that, but because every line of code comes with a maintenance cost, sometimes we opt to deprecate the suboptimal version instead: SBCL doesn't have infinite developer resources.
We also believe that sometimes cleaning out legacy interfaces helps
keep the whole system more comprehensible to users, and makes
introspective tools such as apropos
more useful.
SBCL uses a deprecation pipeline with multiple stages: as time goes by, deprecated things move from earlier stages of deprecation to later stages before finally being removed. The intention is making users aware of necessary changes early but allowing a migration to new interfaces at a reasonable pace.
Deprecation proceeds in three stages, each lasting approximately a year. In some cases it might move slower or faster, but one year per stage is what we aim at in general. During each stage warnings (and errors) of increasing severity are signaled, which note that the interface is deprecated, and point users towards any replacements when applicable.
During early deprecation the interface is kept in working condition. However, when a thing in this deprecation stage is used, an early-deprecation-warning [sb-ext], which is a style-warning [cl], is signaled at compile-time.
The internals may change at this stage: typically because the interface is re-implemented on top of its successor. While we try to keep things as backwards-compatible as feasible (taking maintenance costs into account), sometimes semantics change slightly.
For example, when the spinlock API was deprecated, spinlock objects ceased to exist, and the whole spinlock API became a synonym for the mutex API – so code using the spinlock API continued working, but silently switched to mutexes instead. However, if someone relied on
(typep lock 'spinlock)
returning NIL
for a mutexes, trouble could ensue.
During late deprecation the interface remains as it was during early deprecation, but the compile-time warning is upgraded: when a thing in this deprecation stage is used, a late-deprecation-warning [sb-ext], which is a full warning [cl], is signaled at compile-time.
During final deprecation the symbols still exist. However, when a thing in this deprecation stage is used, a final-deprecation-warning [sb-ext], which is a full warning [cl], is signaled at compile-time and an error [cl] is signaled at run-time.
The interface is deleted entirely.
deprecation-condition [sb-ext] is the superclass of all deprecation-related warning and error conditions. All common slots and readers are defined in this condition class.
Class precedence list:
deprecation-condition, condition, t
Superclass for deprecation-related error and warning conditions.
Class precedence list:
early-deprecation-warning, style-warning, warning, deprecation-condition, condition, t
This warning is signaled when the use of a variable, function, type, etc. in
:early
deprecation is detected at compile-time. The use will work at run-time with no warning or error.
Class precedence list:
late-deprecation-warning, warning, deprecation-condition, condition, t
This warning is signaled when the use of a variable, function, type, etc. in
:late
deprecation is detected at compile-time. The use will work at run-time with no warning or error.
Class precedence list:
final-deprecation-warning, warning, deprecation-condition, condition, t
This warning is signaled when the use of a variable, function, type, etc. in
:final
deprecation is detected at compile-time. An error will be signaled at run-time.
Class precedence list:
deprecation-error, error, serious-condition, deprecation-condition, condition, t
This error is signaled at run-time when an attempt is made to use a thing that is in
:final
deprecation, i.e. call a function or access a variable.
The deprecation status of functions and variables can be inspected using
the sb-cltl2:function-information
and
sb-cltl2:variable-information
functions provided by the
sb-cltl2
contributed module.
The sb-ext:deprecated
declaration can be used to declare objects
in various namespaces11 as deprecated.
Syntax:
sb-ext:deprecated
stage since {object-clause}* stage ::= {:early | :late | :final} since ::= {version | (software version)} object-clause ::= (namespace name [:replacement replacement]) namespace ::= {cl:variable | cl:function | cl:type}were name is the name of the deprecated thing, version and software are strings describing the version in which the thing has been deprecated and replacement is a name or a list of names designating things that should be used instead of the deprecated thing.
Currently the following namespaces are supported:
cl:function
- Declare functions, compiler-macros or macros as deprecated.
note: When declaring a function to be in:final
deprecation, there should be no actual definition of the function as the declaration emits a stub function that signals a deprecation-error [sb-ext] at run-time when called.cl:variable
- Declare special and global variables, constants and symbol-macros as deprecated.
note: When declaring a variable to be in:final
deprecation, there should be no actual definition of the variable as the declaration emits a symbol-macro that signals asb-ext:deprecation-error
at run-time when accessed.cl:type
- Declare named types (i.e. defined via
deftype
), standard classes, structure classes and condition classes as deprecated.
Marking functions as deprecated:
(defun foo ()) (defun bar ()) (declaim (deprecated :early ("my-system" "1.2.3") (function foo :replacement bar))) ;; Remember: do not define the actual function or variable in case of ;; :final deprecation: (declaim (deprecated :final ("my-system" "1.2.3") (function fez :replacement whoop)))
Attempting to use the deprecated functions:
(defun baz () (foo)) | STYLE-WARNING: The function CL-USER::FOO has been deprecated... => BAZ (baz) => NIL ; no error (defun danger () (fez)) | WARNING: The function CL-USER::FEZ has been deprecated... => DANGER (danger) |- ERROR: The function CL-USER::FEZ has been deprecated...
This sections lists legacy interfaces in various stages of deprecation.
Deprecated in favor of the corresponding prefix-less functions
(e.g. sockint::bind
replaces sockint::win32-bind
) as of
1.2.10 in March 2015. Expected to move into late deprecation in August
2015.
Deprecated in favor of sb-ext:exit
as of 1.0.56.55 in May 2012.
Expected to move into late deprecation in May 2013.
The design of sb-ext:quit
proved too broken to fix in a
backwards-compatible manner, so it had to be deprecated and replaced.
Problems with it were manifold: when called in the main thread it
cause the entire process to exit. When called in another thread with
:recklessly-p
it also caused the entire process to exit.
However, when called in another thread without :recklessly-p
it
instead caused that thread to terminate abnormally without terminating
the process. Its behaviour versus other threads than the one it was
called in was also underspecified, and dependent on things such as the
current session. Any conceivable change that would have made it sane
would also have silently broken code that depended on the old
behaviour.
Remedy
For code needing to work with legacy SBCLs, if you were calling
quit
with :recklessly-p t
, use
(defun system-exit (&optional (code 0)) (alien-funcall (extern-alien "exit" (function void int)) code))
instead. In modern SBCLs simply call either
sb-posix:exit
or
sb-ext:exit
.
If you were calling it without :recklessly-p
, be advised
that your code may not function as expected when called from threads
other than the main one (see above) – in any case, you can support
legacy SBCLs using the following conditionalization:
(defun lisp-exit (&key (code 0) abort) #+#.(cl:if (cl:find-symbol "EXIT" :sb-ext) '(and) '(or)) ;; Assuming process exit is what is desired -- if thread termination ;; is intended, use SB-THREAD:ABORT-THREAD instead. (sb-ext:exit :code code :abort abort) #-#.(cl:if (cl:find-symbol "EXIT" :sb-ext) '(and) '(or)) (sb-ext:quit :unix-status code :recklessly-p abort))
Deprecated as of 1.0.56.55 in May 2012. Expected to move into late deprecation in May 2013.
When the SBCL process termination was refactored as part of changes that
led to sb-ext:quit
being deprecated, sb-unix:unix-exit
ceased to be used internally. Since SB-UNIX
is an internal package
not intended for user code to use, and since we're slowly in the process
of refactoring things to be less Unix-oriented, sb-unix:unix-exit
was initially deleted as it was no longer used. Unfortunately it became
apparent that it was used by several external users, so it was re-instated
in deprecated form.
While the cost of keeping sb-unix:unix-exit
indefinitely is
trivial, the ability to refactor our internals is important, so its
deprecation was taken as an opportunity to highlight that
SB-UNIX
is an internal package and SB-POSIX
should be
used by user-programs instead – or alternatively calling the foreign
function directly if the desired interface doesn't for some reason
exist in SB-POSIX
.
Remedy
For code needing to work with legacy SBCLs, use e.g. system-exit
as show above in remedies for sb-ext:quit
. In modern SBCLs
simply call either sb-posix:exit
or sb-ext:exit
with
appropriate arguments.
Deprecated as of 1.0.53.74 in November 2011. Expected to move into late deprecation in November 2012.
This compiler policy was never functional: SBCL has always merged tail calls when it could, regardless of this policy setting. (It was also never officially supported, but several code-bases have historically used it.)
Remedy
Simply remove the policy declarations. They were never necessary: SBCL always merged tail-calls when possible. To disable tail merging, structure the code to avoid the tail position instead.
Deprecated as of 1.0.53.11 in August 2011. Expected to move into late deprecation in August 2012.
Spinlocks were an internal interface, but had a number of external users and were hence deprecated instead of being simply deleted.
Affected symbols: sb-thread::spinlock
,
sb-thread::make-spinlock
, sb-thread::with-spinlock
,
sb-thread::with-recursive-spinlock
,
sb-thread::get-spinlock
, sb-thread::release-spinlock
,
sb-thread::spinlock-value
, and sb-thread::spinlock-name
.
Remedy
Use the mutex API instead, or implement spinlocks suiting your needs
on top of sb-ext:compare-and-swap
,
sb-ext:spin-loop-hint
, etc.
Internally deprecated in 2012. Declared deprecated as of 1.2.10 in March 2015. Expected to move into final deprecation in August 2015.
Deprecated in favor of sb-thread:thread-error-thread
as of
1.0.29.17 in June 2009. Expected to move into final deprecation in
June 2012.
Remedy
For code that needs to support legacy SBCLs, use e.g.:
(defun get-thread-error-thread (condition) #+#.(cl:if (cl:find-symbol "THREAD-ERROR-THREAD" :sb-thread) '(and) '(or)) (sb-thread:thread-error-thread condition) #-#.(cl:if (cl:find-symbol "THREAD-ERROR-THREAD" :sb-thread) '(and) '(or)) (etypecase condition (sb-thread:join-thread-error (sb-thread:join-thread-error-thread condition)) (sb-thread:interrupt-thread-error (sb-thread:interrupt-thread-error-thread condition))))
Deprecated in favor of sb-introspect:function-lambda-list
as of
1.0.24.5 in January 2009. Expected to move into final deprecation in
January 2012.
Renamed for consistency and aesthetics. Functions have lambda-lists, not arglists.
Remedy
For code that needs to support legacy SBCLs, use e.g.:
(defun get-function-lambda-list (function) #+#.(cl:if (cl:find-symbol "FUNCTION-LAMBDA-LIST" :sb-introspect) '(and) '(or)) (sb-introspect:function-lambda-list function) #-#.(cl:if (cl:find-symbol "FUNCTION-LAMBDA-LIST" :sb-introspect) '(and) '(or)) (sb-introspect:function-arglist function))
Deprecated in favor of sb-ext:*stack-allocate-dynamic-extent*
as of 1.0.19.7 in August 2008, and are expected to be removed in
August 2012.
Affected symbols: sb-c::stack-allocate-dynamic-extent
,
sb-c::stack-allocate-vector
, and
sb-c::stack-allocate-value-cells
.
These compiler policies were never officially supported, and turned out the be a flawed design.
Remedy
For code that needs stack-allocation in legacy SBCLs, conditionalize using:
#-#.(cl:if (cl:find-symbol "*STACK-ALLOCATE-DYNAMIC-EXTENT*" :sb-ext) '(and) '(or)) (declare (optimize sb-c::stack-allocate-dynamic-extent))
However, unless stack allocation is essential, we recommend simply removing these declarations. Refer to documentation on
sb-ext:*stack-allocate-dynamic*
for details on stack allocation
control in modern SBCLs.
Deprecated as of 1.0.8.16 in June 2007. Expected to move into final deprecation in June 2012.
Internal interface with some external users. Never officially
supported, deemed unnecessary in presence of write-sequence
and
bivalent streams.
Remedy
Use streams with element-type (unsigned-byte 8)
or :default
– the latter allowing both binary and
character IO – in conjunction with write-sequence
.
No interfaces are currently in final deprecation.
The following is a partial list of interfaces present in historical versions of SBCL, which have since then been deleted.
Historically needed for CLOS code. Deprecated as of 0.9.3.32 in August
2005. Deleted as of 1.0.47.8 in April 2011. Plain lambda
can be
used where sb-kernel:instance-lambda
used to be needed.
Inherited from CMUCL, naming convention not consistent with preferred
SBCL style. Deprecated as of 0.pre7.90 in December 2001. Deleted as of
1.0.9.17 in September 2007. Replaced by
sb-alien:define-alien-routine
,
sb-alien:define-alien-variable
, and
sb-alien:define-alien-type
.
dynamic-extent
: Dynamic-extent allocationdynamic-extent
declaration: Dynamic-extent allocationsafety
: Dynamic-extent allocationsafety
optimization quality: Dynamic-extent allocation(setf elt [sb-sequence])
: Extensible Sequences(setf iterator-element [sb-sequence])
: Simple Iterator Protocol(setf logical-pathname-translations [cl])
: Lisp Pathnames(setf slot-value-using-class [sb-mop])
: Metaobject Protocol?
: Information Commandsabort
: Exiting Commandsabort-thread [sb-thread]
: Threading basicsadd-implementation-package [sb-ext]
: Package Lock Dictionaryadd-package-local-nickname [sb-ext]
: Package-Local Nicknamesaddr [sb-alien]
: Coercing Foreign Valuesadjust-sequence [sb-sequence]
: Extensible Sequencesage [sb-unicode]
: Unicode Supportalien-funcall [sb-alien]
: The alien-funcall Primitivealien-sap [sb-alien]
: Coercing Foreign Valuesalphabetic-p [sb-unicode]
: Unicode Supportalways-bound [sb-ext]
: Global and Always-Bound variablesarray-storage-vector [sb-ext]
: Miscellaneous Extensionsassert-version->= [sb-ext]
: Miscellaneous Extensionsatomic-decf [sb-ext]
: Atomic Operationsatomic-incf [sb-ext]
: Atomic Operationsatomic-pop [sb-ext]
: Atomic Operationsatomic-push [sb-ext]
: Atomic Operationsatomic-update [sb-ext]
: Atomic Operationsbacktrace
: Information Commandsbarrier [sb-thread]
: Barriersbidi-class [sb-unicode]
: Unicode Supportbidi-mirroring-glyph [sb-unicode]
: Unicode Supportboth-case-p [cl]
: Unicode Supportbottom
: Stack Motionbytes-consed-between-gcs [sb-ext]
: Garbage Collectioncancel-finalization [sb-ext]
: Garbage Collectioncas [sb-ext]
: Atomic Operationscase-ignorable-p [sb-unicode]
: Unicode Supportcased-p [sb-unicode]
: Unicode Supportcasefold [sb-unicode]
: Unicode Supportcast [sb-alien]
: Coercing Foreign Valueschar-block [sb-unicode]
: Unicode Supportchar-downcase [cl]
: Unicode Supportclass-name [cl]
: Metaobject Protocolclass-of [cl]
: Metaobject Protocolclass-prototype [sb-mop]
: Metaobject Protocolclear-coverage [sb-cover]
: sb-coverclear-semaphore-notification [sb-thread]
: Semaphoresclose [cl]
: Methods common to all streamsclose-gate [sb-concurrency]
: sb-concurrencycoerce [cl]
: Extensible Sequencescombining-class [sb-unicode]
: Unicode Supportcompare-and-swap [sb-ext]
: Atomic Operationscompute-effective-method [sb-mop]
: Metaobject Protocolconcatenate [sb-sequence]
: Extensible Sequencescondition-broadcast [sb-thread]
: Waitqueue/condition variablescondition-notify [sb-thread]
: Waitqueue/condition variablescondition-wait [sb-thread]
: Waitqueue/condition variablesconfusable-p [sb-unicode]
: Unicode Supportcons [cl]
: Dynamic-extent allocationcontinue
: Exiting Commandscopy function
: Iterator Protocolcopy-seq [cl]
: Extensible Sequencesdecimal-value [sb-unicode]
: Unicode Supportdeclare [cl]
: Package Lock Violationsdefault-ignorable-p [sb-unicode]
: Unicode Supportdefcas [sb-ext]
: Atomic Operationsdefclass [cl]
: Metaobject Protocoldefconstant [cl]
: Defining Constantsdefglobal [sb-ext]
: Global and Always-Bound variablesdefine-alien-routine [sb-alien]
: The define-alien-routine Macrodefine-alien-variable [sb-alien]
: External Foreign Variablesdefine-cas-expander [sb-ext]
: Atomic Operationsdefine-hash-table-test [sb-ext]
: Hash Table Extensionsdefmethod [cl]
: Metaobject Protocoldefpackage [cl]
: Package Lock Dictionarydefpackage [cl]
: Implementation Packagesdefpackage [cl]
: Package-Local Nicknamesdefstruct [cl]
: Metaobject Protocoldelete-directory [sb-ext]
: Miscellaneous Extensionsdeprecated [sb-ext]
: Deprecation Declarationdequeue [sb-concurrency]
: sb-concurrencyderef [sb-alien]
: Accessing Foreign Valuesdescribe
: Information Commandsdescribe-compiler-policy [sb-ext]
: Compiler Policydigit-value [sb-unicode]
: Unicode Supportdisable-debugger [sb-ext]
: Enabling and Disabling the Debuggerdisable-package-locks [sb-ext]
: Package Lock Dictionarydisable-package-locks [sb-ext]
: Package Lock Violationsdolist [cl]
: Extensible Sequencesdosequence [sb-sequence]
: Extensible Sequencesdown
: Stack Motiondynamic-space-size [sb-ext]
: Garbage Collectioneast-asian-width [sb-unicode]
: Unicode Supported [cl]
: Customization Hooks for Userselement function
: Iterator Protocolelt [sb-sequence]
: Extensible Sequencesemptyp [sb-sequence]
: Extensible Sequencesenable-debugger [sb-ext]
: Enabling and Disabling the Debuggerenable-package-locks [sb-ext]
: Package Lock Dictionaryenable-package-locks [sb-ext]
: Package Lock Violationsendp function
: Iterator Protocolenqueue [sb-concurrency]
: sb-concurrencyensure-class [sb-mop]
: Metaobject Protocolensure-class-using-class [sb-mop]
: Metaobject Protocolensure-generic-function [cl]
: Metaobject Protocolerror
: Information Commandseval [cl]
: Interpreterexit [sb-ext]
: Exitextern-alien [sb-alien]
: External Foreign Variablesfile-descriptor [sb-posix]
: File-descriptorsfilename [sb-posix]
: Filenamesfinalize [sb-ext]
: Garbage Collectionfinalize-inheritance [sb-mop]
: Metaobject Protocolfind [cl]
: Extensible Sequencesfind-class [cl]
: Metaobject Protocolfind-method [cl]
: Metaobject Protocolflet [cl]
: Package Lock Violationsflet [cl]
: Dynamic-extent allocationframe
: Stack Motionfree-alien [sb-alien]
: Foreign Dynamic Allocationfrlock-name [sb-concurrency]
: sb-concurrencyfrlock-read [sb-concurrency]
: sb-concurrencyfrlock-read-begin [sb-concurrency]
: sb-concurrencyfrlock-read-end [sb-concurrency]
: sb-concurrencyfrlock-write [sb-concurrency]
: sb-concurrencyfuncallable-standard-instance-access [sb-mop]
: Metaobject Protocolgate-name [sb-concurrency]
: sb-concurrencygate-open-p [sb-concurrency]
: sb-concurrencygatep [sb-concurrency]
: sb-concurrencygc [sb-ext]
: Garbage Collectiongc-logfile [sb-ext]
: Garbage Collectiongeneral-category [sb-unicode]
: Unicode Supportgeneration-average-age [sb-ext]
: Garbage Collectiongeneration-bytes-allocated [sb-ext]
: Garbage Collectiongeneration-bytes-consed-between-gcs [sb-ext]
: Garbage Collectiongeneration-minimum-age-before-gc [sb-ext]
: Garbage Collectiongeneration-number-of-gcs [sb-ext]
: Garbage Collectiongeneration-number-of-gcs-before-promotion [sb-ext]
: Garbage Collectiongeneric-function-declarations [sb-mop]
: Metaobject Protocolget-bytes-consed [sb-ext]
: Garbage Collectionget-cas-expansion [sb-ext]
: Atomic Operationsget-errno [sb-alien]
: External Foreign Variablesget-host-by-address [sb-bsd-sockets]
: Name Serviceget-host-by-name [sb-bsd-sockets]
: Name Serviceget-protocol-by-name [sb-bsd-sockets]
: INET Domain Socketsget-time-of-day [sb-ext]
: Miscellaneous Extensionsgetcwd [sb-posix]
: Functions with idiosyncratic bindingsglobal [sb-ext]
: Global and Always-Bound variablesgrab-frlock-write-lock [sb-concurrency]
: sb-concurrencygrab-mutex [sb-thread]
: Mutex Supportgrapheme-break-class [sb-unicode]
: Unicode Supportgraphemes [sb-unicode]
: Unicode Supporthangul-syllable-type [sb-unicode]
: Unicode Supporthash-table-synchronized-p [sb-ext]
: Hash Table Extensionshash-table-weakness [sb-ext]
: Hash Table Extensionshelp
: Information Commandshex-digit-p [sb-unicode]
: Unicode Supporthost-ent-address [sb-bsd-sockets]
: Name Serviceideographic-p [sb-unicode]
: Unicode Supportindex function
: Iterator Protocolinspect [cl]
: Tools To Help Developersint-sap [sb-sys]
: Accessing Foreign Valuesintern [cl]
: Reader Extensionsintern-eql-specializer [sb-mop]
: Metaobject Protocolinterrupt-thread [sb-thread]
: Threading basicsiterator-copy [sb-sequence]
: Simple Iterator Protocoliterator-element [sb-sequence]
: Simple Iterator Protocoliterator-endp [sb-sequence]
: Simple Iterator Protocoliterator-index [sb-sequence]
: Simple Iterator Protocoliterator-step [sb-sequence]
: Simple Iterator Protocoljoin-thread [sb-thread]
: Threading basicslabels [cl]
: Package Lock Violationslabels [cl]
: Dynamic-extent allocationlength [sb-sequence]
: Extensible Sequenceslet [cl]
: Package Lock Violationslet [cl]
: Miscellaneous Efficiency Issueslet* [cl]
: Package Lock Violationslet* [cl]
: Miscellaneous Efficiency Issuesline-break-class [sb-unicode]
: Unicode Supportlines [sb-unicode]
: Unicode Supportlist [cl]
: Dynamic-extent allocationlist* [cl]
: Dynamic-extent allocationlist-all-threads [sb-thread]
: Threading basicslist-all-timers [sb-ext]
: Timerslist-locals
: Variable Accesslist-mailbox-messages [sb-concurrency]
: sb-concurrencylist-queue-contents [sb-concurrency]
: sb-concurrencyload-shared-object [sb-alien]
: Loading Shared Object Fileslock-package [sb-ext]
: Package Lock Dictionarylogand [cl]
: Modular arithmeticlogical-pathname-translations [cl]
: Lisp Pathnameslowercase [sb-unicode]
: Unicode Supportlowercase-p [sb-unicode]
: Unicode Supportmacrolet [cl]
: Package Lock Violationsmailbox-count [sb-concurrency]
: sb-concurrencymailbox-empty-p [sb-concurrency]
: sb-concurrencymailbox-name [sb-concurrency]
: sb-concurrencymailboxp [sb-concurrency]
: sb-concurrencymain-thread [sb-thread]
: Threading basicsmain-thread-p [sb-thread]
: Threading basicsmake-alien [sb-alien]
: Foreign Dynamic Allocationmake-alien-string [sb-alien]
: Foreign Dynamic Allocationmake-array [cl]
: Dynamic-extent allocationmake-frlock [sb-concurrency]
: sb-concurrencymake-gate [sb-concurrency]
: sb-concurrencymake-hash-table [cl]
: Hash Table Extensionsmake-inet-address [sb-bsd-sockets]
: INET Domain Socketsmake-inet6-address [sb-bsd-sockets]
: INET Domain Socketsmake-instance [cl]
: Extensible Sequencesmake-mailbox [sb-concurrency]
: sb-concurrencymake-method-lambda [sb-mop]
: Metaobject Protocolmake-method-specializers-form [sb-pcl]
: Metaobject Protocolmake-mutex [sb-thread]
: Mutex Supportmake-queue [sb-concurrency]
: sb-concurrencymake-semaphore [sb-thread]
: Semaphoresmake-semaphore-notification [sb-thread]
: Semaphoresmake-sequence-iterator [sb-sequence]
: Iterator Protocolmake-sequence-like [sb-sequence]
: Extensible Sequencesmake-simple-sequence-iterator [sb-sequence]
: Simple Iterator Protocolmake-simple-sequence-iterator [sb-sequence]
: Iterator Protocolmake-thread [sb-thread]
: Threading basicsmake-timer [sb-ext]
: Timersmake-waitqueue [sb-thread]
: Waitqueue/condition variablesmake-weak-pointer [sb-ext]
: Garbage Collectionmap [sb-sequence]
: Extensible Sequencesmath-p [sb-unicode]
: Unicode Supportmd5sum-file [sb-md5]
: sb-md5md5sum-sequence [sb-md5]
: sb-md5md5sum-stream [sb-md5]
: sb-md5md5sum-string [sb-md5]
: sb-md5merge [sb-sequence]
: Extensible Sequencesmirrored-p [sb-unicode]
: Unicode Supportmuffle-conditions [sb-ext]
: Controlling Verbositymutex-name [sb-thread]
: Mutex Supportmutex-owner [sb-thread]
: Mutex Supportmutex-value [sb-thread]
: Mutex Supportname-conflict-symbols [sb-ext]
: Resolution of Name Conflictsnative-namestring [sb-ext]
: Native Filenamesnative-pathname [sb-ext]
: Native Filenamesnext
: Single Steppingnon-blocking-mode [sb-bsd-sockets]
: General Socketsnormalize-string [sb-unicode]
: Unicode Supportnormalized-p [sb-unicode]
: Unicode Supportnumeric-value [sb-unicode]
: Unicode Supportopen [cl]
: External Formatsopen-gate [sb-concurrency]
: sb-concurrencyout
: Single Steppingpackage-implemented-by-list [sb-ext]
: Package Lock Dictionarypackage-implements-list [sb-ext]
: Package Lock Dictionarypackage-local-nicknames [sb-ext]
: Package-Local Nicknamespackage-locally-nicknamed-by-list [sb-ext]
: Package-Local Nicknamespackage-locked-error-symbol [sb-ext]
: Package Lock Dictionarypackage-locked-p [sb-ext]
: Package Lock Dictionaryparse-native-namestring [sb-ext]
: Native Filenamesparse-specializer-using-class [sb-pcl]
: Metaobject Protocolposix-getenv [sb-ext]
: Querying the process environmentprint
: Information Commandsprocess-alive-p [sb-ext]
: Running external programsprocess-close [sb-ext]
: Running external programsprocess-core-dumped [sb-ext]
: Running external programsprocess-error [sb-ext]
: Running external programsprocess-exit-code [sb-ext]
: Running external programsprocess-input [sb-ext]
: Running external programsprocess-kill [sb-ext]
: Running external programsprocess-output [sb-ext]
: Running external programsprocess-p [sb-ext]
: Running external programsprocess-status [sb-ext]
: Running external programsprocess-wait [sb-ext]
: Running external programsprofile [sb-profile]
: Deterministic Profilerprofile-call-counts [sb-sprof]
: Statistical Profilerproplist-p [sb-unicode]
: Unicode Supportpurify [sb-ext]
: Efficiency Hacksqueue-count [sb-concurrency]
: sb-concurrencyqueue-empty-p [sb-concurrency]
: sb-concurrencyqueue-name [sb-concurrency]
: sb-concurrencyqueuep [sb-concurrency]
: sb-concurrencyreadlink [sb-posix]
: Functions with idiosyncratic bindingsreadtable-normalization [sb-ext]
: Reader Extensionsreceive-message [sb-concurrency]
: sb-concurrencyreceive-message-no-hang [sb-concurrency]
: sb-concurrencyreceive-pending-messages [sb-concurrency]
: sb-concurrencyrelease-frlock-write-lock [sb-concurrency]
: sb-concurrencyrelease-mutex [sb-thread]
: Mutex Supportremove-implementation-package [sb-ext]
: Package Lock Dictionaryremove-package-local-nickname [sb-ext]
: Package-Local Nicknamesreport [sb-cover]
: sb-coverreport [sb-profile]
: Deterministic Profilerreport [sb-sprof]
: Statistical Profilerrequire [cl]
: Customization Hooks for Usersreset [sb-profile]
: Deterministic Profilerreset [sb-sprof]
: Statistical Profilerreset-coverage [sb-cover]
: sb-coverrestart
: Exiting Commandsrestart-frame
: Exiting Commandsrestore-coverage [sb-cover]
: sb-coverrestore-coverage-from-file [sb-cover]
: sb-coverrestrict-compiler-policy [sb-ext]
: Compiler Policyreturn
: Exiting Commandsreturn-from-thread [sb-thread]
: Threading basicsrotate-byte [sb-rotate-byte]
: sb-rotate-byterotate-byte [sb-rotate-byte]
: sb-md5run-program [sb-ext]
: Running external programssap-alien [sb-alien]
: Coercing Foreign Valuessap-ref-32 [sb-sys]
: Accessing Foreign Valuessap= [sb-sys]
: Accessing Foreign Valuessatisfies [cl]
: Handling of Typessave-coverage [sb-cover]
: sb-coversave-coverage-in-file [sb-cover]
: sb-coversave-lisp-and-die [sb-ext]
: Saving a Core Imageschedule-timer [sb-ext]
: Timersscript [sb-unicode]
: Unicode Supportseed-random-state [sb-ext]
: Random Number Generationsemaphore-count [sb-thread]
: Semaphoressemaphore-name [sb-thread]
: Semaphoressemaphore-notification-status [sb-thread]
: Semaphoressend-message [sb-concurrency]
: sb-concurrencysentence-break-class [sb-unicode]
: Unicode Supportsentences [sb-unicode]
: Unicode Supportset-sbcl-source-location [sb-ext]
: Lisp Pathnamessetf [cl]
: Miscellaneous Efficiency Issuessetf element function
: Iterator Protocolsetq [cl]
: Miscellaneous Efficiency Issuessignal-semaphore [sb-thread]
: Semaphoresslot [sb-alien]
: Accessing Foreign Valuesslot-boundp-using-class [sb-mop]
: Metaobject Protocolslot-definition-name [sb-mop]
: Metaobject Protocolslot-value-using-class [sb-mop]
: Metaobject Protocolsocket-accept [sb-bsd-sockets]
: General Socketssocket-bind [sb-bsd-sockets]
: General Socketssocket-close [sb-bsd-sockets]
: General Socketssocket-connect [sb-bsd-sockets]
: General Socketssocket-error [sb-bsd-sockets]
: General Socketssocket-listen [sb-bsd-sockets]
: General Socketssocket-make-stream [sb-bsd-sockets]
: General Socketssocket-name [sb-bsd-sockets]
: General Socketssocket-open-p [sb-bsd-sockets]
: General Socketssocket-peername [sb-bsd-sockets]
: General Socketssocket-receive [sb-bsd-sockets]
: General Socketssocket-send [sb-bsd-sockets]
: General Socketssocket-shutdown [sb-bsd-sockets]
: General Socketssockopt-broadcast [sb-bsd-sockets]
: Socket Optionssockopt-bsd-compatible [sb-bsd-sockets]
: Socket Optionssockopt-debug [sb-bsd-sockets]
: Socket Optionssockopt-dont-route [sb-bsd-sockets]
: Socket Optionssockopt-keep-alive [sb-bsd-sockets]
: Socket Optionssockopt-oob-inline [sb-bsd-sockets]
: Socket Optionssockopt-pass-credentials [sb-bsd-sockets]
: Socket Optionssockopt-reuse-address [sb-bsd-sockets]
: Socket Optionssockopt-tcp-nodelay [sb-bsd-sockets]
: Socket Optionssoft-dotted-p [sb-unicode]
: Unicode Supportsource
: Source Location Printingstandard-instance-access [sb-mop]
: Metaobject Protocolstart
: Single Steppingstart-profiling [sb-sprof]
: Statistical Profilerstep
: Single Steppingstep [cl]
: Single Steppingstep function
: Iterator Protocolstop
: Single Steppingstop-profiling [sb-sprof]
: Statistical Profilerstream-advance-to-column [sb-gray]
: Character output stream methodsstream-clear-input [sb-gray]
: Input stream methodsstream-clear-output [sb-gray]
: Output stream methodsstream-element-type [cl]
: Methods common to all streamsstream-external-format [cl]
: External Formatsstream-file-position [sb-gray]
: Methods common to all streamsstream-finish-output [sb-gray]
: Output stream methodsstream-force-output [sb-gray]
: Output stream methodsstream-fresh-line [sb-gray]
: Character output stream methodsstream-line-column [sb-gray]
: Character output stream methodsstream-line-length [sb-gray]
: Character output stream methodsstream-listen [sb-gray]
: Character input stream methodsstream-peek-char [sb-gray]
: Character input stream methodsstream-read-byte [sb-gray]
: Binary stream methodsstream-read-char [sb-gray]
: Character input stream methodsstream-read-char-no-hang [sb-gray]
: Character input stream methodsstream-read-line [sb-gray]
: Character input stream methodsstream-read-sequence [sb-gray]
: Input stream methodsstream-start-line-p [sb-gray]
: Character output stream methodsstream-terpri [sb-gray]
: Character output stream methodsstream-unread-char [sb-gray]
: Character input stream methodsstream-write-byte [sb-gray]
: Binary stream methodsstream-write-char [sb-gray]
: Character output stream methodsstream-write-sequence [sb-gray]
: Output stream methodsstream-write-string [sb-gray]
: Character output stream methodsstring-upcase [cl]
: Unicode Supportsubseq [cl]
: Extensible Sequencessubtypep [cl]
: Metaobject Protocolsymbol-macrolet [cl]
: Package Lock Violationssymbol-value-in-thread [sb-thread]
: Threading basicssyslog [sb-posix]
: Functions with idiosyncratic bindingsterminate-thread [sb-thread]
: Threading basicsthread-alive-p [sb-thread]
: Threading basicsthread-error-thread [sb-thread]
: Threading basicsthread-name [sb-thread]
: Threading basicsthread-yield [sb-thread]
: Threading basicstimer-name [sb-ext]
: Timerstimer-scheduled-p [sb-ext]
: Timerstitlecase [sb-unicode]
: Unicode Supporttop
: Stack Motiontoplevel
: Exiting Commandstrace [cl]
: Tools To Help Developerstrace [cl]
: Function Tracingtruly-the [sb-ext]
: Efficiency Hackstry-semaphore [sb-thread]
: Semaphorestypep [cl]
: Metaobject Protocolunicode-1-name [sb-unicode]
: Unicode Supportunicode-equal [sb-unicode]
: Unicode Supportunicode< [sb-unicode]
: Unicode Supportunicode<= [sb-unicode]
: Unicode Supportunicode= [sb-unicode]
: Unicode Supportunicode> [sb-unicode]
: Unicode Supportunicode>= [sb-unicode]
: Unicode Supportunload-shared-object [sb-alien]
: Loading Shared Object Filesunlock-package [sb-ext]
: Package Lock Dictionaryunmuffle-conditions [sb-ext]
: Controlling Verbosityunparse-specializer-using-class [sb-pcl]
: Metaobject Protocolunprofile [sb-profile]
: Deterministic Profilerunprofile-call-counts [sb-sprof]
: Statistical Profilerunschedule-timer [sb-ext]
: Timersuntrace [cl]
: Function Tracingup
: Stack Motionuppercase [sb-unicode]
: Unicode Supportuppercase-p [sb-unicode]
: Unicode Supportvalidate-superclass [sb-mop]
: Metaobject Protocolvar [sb-debug]
: Variable Accessvector [cl]
: Dynamic-extent allocationwait-for [sb-ext]
: Miscellaneous Extensionswait-on-gate [sb-concurrency]
: sb-concurrencywait-on-semaphore [sb-thread]
: Semaphoreswaitqueue-name [sb-thread]
: Waitqueue/condition variablesweak-pointer-value [sb-ext]
: Garbage Collectionwhitespace-p [sb-unicode]
: Unicode Supportwith-alien [sb-alien]
: Local Foreign Variableswith-compilation-unit [cl]
: Compiler Policywith-compilation-unit [cl]
: The Parts of a Compiler Diagnosticwith-locked-hash-table [sb-ext]
: Hash Table Extensionswith-mutex [sb-thread]
: Mutex Supportwith-open-file [cl]
: External Formatswith-profiling [sb-sprof]
: Statistical Profilerwith-recursive-lock [sb-thread]
: Mutex Supportwith-sampling [sb-sprof]
: Statistical Profilerwith-sequence-iterator [sb-sequence]
: Iterator Protocolwith-sequence-iterator-functions [sb-sequence]
: Iterator Protocolwith-unlocked-packages [sb-ext]
: Package Lock Dictionarywithout-package-locks [sb-ext]
: Package Lock Dictionaryword-break-class [sb-unicode]
: Unicode Supportwords [sb-unicode]
: Unicode Support*after-gc-hooks* [sb-ext]
: Garbage Collection*compiler-print-variable-alist* [sb-ext]
: Controlling Verbosity*core-pathname* [sb-ext]
: Saving a Core Image*current-thread* [sb-thread]
: Threading basics*debug-print-variable-alist* [sb-ext]
: Debugger Command Loop*ed-functions* [sb-ext]
: Customization Hooks for Users*evaluator-mode* [sb-ext]
: Interpreter*exit-hooks* [sb-ext]
: Initialization and Exit Hooks*gc-run-time* [sb-ext]
: Garbage Collection*init-hooks* [sb-ext]
: Initialization and Exit Hooks*invoke-debugger-hook* [sb-ext]
: Debugger Invocation*max-samples* [sb-sprof]
: Statistical Profiler*max-trace-indentation* [sb-debug]
: Function Tracing*module-provider-functions* [sb-ext]
: Customization Hooks for Users*muffled-warnings* [sb-ext]
: Customization Hooks for Users*on-package-variance* [sb-ext]
: Package Variance*package* [cl]
: Implementation Packages*posix-argv* [sb-ext]
: Command-line arguments*posix-argv* [sb-ext]
: Shebang Scripts*sample-interval* [sb-sprof]
: Statistical Profiler*save-hooks* [sb-ext]
: Saving a Core Image*stack-allocate-dynamic-extent* [sb-ext]
: Dynamic-extent allocation*sysinit-pathname-function* [sb-ext]
: Saving a Core Image*trace-encapsulate-default* [sb-debug]
: Function Tracing*trace-indentation-step* [sb-debug]
: Function Tracing*userinit-pathname-function* [sb-ext]
: Saving a Core Image+slot-unbound+ [sb-pcl]
: Metaobject Protocolbuilt-in-class [cl]
: Metaobject Protocolcode-deletion-note [sb-ext]
: Diagnostic Severitycompiler-note [sb-ext]
: Diagnostic Severitydeprecation-condition [sb-ext]
: Deprecation Conditionsdeprecation-error [sb-ext]
: Deprecation Conditionsearly-deprecation-warning [sb-ext]
: Deprecation Conditionserror [cl]
: Diagnostic Severityfile-descriptor [sb-posix]
: File-descriptorsfile-descriptor-designator [sb-posix]
: File-descriptorsfilename [sb-posix]
: Filenamesfilename-designator [sb-posix]
: Filenamesfinal-deprecation-warning [sb-ext]
: Deprecation Conditionsflock [sb-posix]
: Lisp objects and C structuresfrlock [sb-concurrency]
: sb-concurrencyfuncallable-standard-class [sb-mop]
: Metaobject Protocolfuncallable-standard-object [sb-mop]
: Metaobject Protocolfunction [cl]
: Metaobject Protocolfundamental-binary-input-stream [sb-gray]
: Gray Streams classesfundamental-binary-output-stream [sb-gray]
: Gray Streams classesfundamental-binary-stream [sb-gray]
: Gray Streams classesfundamental-character-input-stream [sb-gray]
: Gray Streams classesfundamental-character-output-stream [sb-gray]
: Gray Streams classesfundamental-character-stream [sb-gray]
: Gray Streams classesfundamental-input-stream [sb-gray]
: Gray Streams classesfundamental-output-stream [sb-gray]
: Gray Streams classesfundamental-stream [sb-gray]
: Gray Streams classesgate [sb-concurrency]
: sb-concurrencygeneric-function [cl]
: Metaobject Protocolhost-ent [sb-bsd-sockets]
: Name Serviceinet-socket [sb-bsd-sockets]
: INET Domain Socketsinet6-socket [sb-bsd-sockets]
: INET Domain Socketsinterrupt-thread-error [sb-thread]
: Threading basicsjoin-thread-error [sb-thread]
: Threading basicslate-deprecation-warning [sb-ext]
: Deprecation Conditionslist [cl]
: Extensible Sequenceslocal-socket [sb-bsd-sockets]
: Local (Unix) Domain Socketsmailbox [sb-concurrency]
: sb-concurrencymutex [sb-thread]
: Mutex Supportname-conflict [sb-ext]
: Resolution of Name Conflictspackage-error [cl]
: Package Lock Violationspackage-lock-violation [sb-ext]
: Package Lock Dictionarypackage-lock-violation [sb-ext]
: Package Lock Violationspackage-locked-error [sb-ext]
: Package Lock Dictionarypackage-locked-error [sb-ext]
: Package Lock Violationspasswd [sb-posix]
: Lisp objects and C structuresprotocol-unimplemented [sb-sequence]
: Extensible Sequencesqueue [sb-concurrency]
: sb-concurrencysemaphore [sb-thread]
: Semaphoressemaphore-notification [sb-thread]
: Semaphoressequence [cl]
: Iterator Protocolsequence [cl]
: Extensible Sequencessocket [sb-bsd-sockets]
: General Socketsstandard-class [cl]
: Metaobject Protocolstandard-generic-function [cl]
: Metaobject Protocolstandard-object [cl]
: Extensible Sequencesstandard-object [cl]
: Metaobject Protocolstat [sb-posix]
: Lisp objects and C structuresstructure-class [cl]
: Metaobject Protocolstyle-warning [cl]
: Diagnostic Severitysymbol-package-locked-error [sb-ext]
: Package Lock Dictionarysymbol-package-locked-error [sb-ext]
: Package Lock Violationst [cl]
: Metaobject Protocoltermios [sb-posix]
: Lisp objects and C structuresthread [sb-thread]
: Threading basicsthread-error [sb-thread]
: Threading basicstimer [sb-ext]
: Timerstimeval [sb-posix]
: Lisp objects and C structuresvector [cl]
: Extensible Sequenceswaitqueue [sb-thread]
: Waitqueue/condition variableswarning [cl]
: Diagnostic SeverityThis manual is maintained in Texinfo, and automatically translated into other forms (e.g. HTML or pdf). If you're reading this manual in one of these non-Texinfo translated forms, that's fine, but if you want to modify this manual, you are strongly advised to seek out a Texinfo version and modify that instead of modifying a translated version. Even better might be to seek out the Texinfo version (maintained at the time of this writing as part of the SBCL project at http://sbcl.sourceforge.net/) and submit a patch.
[1] Historically, the ILISP package at http://ilisp.cons.org/ provided similar functionality, but it does not support modern SBCL versions.
[2] Actually, this declaration is unnecessary in
SBCL, since it already knows that position
returns a
non-negative fixnum
or nil
.
[3] A deprecated
extension sb-ext:inhibit-warnings
is still supported, but
liable to go away at any time.
[4] Since the location of an interrupt or hardware error will always be an unknown location, non-argument variable values will never be available in the interrupted frame. See Unknown Locations and Interrupts.
[5] The variable bindings are actually created
using the Lisp symbol-macrolet
special form.
[6] A motivation, rationale and additional examples for the design of this extension can be found in the paper Rhodes, Christophe (2007): User-extensible sequences in Common Lisp available for download at http://www.doc.gold.ac.uk/~mas01cr/papers/ilc2007/sequences-20070301.pdf.
[7] In SBCL versions prior to 1.0.13, sb-ext:run-program
searched for executables in a manner somewhat incompatible with other
languages. As of this version, SBCL uses the system library routine
execvp(3)
, and no longer contains the function,
find-executable-in-search-path
, which implemented the old
search. Users who need this function may find it
in run-program.lisp versions 1.67 and earlier in SBCL's CVS
repository here
http://sbcl.cvs.sourceforge.net/sbcl/sbcl/src/code/run-program.lisp?view=log. However,
we caution such users that this search routine finds executables that
system library routines do not.
[8] Please
note that the codepoint U+1F5CF (PAGE) introduced in Unicode 7.0 is
named UNICODE_PAGE
, since the name “Page” is required to be
assigned to form-feed (U+0C) by the ANSI standard.
[9] See chapter 7 "Testing widely used RNGs" in TestU01: A C Library for Empirical Testing of Random Number Generators by Pierre L'Ecuyer and Richard Simard, ACM Transactions on Mathematical Software, Vol. 33, article 22, 2007.
[10] The functionality contained in the package
SB-UNIX
is for SBCL internal use only; its contents are likely to
change from version to version.
[11] See “namespace” entry in the glossary of the Common Lisp Hyperspec.